Saltearse al contenido

Explotación de heap

El heap es la memoria dinámica que gestionan malloc/free. A diferencia del stack, no hay direcciones de retorno que sobrescribir, pero el gestor de memoria (el allocator) guarda metadatos entre y alrededor de los chunks, y esos metadatos se pueden corromper. La explotación de heap consiste en manipular esos metadatos —vía overflows, use-after-free, double-free— para engañar al allocator y lograr escrituras arbitrarias que acaban en control del flujo. Es más compleja que el stack y muy dependiente de la versión de la libc.

# un chunk de memoria tiene cabecera con metadatos:
[ prev_size ][ size | flags ][ ... datos del usuario ... ]
# al liberar (free), los chunks libres se guardan en listas enlazadas (bins):
tcache (glibc >=2.26) listas rápidas por tamaño (el objetivo moderno)
fastbins listas LIFO para chunks pequeños
unsorted/small/large bins
# los punteros fd/bk de esas listas viven en los datos del chunk liberado

La clave: cuando un chunk se libera, el allocator escribe punteros de lista en su área de datos. Si controlas esos punteros, controlas dónde “cree” el allocator que hay chunks libres → malloc te devuelve un puntero a donde tú quieras.

Heap overflow escribir más allá de un chunk -> corromper la cabecera del siguiente
Use-After-Free (UAF) usar un chunk después de free -> leer/escribir datos de otro, o punteros de bin
Double-Free liberar dos veces -> corromper las listas (tcache/fastbin)
Type confusion tratar un objeto como otro tipo

Técnicas clásicas (según versión de libc)

Sección titulada «Técnicas clásicas (según versión de libc)»
tcache poisoning (moderno, el más común) corromper el fd de un chunk en tcache
-> el siguiente malloc devuelve una dirección controlada
fastbin dup double-free en fastbin -> devolver el mismo chunk dos veces
unlink (antiguo) abusar de la macro unlink -> escritura arbitraria
House of <X> familia de técnicas avanzadas (Spirit, Force, Einherjar, Orange...)
para escenarios con primitivas limitadas

tcache poisoning (el pan de cada día moderno)

Sección titulada «tcache poisoning (el pan de cada día moderno)»
# con un UAF o double-free sobre tcache:
1. free(A) # A va a tcache; su fd apunta al siguiente libre
2. editar A->fd = dirección_objetivo # corromper el puntero (UAF/overflow)
3. malloc() -> devuelve A
4. malloc() -> devuelve dirección_objetivo # ¡write/read donde quieras!
# objetivo típico: __free_hook / __malloc_hook (libc antigua) o la GOT -> system
# con un write-what-where del heap:
# libc antigua: sobrescribir __free_hook = system, luego free(chunk con "/bin/sh")
# libc moderna (sin hooks): FSOP (File Stream Oriented Programming),
# sobrescribir estructuras _IO_FILE, o apuntar a one_gadget
pwntools interacción y empaquetado
gdb + pwndbg/GEF comandos de heap: 'heap', 'bins', 'tcache' -> ver el estado del allocator
glibc source / how2heap referencia de técnicas por versión
# how2heap (shellphish): ejemplos reproducibles de CADA técnica

La explotación de heap cambia mucho entre versiones de glibc (se añaden mitigaciones: tcache key, safe-linking a partir de 2.32, etc.). Siempre identifica la versión exacta de libc y usa la técnica que aplique:

# safe-linking (glibc >=2.32): los fd de tcache/fastbin están "cifrados" con la dirección
# -> necesitas un leak del heap para calcular el valor correcto
  • glibc actualizada (mitigaciones de heap: tcache key contra double-free, safe-linking).
  • Hardened allocators (p. ej. hardened_malloc) en entornos críticos.
  • Sanitizers (ASan, con detección de UAF/heap-overflow) en desarrollo y fuzzing.
  • Lenguajes seguros en memoria (Rust) eliminan UAF/double-free por diseño.
  • Revisión de código del manejo de punteros/tamaños; no usar punteros tras free (poner a NULL).
  • Identificar la versión exacta de glibc
  • Identificar el bug: overflow / UAF / double-free
  • Ver el estado del heap en gdb (heap/bins/tcache)
  • Leak del heap si hay safe-linking (>=2.32)
  • tcache/fastbin poisoning → malloc devuelve dirección controlada
  • Write-what-where → __free_hook/GOT/FSOP → system/one_gadget
  • Shell/flag en local → remoto
  • Practicar con how2heap la técnica concreta