Behemoth - [OverTheWire]
![Cover Image for Behemoth - [OverTheWire]](/assets/images/blog/behemoth-overthewire/Behemoth.jpg)

Introducción
Behemoth son una serie de retos que tienen que ver con la explotación y el reversing de binarios, una vez solucionas un reto puedes acceder al fichero donde se encuentran la contraseña para acceder al siguiente reto.
Para acceder a los retos tienes que emplear SSH.
Una vez dentro de la máquinas encontrarás todos los retos en /behemoth/.
Todas las contraseñas para pasar al siguiente nivel están en la carpeta /etc/behemoth_pass/ y solo se pueden leer por el usuario del siguiente nivel.
Nota: Si es tu primera vez en el mundo de la explotación binaria, te recomiendo que empieces leyendo mis posts de Protostar, Leviathan y Narnia antes que comenzar por este nivel, pues se darán por hecho algunos conocimientos.
Behemoth 0
Al ejecutar el programa vemos que comprueba si la contraseña que introducimos es correcta.
Para averiguar la contraseña se puede emplear ltrace (Programa que muestra las llamadas al sistema).
Como podemos comprobar, el programa realiza la llamada strcmp que compara dos cadenas de caracteres; la primera de ellas es lo que he introducido "MIPASSWORD" y la segunda "eatmyshorts". Si lo introducimos, vemos como nos crea una shell como el usuario behemoth1, permitiéndonos obtener la contraseña para el siguiente usuario.
Behemoth 1
El funcionamiento del binario de behemoth1 es igual que el nivel anterior.
Sin embargo, ltrace no nos muestra la función strcpm.
Para analizarlo mejor, me lo he descargado empleado SCP:
Utilizando Ghidra genera el siguiente código decompilado.
Como podemos ver, el programa almacena los valores que nosotros le introduzcamos en un char array de 67 caracteres y finaliza directamente.
El empleo de gets es peligroso debido a que su uso puede resultar en Buffer Overflows. Como demostración, al introducir una cantidad exagerada de caracteres se produce una Segmentation Fault.
Usando el comando dmesg podemos ver que ha pasado.
La dirección que había en el Instruction Pointer Register o (RIP) ha sido sobrescrita por el valor 0x41 o 'A's en ASCII. Esto implica que podemos saltar a cualquier posición de la memoria. Pero antes, necesitamos saber cuantos caracteres son necesarios para sobrescribir el RIP con la dirección que queramos.
Mediante prueba y error, se obtiene que escribiendo 71 'A's, podemos escribir la dirección de memoria que queramos.
Una vez sabemos el OFFEST se pueden emplear diferentes técnicas de explotación binaria. Entre ellas, he utilizado la técnico de ROP con el uso de SHELLCODES (Instrucciones máquinas que al ejecutarse ejecutan una terminal).
Primero de todo, necesitamos saber donde se encuentra en el binario la instrucción jmp esp. Para ello, empleamos la herramienta GDB.
Ejecutamos la herramienta, pasando como parámetro la ruta del programa a analizar. Después añadimos un breakpoint para que el programa se detenga cuando se ejecute.
Una vez parado el programa, podemos usar el comando info proc map para mostrar todas las direcciones de memoria de las que se componen el programa y entre ellas los rangos de direcciones de las librerías del binario. Gracias a este rango de direcciones, podemos encontrar las apariencias de la instrucción jmp esp que en hexadecimal es \xFF\xE4.
De todas las ocurrencias que aparecen en el texto anterior se ha elegido la primera, debido a que al acceder a dicha dirección nos encontramos con la dirección jmp esp.
Ahora necesitamos saber que SHELLCODE vamos a ejecutar, para ello podemos emplear la web shell-storm donde existen muchas líneas de código en ensamblador que realizan diversas acciones. Entre ellas, he elegido el shellcode que ejecuta execve pasando como parámetro la cadena "/bin/sh".
Finalmente, el exploit resultante es el siguiente.
Si ejecutamos el exploit directamente dirigiendo la salida del exploit al programa mediante una pipe no va a funcionar. Esto sucede porque cuando el shellcode ejecuta el comando sh comprueba si recibe datos por el stream de entrada, el cual se encuentra cerrado, por lo que sh acaba sin ejecutar ningún comando. Para dejar el stream de entrada abierto, es necesario ejecutar cat -.
De esta forma, ejecutamos el exploit obteniendo la contraseña para el nivel 2.
Behemoth 2
A la hora de ejecutar el binario behemoth2 podemos apreciar como el programa no realiza ninguna acción independientemente de lo que escribamos por la terminal.
Ejecutándolo nuevamente con ltrace podemos ver como el programa crea un archivo cuyo nombre es el número de su proceso mediante touch y se espera 2000 segundos o 33 minutos aproximadamente.
Antes que nada, he de aclarar que la forma de resolver el reto la cual voy a explicar se le ocurrió a xavilok, mi forma se basaba en el principio de usar enlaces simbólicos que se verá en el nivel 4, lamentablemente tenías que esperar 30 minutos para que se ejecutase, por lo que es mejor la de Xavi, y es la que se va a utilizar. Dicho esto, seguimos con el reto.
Como se puede ver en la ejecución de ltrace, el comando touch no tiene ninguna ruta asignada de donde se encuentra el binario, por lo que se puede realizar un Path Hijacking para que en lugar de ejecutar touch se ejecute lo que nosotros queramos.
Para ello se ha creado el siguiente script llamado "touch" que ejecuta bash y se le han añadido el permiso de ejecución (chmod +x touch).
Ahora modificamos la variable de entorno PATH, que se encuentra en nuestra consola, para que primeramente busque el binario en la ruta /tmp/Marmeus.
Finalmente, solo queda ejecutar el binario obteniendo nuestra terminal como el usuario "behemoth3".
Behemoth 3
El binario tres muestra por pantalla lo que nosotros le introducimos.
Sin embargo, si le introducimos %xnos muestra un valor en hexadecimal, esto implica a que es vulnerable a Format String. Si quieres saber más aquí tienes un post donde te explican en que consiste la debilidad de Format String.
Para asegurarnos, se puede ver el decompilado del binario, y podemos ver como todo lo que le introducimos es directamente mostrado mediante la instrucción printf.
Entonces, si nosotros enviamos un conjunto de As y un conjunto de |%x, no solamente nos mostrará las As sino que nos mostrará todos los datos que se encuentran en el stack en formato hexadecimal (separados por |). Esto funciona porque el parámetro %x es empleado por printf para sacar el valor introducido como parámetro en hexadecimal. Sin embargo, como el único parámetro que le pasamos es la dirección de la string coge los valores que se encuentran en el stack.
Como podemos ver, lo primero que introducimos, en nuestro caso las As, es lo primero que se muestra y después vemos las As en hexadecimal 41 y el resto de valores en el stack. Entonces, empleando el parámetro %n que escribe el número de caracteres que se han mostrado por pantalla en una dirección de memoria que le pasemos como parámetro.
Entonces, si en vez de introducir un conjunto de As, introducimos una dirección de memoria y posteriormente el parámetro %1$nescribirá un 4 en la dirección de memoria que le hemos introducido al principio (Es un cuatro porque en 32bits las direcciones de memoria son 4 caracteres). Para modificar el número de caracteres que queremos que se muestre por pantalla basta con introducir %<NumCaracteres>.
El objetivo para poder obtener una shell, es mediante la debilidad Format String sobrescribir la dirección de puts en la GOT para que cuando se ejecute la instrucción puts salte al stack donde se encuentre nuestro shellcode y ejecute la shell.
El exploit es el siguiente:
Hay que decir, que la dirección de nuestro shellcode en el stack puede variar si emplease GDB o no, por lo que tendrás que jugar con los 2 últimos bytes de aux y aumentar el número de instrucciones nop en la variable NOP_SLED.
Behemoth 4
Al ejecutar el binario nos muestra que no encuentra el PID.
Una rápida decompilazión con Ghidra nos muestra el siguiente código en C.
Como podemos ver, nada más ejecutarse el programa obtiene su PID y comprueba si existe algún archivo con ese nombre en la ruta /tmp/ si existe el fichero, muestra su contenido, en caso contrario muestra "PID not found!".
Manualmente, es imposible obtener el PID del programa, para luego crear un archivo. Por lo tanto me he creado un script, que obtiene el PID del programa, lo detiene, crea un enlace simbólico para que lea la contraseña del usuario behemoth5 y continúe la ejecución del proceso.
El script es el siguiente.
Al ejecutarlo, obtenemos la contraseña para el siguiente nivel.
Behemoth 5
Como podemos ver en los siguiente comandos, al ejecuta behemoth5 no nos muestra nada por pantalla y se de tiene.
Además, usando ltrace no nos proporciona demasiada información.
Analizando el decompilado que nos proporciona Ghidra, se pueden entender más cosas.
Básicamente, el programa lee el archivo y lo envía a localhost por el puerto 1337. No obstante hay que tener en cuenta que para enviarlo emplea la instrucción sendto la cual envía los datos empleando el protocolo UDP. Por lo tanto, para poder recibir la contraseña necesitamos crear un puerto a la escucha con el protocolo UDP y ejecutar el programa. Para ello se ha empleado netcat.
Behemoth 6
Behemoth6 es bastante distinto a los que hemos visto hasta ahora. El reto esta compuesto por 2 binarios "behemoth6" y "behemoth6_reader". Este último lee los caracteres almacenados en un fichero llamado "shellcode.txt" COMO SI FUESEN CÓDIGO MÁQUINA. El primero, una vez que se ha ejecutado "behemoth6_reader", lee el output que ha generado "behemoth6_reader" y si es igual a HelloKitty\0" ejecuta una shell.
Buscando en Internet, encontré un post en wikipedia el cual te muestra como crear tu propio código máquina para mostrar por pantalla una cadena de caracteres. Sin embargo, nos hace falta la dirección de memoria de la cadena de caracteres que queremos imprimir. Como tenemos control sobre el código a ejecutar, podemos meter la cadena en el stack empleado la instrucción push y pasándole el registro ESP, pues apunta a la parte de arriba del stack. El código máquina es el siguiente:
Ahora, falta transformarlo en hexadecimal, para ello se ha empleado el assembler de defuse.ca, cuyo resultado es el siguiente:
Ahora solo falta emplear python para que nos cree el archivo "shellcode.txt".
Finalmente, solo falta ejecutarlo obteniendo nuestra shell.
Behemoth 7
Al igual que en el nivel 5, el ejecutar el binario no nos muestra nada.
Sin embargo, con ltrace muestra como todas las variables de entorno las sobrescribe con 0s empleando la instrucción menset.
Para entender mejor el binario he vuelto a emplear Ghidra para saber que se esta ejecutando.
Básicamente, el programa sobrescribe todas las variables de entorno a 0s como hemos visto anteriormente con ltrace, y si se le ha pasado un parámetro busca en los primeros 512 caracteres del parámetro y si existen caracteres no imprimibles el programa termina mostrando por pantalla "Non-alpha chars found in string, possible shellcode!". No obstante, el programa es vulnerable a Buffer Overflow pues emplea la instrucción strcpy que copia en local_210 hasta encontrarse un Null Byte (0x00) . Entonces, si enviamos más de 512 caracteres obtenemos un Segmentation Fault.
Como ya sabemos que es vulnerable, falta saber el offset necesario para poder sobrescribir la dirección de retorno.
El offset resultante es de 528 caracteres que podemos comprobarlo ejecutando el exploit con GDB.
Ahora, para poder obtener nuestra una shell se plantea añadir un nop slide y shellcode al payload de tal forma que el proceso salte una vez se produce el Overflow. Lo único, que nos hace falta es conocer una posición de memoria a la cual podemos saltar, para ello se ha empleado GDB.
Como se puede ver en el output mostrado por GDB, una buena dirección a la que se podría salta sería la 0xffffd420. Por lo tanto, juntando toda la información obtenemos el siguiente exploit.
Nota: Al igual que en el nivel 3 es posible que tengas que reajustar el número de nops y la dirección de memoria a saltar, pues es diferente si se usa GDB o no.
Finalmente, se ejecuta el exploit para que el output se pase como parámetro, obteniendo la última contraseña de los retos Behemoth.