Saltearse al contenido

Introducción a la explotación binaria

La explotación binaria (“pwn” o “binary exploitation”) consiste en aprovechar errores en programas compilados —típicamente en C/C++— para alterar su ejecución y, en última instancia, ejecutar código propio o tomar control del proceso. A diferencia de la web, aquí trabajas a nivel de memoria, registros y ensamblador: un fallo al manejar un buffer, un puntero o un entero se convierte en control del flujo de ejecución. Es la disciplina reina de los CTF y la base de los exploits de software de bajo nivel.

C y C++ dan control total sobre la memoria pero sin red de seguridad: no comprueban límites de arrays, confían en que el programador gestione punteros y tamaños correctamente. Un error (escribir más allá de un buffer, usar memoria liberada, confiar en un tamaño controlado por el atacante) corrompe estructuras de memoria que el atacante puede manipular para redirigir la ejecución.

# memoria de un proceso (simplificado)
Stack variables locales, direcciones de retorno (crece hacia abajo)
Heap memoria dinámica (malloc/free)
.text código del programa (ejecutable)
.data/.bss variables globales
# registros clave (x86-64)
RIP/PC instruction pointer: qué instrucción se ejecuta (el objetivo)
RSP stack pointer RBP base pointer
RAX..R15 registros de propósito general

El objetivo casi siempre es controlar RIP (el puntero de instrucción): si decides qué se ejecuta a continuación, controlas el programa.

Stack buffer overflow escribir más allá de un buffer en el stack -> sobrescribir la dirección de retorno (ver pwn-stack)
Format string printf(user) -> leer/escribir memoria arbitraria (pwn-format)
Heap exploitation corromper metadatos del heap (use-after-free, overflow) (pwn-heap)
Integer issues overflow/underflow/signedness -> tamaños/índices erróneos (pwn-integer)
Use-after-free usar memoria ya liberada

Los binarios actuales tienen defensas que hay que entender y sortear:

ASLR aleatoriza las direcciones de memoria -> necesitas un leak
NX/DEP el stack no es ejecutable -> no puedes meter shellcode ahí (-> ROP, pwn-rop)
Stack Canary valor centinela antes de la dirección de retorno -> detecta overflow (hay que filtrarlo)
PIE el propio ejecutable se carga en dirección aleatoria -> necesitas leak
RELRO protege la GOT (ver pwn-got)
# ver qué trae un binario
checksec --file=./binario

El exploit moderno suele ser: filtrar una dirección (bypass ASLR/PIE), sortear el canary, y luego redirigir el flujo (ROP porque NX).

pwntools la librería Python para escribir exploits (interactuar, empaquetar, ROP)
gdb + pwndbg/GEF depurar y ver memoria/registros con ayudas de exploit
checksec ver mitigaciones del binario
ghidra / IDA / radare2 análisis estático (reversing, ver rev-*)
ropgadget / ropper buscar gadgets para ROP
one_gadget encontrar un "gadget mágico" que lanza shell en libc
1. checksec + reversing: entender qué hace el binario y qué protecciones tiene
2. identificar la vulnerabilidad (overflow, format string, heap...)
3. construir un plan: ¿necesito leak? ¿ROP? ¿shellcode?
4. desarrollar el exploit con pwntools (local primero)
5. sortear mitigaciones (ASLR via leak, canary, NX via ROP)
6. conseguir control de RIP -> shell / lectura de la flag
7. lanzar contra el remoto
  • Lenguajes seguros en memoria (Rust, Go) donde sea viable; en C/C++, prácticas seguras (no funciones inseguras como gets/strcpy).
  • Activar todas las mitigaciones: ASLR, NX, stack canaries, PIE, Full RELRO, FORTIFY_SOURCE.
  • Análisis estático/dinámico (sanitizers: ASan, UBSan), fuzzing (AFL++) para encontrar los bugs antes que el atacante.
  • Validar tamaños y límites; no confiar en entrada controlada por el usuario para tamaños/índices.
  • Entender la memoria del proceso y el objetivo (controlar RIP)
  • checksec: ver mitigaciones del binario
  • Identificar la clase de vulnerabilidad
  • Reversing del binario (ghidra/gdb) para entender el flujo
  • Plan de exploit según las protecciones (leak/ROP/shellcode)
  • Desarrollar con pwntools (local)
  • Sortear ASLR/canary/NX/PIE
  • Control de RIP → shell/flag → remoto