En este post vamos a estar resolviendo el laboratorio de PortSwigger: “Web shell upload via extension blacklist bypass”.

Para resolver el laboratorio tenemos que subir un archivo PHP que lea y nos muestre el contenido del archivo /home/carlos/secret. Ya que para demostrar que hemos completado el laboratorio, deberemos introducir el contenido de este archivo.
Además, el servidor está configurado para que no acepte ciertas extensiones.
En este caso, el propio laboratorio nos proporciona una cuenta para iniciar sesión, por lo que vamos a hacerlo:


Una vez hemos iniciado sesión, nos encontramos con el perfil de la cuenta:

Como podemos ver, tenemos una opción para subir archivo, y concretamente parece ser que se trata de actualizar el avatar del perfil. Vamos a intentar aprovecharnos de esta opción para subir el siguiente archivo PHP:

Antes que nada, vamos a preparar Burp Suite para que intercepte la petición:


Una vez tenemos Burp Suite listo junto al proxy, seleccionamos el archivo y le damos a “Upload”:



Aquí Burp Suite interceptará la petición de subida del archivo:

Para tratar mejor con la petición y poder analizar de mejor manera la respuesta del servidor, vamos a pasar la petición al repeater con Ctrl R.
Una vez pasado, le damos a “Send” para ver la respuesta del servidor a la petición por defecto:

Nos dice que los archivos PHP no están permitidos. Por lo que la idea va a ser probar alternativas a la extensión de PHP para ver si no están definidas en la blacklist. En wikipedia podemos ver los tipos de extensiones asociadas a PHP:

Dicho esto, pasamos la petición del repeater al intruder pulsando Ctrl I. Una vez tengamos la petición en el intruder, le daremos al botón de clear para quitar los lugares de sustitución que se ponen por defecto:

Como lo que nos interesa es lanzar varias peticiones y que la diferencia entre cada una solo sea la extensión, declararemos un campo de sustitución en la extensión del nombre del archivo:

Con esto hecho, nos dirigiremos a la pestaña de “Payloads”:

Una vez aquí, definiremos nuestro diccionario, es decir, el diccionario que se usará para sustituir la extensión por defecto, por las definidas en el diccionario:


Una vez tengamos el diccionario de extensiones a probar hecho, nos dirigiremos a la pestaña de “Options” y a la parte de “Grep – Extract”:

Una vez aquí, estableceremos el string por el que queremos que filtre en las distintas respuestas, para que cuando no posea el string indicado, podamos detectar la respuesta en la que no lo esté rápidamente:

Una vez hecho, nos dirigiremos de nuevo a la pestaña de “Payloads” para empezar el ataque:


Se nos abrirá una nueva ventana referente al ataque:

En este caso, como podemos ver, parece que la única extensión que el servidor no permite, es la PHP. Por lo que presuntamente se han subido todas las demás. Vamos a ver la respuesta a la última petición en el navegador, para ello hacemos lo siguiente:




Una vez tengamos la respuesta, podemos desactivar el burp suite porque no haremos mas uso de él:

Con esto hecho, volvemos a nuestro perfil:

Ahora, si nos fijamos en el perfil, podemos ver como el avatar ha cambiado, y ahora muestra un fallo de que no carga bien la imagen:

Dándole click derecho, podemos irnos a la ruta directa de la imagen para ver si se trata de nuestro archivo PHP:


Ojo, el archivo parece que existe porque no nos da error 404, sin embargo, no se interpreta del todo ya que no ha leido el archivos que le hemos indicado que lea. No pasa nada, antes de entrar en panico vamos a probar con los demas archivos con otra extensión que hemos subido, por ejemplo, el phtml:

Este si nos lo interpreta, y de esta forma conseguimos leer el archivo secret.
Habiéndolo leído, ya simplemente entregamos la solución:


Y de esta forma, completamos el laboratorio:


Aunque lo hayamos solucionado de esta forma, la solución de PortSwigger me parece super chula e importante de comentar:
- Nos logueamos y subimos una imagen de nuestro avatar, con esto hecho, volvemos a la página de nuestro perfil.
- En el burp suite, nos dirigimos a Proxy > HTTP History. Aquí podremos ver una petición GET a la ruta
/files/avatars/<archivo>
. Enviamos esta respuesta al repeater. - En nuestro sistema, creamos un archivo que se llame exploit.php que contenta un código que lea el contenido del archivo secret del usuario Carlos. Por ejemplo:
<?php echo file_get_contents('/home/carlos/secret'); ?>
- Intentamos subir este archivo como nuestro avatar. La respuesta del servidor nos indicará que no se permiten archivos de extensión PHP.
- En el HTTP History ahora buscaremos la petición POST en la que hemos intentado subir el archivo php. En la respuesta del servidor a esta petición, nos podremos dar cuenta de que estamos tratando con un servidor apache. Dicho esto, enviamos esta petición al repeater.
- En la petición POST que ahora tenemos en el repeater, vamos a hacer los siguientes cambios:
- Cambiamos el nombre del archivo a
.htaccess
. - Cambiamos el valor de Content-Type a
text/plain
- Reemplazamos el contenido del archivo (el código PHP) por la siguiente directiva de apache:
AddType application/x-httpd-php .l33t
Esta directiva añadirá una nueva extensión al servidor, además, indicando que el tipo de MIME esapplication/x-httpd-php
, lo que quiere decir que se comportará como un archivo PHP. Como el servidor hace uso demod_php
(módulo de PHP para apache), sabrá y entenderá lo que le estamos diciendo.
- Cambiamos el nombre del archivo a
- Enviamos la petición, y veremos que el servidor nos indicará en la respuesta que el archivo se ha subido correctamente.
- Ahora volvemos a la petición original del archivo PHP, y lo único que cambiaremos será el nombre. Cambiaremos exploit.php por por ejemplo, exploit.l33t. Con esto, enviamos la petición y veremos que se ha subido correctamente.
- Ahora, volviendo a la petición GET del
/files/avatars/<archivo>
donde archivo será exploit.l33t, al hacerla, en la respuesta se nos devolverá el secret de Carlos. - Mandamos la solución y laboratorio completado.