Parte: 5 — Explotación de sistemas y binarios · Fuente: The Shellcoder's Handbook · docs pwntools ⏱️ Duración estimada: 140 min · Nivel: Experto
Integrar todo lo aprendido en un flujo de desarrollo de exploits moderno: encadenar primitivas (info leak → cálculo de bases → escritura/control de flujo → ROP → shell), automatizar con pwntools, manejar la libc correcta y escribir exploits fiables y reutilizables. Verás cómo se combinan las técnicas para derrotar NX+ASLR+PIE+canary en un objetivo realista de laboratorio.
⚠️ Ética: solo binarios propios o retos de CTF autorizados.
Al finalizar, el alumno podrá:
| # | Tema | Por qué importa |
|---|---|---|
| 1 | Pensar por primitivas | Estructura mental del exploit |
| 2 | Info leak → base | Vencer ASLR/PIE |
| 3 | Cálculo de direcciones dinámico | Independencia de la versión |
| 4 | ROP + ret2libc combinados | Ejecución bajo NX |
| 5 | pwntools avanzado | Automatización real |
| 6 | libc-database / ret2dlresolve | Cuando no conoces la libc |
| 7 | Robustez y badchars | Que funcione siempre |
| 8 | Local → remoto | Retos en servidor |
base = leak - offset. Clave: hace el exploit robusto entre corridas.system)
sin conocer libc. Clave: útil sin leak de libc.process, remote, recvuntil, sendlineafter). Clave:
el mismo exploit sirve local y remoto.pip install pwntools ROPgadget
# libc-database para identificar libc por un leak
git clone https://github.com/niklasb/libc-database
Entorno propio.
bash
checksec ./target
python
from pwn import *
exe = context.binary = ELF("./target")
libc = ELF("./libc.so.6")
def conn():
return remote(args.HOST, int(args.PORT)) if args.REMOTE else process(exe.path)
io = conn()
python
leak = u64(io.recvline().strip().ljust(8, b"\x00"))
libc.address = leak - libc.symbols["puts"]
log.success(f"libc @ {hex(libc.address)}")
Primitiva 2 — control de flujo: construye una cadena ROP con la base ya conocida para
system("/bin/sh") o un one_gadget, cuidando la alineación.
Si el binario es PIE, filtra también su base y usa exe.address = code_leak - offset.
Si no conoces la libc, identifícala por el leak con libc-database o aplica ret2dlresolve
(rop.ret2dlresolve(...) en pwntools).
Robustece: envuelve en un bucle de reintentos, evita badchars y estabiliza el entorno (env, ASLR).
Prueba ./exploit.py REMOTE HOST=... PORT=... contra un socat local.
args.REMOTE.system por un one_gadget válido y verifica constraints.Desarrolla un exploit completo contra un binario de laboratorio con NX+ASLR (y PIE si te atreves) que obtenga shell filtrando la base de libc en runtime.
Criterio de aceptación: ./exploit.py da shell interactiva de forma fiable (≥ 8/10 corridas) con
ASLR activado, calculando la base dinámicamente.
| Síntoma / mensaje | Causa y cómo arreglar |
|---|---|
| Base de libc incorrecta | libc equivocada; identifícala con el leak |
| Funciona local, no remoto | Diferencias de libc/entorno; usa la del servidor |
| Crash intermitente | Badchars o alineación; revisa el payload |
| one_gadget no da shell | No se cumplen sus constraints; prueba otro |
| Leak desalineado | Falta ljust(8,\x00) o offset del leak erróneo |
❓ ¿Siempre necesito un leak? Con ASLR/PIE, casi siempre. Sin leak, técnicas como ret2dlresolve o partial overwrite pueden ayudar.
❓ ¿Cómo sé qué libc usa el reto? Por un leak + libc-database, o porque el reto la proporciona.
❓ ¿Un exploit debe ser 100% fiable? Apunta a la máxima fiabilidad; en CTF basta con que funcione consistentemente contra el servidor.
Clase 137 — Descubrimiento de vulnerabilidades en código