Saltearse al contenido

Padding oracle

El padding oracle es uno de los ataques criptográficos más elegantes y a la vez más prácticos: permite descifrar (y a menudo cifrar) datos protegidos con CBC sin conocer la clave, aprovechando que el sistema revela si el relleno (padding) es válido. Aparece en cookies, tokens, parámetros cifrados y APIs.

CBC descifra: P_i = D(C_i) XOR C_{i-1} (C_0 = IV)
PKCS#7 padding: rellena el último bloque con N bytes de valor N (p. ej. 04 04 04 04)
Al descifrar, se valida que el padding sea correcto -> si no, ERROR de padding

El fallo: si el servidor responde distinto ante “padding inválido” vs “padding válido pero datos mal” (error HTTP distinto, mensaje, o incluso timing), tienes un oráculo.

Objetivo: recuperar P2 = D(C2) XOR C1, sin la clave.
Se manipula C1 byte a byte (C1') y se observa el oráculo sobre [C1' | C2]:
- ajustando el último byte de C1' hasta que el padding sea VÁLIDO (0x01),
se deduce D(C2)[último] = C1'[último] XOR 0x01
- conocido D(C2)[último], se fuerza padding 0x02 0x02 y se repite para el penúltimo byte
- ... así hasta recuperar los 16 bytes de D(C2) -> luego P2 = D(C2) XOR C1 (el C1 real)
Resultado: se descifra bloque a bloque TODO el mensaje. Máx. 256 pruebas por byte.

Para cifrar texto a voluntad (forjar un criptograma válido) se usa la misma propiedad al revés, eligiendo los C_{i-1} que produzcan el texto deseado.

# padbuster: automatiza el ataque contra un endpoint web
padbuster http://host/x?data=<C> <C_en_base64> 16 -encoding 0 -cookies 'sess=...'
# python-paddingoracle para montarlo a medida cuando el oráculo es no-estándar
# clave: definir la función oracle(ciphertext)->bool (padding ok?) correctamente

Señales de que hay oráculo: un parámetro/cookie que es claramente un criptograma (múltiplo de 16 bytes en base64/hex) y respuestas distinguibles al corromperlo.

Variante: Padding Oracle en RSA (Bleichenbacher / ROBOT)

Sección titulada «Variante: Padding Oracle en RSA (Bleichenbacher / ROBOT)»

El mismo principio aplica a RSA con padding PKCS#1 v1.5: un oráculo de “padding válido” permite descifrar o firmar. Revivido como ROBOT (2017) en grandes sitios (ver PKI & certificados/TLS).

  • padbuster, python-paddingoracle, scripts propios en PyCryptodome.
  • Burp (para automatizar peticiones y distinguir respuestas), CyberChef (verificar bloques).
  • Cifrado autenticado (AEAD): AES-GCM / ChaCha20-Poly1305 — no hay padding que validar.
  • Si se usa CBC, encrypt-then-MAC y verificar el MAC antes de intentar descifrar/validar padding.
  • No distinguir errores: misma respuesta y tiempo ante padding inválido y datos inválidos.
  • No exponer criptogramas manipulables al cliente sin integridad.
  • Vaudenay (2002): formulación original del padding oracle sobre CBC.
  • Lucky Thirteen (2013): padding oracle por timing en TLS CBC.
  • ROBOT (2017): Bleichenbacher (padding oracle RSA) en Facebook, PayPal, Cisco, F5, etc.
  • POODLE (2014): padding oracle sobre SSLv3 CBC.
  • Localizar parámetros/cookies que sean criptogramas CBC (múltiplo de 16)
  • ¿El sistema distingue “padding inválido” de “datos inválidos”? (error/timing)
  • Ejecutar padbuster / script para descifrar bloque a bloque
  • Probar la forja de criptogramas (cifrado controlado)
  • RSA PKCS#1v1.5: buscar oráculo tipo Bleichenbacher/ROBOT
  • Verificar defensa: AEAD o encrypt-then-MAC + respuestas uniformes