Buffered
Máquina Buffered de la plataforma DockerLabs
Autor: rxffsec
Dificultad: Dificil

Reconocimiento
Comenzamos con un escaneo de nmap el cual nos permita saber los puertos abiertos de la máquina:
como podemos ver solo hay un puerto abierto, además también podemos ver un dominio el cual agregaremos al archivo /etc/hosts para que nuestra computadora sepa a donde tiene que apuntar con ese dominio:
Puerto 80
Al entrar a la página web del puerto 80 no vemos nada muy interesante pero si una posible lista de usuarios:
Pasaremos directamente a usar gobuster para enumerar subdominios ya que el dominio principal no tiene nada mas que eso:
teniendo ese subdominio, lo agregamos en el archivo /etc/hosts de la siguiente manera:
Si revisamos el subdominio, podremos ver que podemos registrarnos, por lo que nos registramos e iniciamos sesión. Al iniciar sesión no hay nada interesante, por lo que podemos intentar ver que pasa por detrás con BurpSuite. Iniciamos sesión y dejamos pasar la primer petición, y al llegar a la siguiente:

cambiamos el mail con el que nos registramos por admin@buffered.dl, esto hará que nos iniciemos como admin ya que la petición se hace por GET en vez de POST. Una vez estamos como admin, podremos ver un buscador, y si probamos distintos payloads podemos ver que es vulnerable a SSTI, ya que al poner {{7*7}} nos dice "49":

con esto ya podemos ejecutar comandos y entrar en la máquina.
Intrusión
Para ejecutar comandos, simplemente nos fijamos en PayloadsAllTheThings y vemos que podemos ejecutar comandos con lo siguiente:

ahora simplemente nos ponemos en escucha con netcat por el puerto 443 y enviamos una consola interactiva:
Escalada de Privilegios
Wilson
Una vez estamos como wilson, la variable PATH está mal puesta, ya que si nos fijamos veremos que es la siguiente:
viendo esto pondremos la variable PATH de nuestro host:
y ahora si podremos hacer el tratamiento de la tty.
Estando dentro, revisamos los puertos abiertos de la máquina con ss -tulunp y podremos ver que el puerto 5555 está abierto. Además, podemos saber que es una web ya que si ejecutamos curl desde la máquina a 127.0.0.1:5555 veremos código html.
Port Forwarding
Como estamos dentro de la maquina, utilizaremos chisel para que el puerto 5555 de la máquina sea el 5555 de nuestro host:
una vez hecho podremos acceder al puerto 5555 de la máquina victima poniendo "127.0.0.1:5555" en el navegador.
Puerto 5555
Al entrar en la página, podemos ver como hay un "niceadmin":

el problema es que no contamos con credenciales válidas. Luego de revisar un rato, encuentro un script de python en ~/dashboard/.pwgen.py, el cual si lo revisamos veremos lo siguiente:
al parecer el código genera contraseñas como estas:
Sabiendo esto podriamos intentar generar la contraseña de el usuario christine o tyler pero no podriamos saber los números que irian al final ya que es totalmente aleatorio, por lo que podriamos probar en buscar las credenciales de la base de datos mysql que está corriendo para ver si asi encontramos el hash de algún usuario. Para esto filtro por "mysql" en el archivo app.py que se encuentra en ~/dashboard:
ya tenemos credenciales para la base de datos, por lo que nos conectaremos de la siguiente manera:
Una vez dentro, listamos las bases de datos con show databases; y solo vemos una llamada "myflaskapp". Ahora seleccionamos la base de datos con use myflaskapp; y listamos las tablas con show tables;. De la base de datos que encontramos, la única tabla que nos interesa es la siguiente:
perfecto, ahora que tenemos un hash, debemos elegir que usuario generar contraseñas para intentar romperla, y luego de revisar los procesos decido que el usuario christine es la mejor opcion ya que es el único que está ejecutando algo en segundo plano (posiblemente la web):
Ahora como sabemos que las contraseñas siempre empiezan igual, en el caso de christine seria "c.ross@buffered_xxxxxx" (ross porque como vimos antes en la página principal, christine tenia el apellido ross), y solo generaremos los números usando crunch:
luego metemos el hash en un archivo y lo crackeamos con john:
y ya tenemos credenciales:
NiceAdmin
Una vez logeados, podremos ver que hay un botón llamado "download report", el cual si lo presionamos nos descarga un archivo llamado "logins.txt". Si revisamos el código con las devtools del navegador, podremos ver que selecciona el archivo como "logins.txt" y podemos probar en cambiarlo por otro archivo, como por ejemplo /etc/passwd:

una vez descargado el archivo, lo leemos y podremos ver que efectivamente descargamos el archivo passwd, lo que significa que podriamos descargar cualquier archivo al cual no tengamos acceso como wilson pero si como christine (ya que christine es el usuario que ejecuta la web). En este caso, el único archivo que nos es de utilidad es /home/christine/.site/APP_3411/app.py, ya que como vimos en los procesos ese es la misma página que se encuentra en el puerto 5555. Una vez descargado, podremos visualizar el código de python de la página, pero no hay nada muy llamativo mas que al final, ya que vemos que usa pickle (el cual tambien importa al principio del archivo) para deserializar datos en base64 pasados con el parametro "mydata". Luego de buscar en HackTricks, encuentro el siguiente código que aprovecha la deserializacion de pickle:
solo que haremos unas modificaciones para que funcione bien:
Luego de ejecutarlo, nos dará el siguiente string en base64:
escuchamos por el puerto 443 con netcat:
y enviamos los datos para recibir una shell:
una vez lo enviemos, habremos escalado al usuario christine.
Christine
Si ejecutamos id veremos que estamos en el grupo ftp, por lo que procederemos a buscar archivos pertenecientes a ese grupo:
solo vemos un directorio.
Al entrar en /ftp podremos ver un binario llamado "bufferbot", pero no podemos ejecutarlo, ya que intenta abrir un puerto pero parece que ya está en uso, por lo que lo pasaremos a nuestra máquina para analizarlo.
Una vez tenemos el binario, lo ejecutamos y veremos un mensaje de que está esperando conexiones por el puerto 9000, por lo que nos conectaremos con netcat para ver que hay en el:
al parecer no tiene nada interesante, pero podemos intentar enviar muchos datos para ver que pasa:
resultado:
perfecto, estamos frente a un buffer overflow.
Buffer Overflow 1
Si ejecutamos file sobre el binario, veremos que es un ejecutable de 32 bits y además con checksec podemos saber que no tiene protecciones, por lo que el stack es ejecutable y podemos tener en cuenta eso. Con gdb listamos las funciones y vemos una llamada "jmp_esp":
El binario es de 32 bits y no tiene protecciones, lo que significa que la pila es ejecutable. Esto nos permite inyectar y ejecutar código arbitrario. Nuestro objetivo es tomar el control del registro EIP, ya que este determina la próxima instrucción a ejecutar. Para esto, aprovechamos un buffer overflow, sobrescribiendo EIP con la dirección de un gadget jmp esp.
¿Por qué jmp esp? Porque este gadget redirige la ejecución al registro ESP, y como todo lo que coloquemos después de sobreescribir EIP se almacenará en la pila, esto nos permite colocar ahí un shellcode y ejecutarlo cuando jmp esp transfiera el control a ESP.
Para hacer esto debemos crear un exploit en python, y utilizaremos la libreria "socket", ya que la máquina no tiene pip ni "pwntools". Primero haremos la base del exploit:
Tenemos varias cosas definidas y además lo que necesitamos saber, ya que necesitamos unos datos antes de hacer el exploit, como el offset (la cantidad de basura que tenemos que poner antes de llegar al EIP), la dirección del gadget jmp_esp, y un shellcode (el cual generaremos con msfvenom).
Obtener el offset
Para obtener el offset, utilizaremos la herramienta pattern_create.rb y pattern_offset.rb de metasploit. La primera nos genera una cadena, la cual al enviarla y ver los resultados podremos pasarla a pattern_offset.rb y nos dirá el offset del binario:
Primero ejecutamos gdb y le pasamos el binario:
luego ejecutamos pattern_create.rb de la siguiente manera:
una vez lo enviemos, podremos ver en gdb que el programa ha crasheado, y en el registro EIP se encuentra lo siguiente:
con "5Bs6" lo pasamos a pattern_offset.rb y nos dirá el offset:
perfecto, ya podemos actualizar el exploit:
Para obtener la dirección de el gadget jmp esp simplemente utilizaremos la herramienta ropper:
y ya tenemos la dirección, por lo cual podemos actualizar el exploit:
finalmente, generamos un shellcode con msfvenom y actualizamos el exploit:
Exploit final:
Perfecto, ahora solo nos queda escuchar en el puerto 7070 con netcat y ejecutar el exploit en la máquina víctima. Una vez ejecutado seremos el usuario tyler.
Tyler
Buffer Overflow 2
Siendo el usuario Tyler, podemos ver un binario con el bit suid activado en la home de este. Al ejecutarlo, parece ser una shell (además de que se llama shell) pero no parece hacer mucho, ya que si ejecutamos id no nos dice realmente si somos root, nuevamente si ponemos muchos datos, podremos ver que es vulnerable a buffer overflow.
Pasamos el binario a nuestra máquina, y nos ponemos como root, ya que el binario necesita ejecutar "setuid(0)" y no puede si lo ejecutamos como un usuario normal. Primeramente podemos ver varias cosas:
• Con checksec vemos que el binario tiene NX como protección, lo que significa que la pila no es ejecutable y no podemos hacer una explotación como la anterior, y solo nos quedan 3 chances:
1: Apuntar a una función interesante que pueda por ejemplo ejecutarnos una shell
2: Buffer overflow de tipo ret2libc
3: Buffer Overflow de tipo ROP(Return-Oriented Programming)
En este caso haremos un ROP, ya que es lo mas fácil para este binario.
Base del exploit:
Esta vez, en lugar de conectarnos a un servicio remoto, ejecutaremos el binario localmente y lo explotaremos directamente. En un principio lo único que conocemos es "tmp_shell", ya que es lo que vamos a ejecutar al explotar el binario (también podriamos ejecutar /bin/sh pero yo ejecutaré un script). Además definimos una función p64() la cual se encargará en convertir direcciones en una representación binaria de 64 bits en little-endian, para que sean interpretadas correctamente por la arquitectura.
¿Por que necesitamos estos datos?
En este tipo de buffer overflow, aprovechamos algunas instrucciones que se encuentran en el binario, que en este caso están en la función _x2:

como podemos ver en la imagen, hay una instrucción que mueve el contenido de RSP a el registro RDI, esto lo necesitamos porque lo que queremos hacer es ejecutar system() de la siguiente manera:
la función system busca un argumento en los siguientes registros y con ese orden: rdi, rsi, rdx, rcx, r8, r9.
Y como vemos en la instrucción, esta moviendo el contenido del registro RSP (del cual tenemos el control ya que seria como el ESP pero en 64 bits) a el registro RDI, por lo que ahi podriamos meter nuestra cadena de /tmp/sh para que ejecute ese script. Además, hace un salto a el registro R13, y da la casualidad de que el binario también tiene un gadget POP r13, el cual toma el valor que se encuentra en el tope de la pila, que será system() y lo meterá en el registro R13, por lo que ahí habremos preparado la función y cuando la llamemos, moverá lo que se encuentra en RSP (que será nuestra cadena de /tmp/sh) al registro RDI, y luego saltará a R13, en donde estará system (el cual buscará el primer argumento en RDI) y ejecutará nuestro script, ya que en RDI estará nuestra cadena.
Una vez explicado todo eso, pasaremos a encontrar las direcciónes necesarias, lo cual es bastante sencillo realmente.
Calcular el offset
Para calcular el offset, debemos hacer exactamente lo mismo que la vez pasada, por lo que no voy a explicarlo. Esta vez es de 136, pero debemos restarle la cadena /tmp/sh para que esa sea la que se encuentre en RSP al momento de la explotación, osea que en total seria 128.
Obtener las direcciones de _x2, system y pop_r13
Para obtener las direcciones de _x2 y system se puede hacer con un mismo comando:
en este caso, las direcciónes serian las siguientes:
_x2 = 0x4014a3
system = 0x401040
Para encontrar la dirección de pop r13, simplemente volvemos a utilizar ropper:
como vemos, la dirección de el gadget seria 0x40149d, por lo que ya tendriamos el exploit completo:
Lo último que nos quedaría antes de ejecutar el exploit, es crear un script en /tmp/ llamado sh que ejecute lo que queramos que nos permita escalar a root, en mi caso quitará la "x" del archivo /etc/passwd para que al ejecutar su pueda escalar sin necesidad de poner contraseña:
y listo, ejecutamos el exploit y al hacerlo solo nos queda ejecutar su y seremos root.
Root

Gracias por leer ;)
Última actualización