Ataque de extensión de longitud de hash
Un ataque de extensión de longitud es una vulnerabilidad criptográfica que afecta a funciones hash construidas con la construcción Merkle-Damgård (MD5, SHA-1, SHA-256). Permite a un…
Definición
Un ataque de extensión de longitud es una vulnerabilidad criptográfica que afecta a funciones hash construidas con la construcción Merkle-Damgård (MD5, SHA-1, SHA-256). Permite a un atacante que conoce el hash H(secreto || mensaje) calcular un hash válido para H(secreto || mensaje || relleno || datos_extra) sin conocer el secreto, simplemente continuando el proceso de hash desde el estado interno que representa el hash conocido.
La vulnerabilidad no está en los datos ni en el secreto, sino en cómo la función hash transfiere su estado interno entre bloques de datos.
Contexto
Fundamentos de funciones hash criptográficas
Las funciones hash transforman una entrada de longitud variable en una salida de longitud fija (el digest). Sus propiedades de seguridad son:
- Resistencia a preimagen: dado
H(m), no es viable calcularm. - Resistencia a segunda preimagen: dado
m₁, no es viable encontrarm₂ ≠ m₁conH(m₁) = H(m₂). - Resistencia a colisiones: no es viable encontrar ningún par
(m₁, m₂)conH(m₁) = H(m₂).
Usos comunes: verificación de integridad de archivos, almacenamiento de contraseñas, firmas digitales, HMAC.
Construcción Merkle-Damgård y por qué es explotable
MD5, SHA-1 y SHA-256 procesan los datos en bloques de tamaño fijo (512 bits). El proceso es:
- Padding: el mensaje se rellena hasta el siguiente múltiplo del tamaño de bloque.
- Procesamiento por bloques: cada bloque actualiza un estado interno (registros A, B, C, D en MD5; H0–H7 en SHA-256).
- Salida: el estado interno final es el hash.
La vulnerabilidad radica en que el estado interno tras procesar el mensaje original es exactamente el hash. Si un atacante obtiene el hash, obtiene el estado desde el que la función continuaría procesando bloques adicionales. Puede así extender el mensaje y calcular el nuevo hash válido sin conocer la entrada original.
Funciones hash comparadas
| Función | Tamaño de bloque | Estado interno | Rondas | ¿Vulnerable a LEA? |
|---|---|---|---|---|
| MD5 | 512 bits | 128 bits (4 registros) | 64 | ✅ Sí |
| SHA-1 | 512 bits | 160 bits (5 palabras) | 80 | ✅ Sí |
| SHA-256 | 512 bits | 256 bits (8 palabras) | 64 | ✅ Sí (si se usa sin HMAC) |
| SHA-3 (Keccak) | Variable | Construcción esponja | — | ❌ No |
| HMAC-SHA256 | — | Clave mezclada | — | ❌ No |
Desarrollo
Mecánica del ataque
Para ejecutar un ataque de extensión de longitud, el atacante necesita:
- El hash
H(secreto || mensaje). - La longitud del secreto (o capacidad de estimarla).
- Comprensión del relleno (padding) que aplica la función hash.
El relleno PKCS-SHA añade:
- Un bit
1al final del mensaje. - Ceros hasta llegar a 448 bits (para un bloque de 512 bits).
- La longitud original del mensaje en los últimos 64 bits.
Ejemplo para SHA-256 con mensaje de 72 bits (“TryHackMe”):
72 bits de mensaje + 1 bit '1' + 375 bits de ceros + 64 bits de longitud = 512 bitsUna vez añadido el relleno, la función continúa procesando nuevos bloques. Los 64 rounds de SHA-256 por bloque actualizan las 8 variables de trabajo (a–h), que se suman a los valores hash iniciales (H0–H7) para producir el estado final.
El hash resultante es exactamente el estado que el atacante necesita para continuar el proceso.
Escenario de comparación
| Hashing normal | Ataque de extensión |
|---|---|
Mensaje: usuario=test |
Mensaje: usuario=test |
| Padding → 1 bloque | El atacante añade &admin=true |
| Hash válido para el mensaje original | Nuevo hash predecible sin conocer la clave |
Escenario 1 — Falsificación de firma en archivos (Lab 1)
La aplicación en http://lea.thm/labs/lab1/ firma nombres de archivo con SHA-256:
function sign($str, $secret) { return hash('sha256', $secret . $str);}// Valida: sign($file, $SECRET) === $signatureEl atacante conoce el hash de 1.png y quiere acceder a 4.png. Usando hash_extender:
# Solo en laboratorio controlado./hash_extender \ --data 1.png \ --signature 02d101c0ac898f9e69b7d6ec1f84a7f0d784e59bbbe057acb4cef2cf93621ba9 \ --append /../4.png \ --out-data-format=htmlSalida:
Type: sha256Secret length: 8New signature: <nuevo_hash>New string: 1%2epng%80%00...%00h%2f%2e%2e%2f4%2epngLa solicitud falsificada:
GET /product.php?file=1%2epng%80%00...%2f4%2epng&signature=<nuevo_hash>El servidor valida la firma y concede acceso a 4.png porque el hash extendido es criptográficamente válido para la cadena completa (incluyendo el relleno).
Escenario 2 — Escalada de privilegios en cookie (Lab 2)
La aplicación en http://lea.thm/labs/lab2/ firma cookies con SHA-256:
if ($hsh === hash("sha256", $SECRET . $auth)) { if (strpos($auth, 'role=1') !== false) { // Panel de admin }}Cookie de usuario estándar: username=user;role=0. El atacante extiende la cookie para añadir ;role=1:
# Solo en laboratorio controlado./hash_extender \ --data 'username=user;role=0' \ --append ';role=1' \ --signature bfe0fa5c36531773c73dcc8d2a931301f69cf9add05a1f35dcfa2d48b44c37f0 \ --format sha256 \ --secret 8 \ --out-data-format=htmlResultado: una nueva firma y cadena auth con ;role=1 al final. El servidor aplica strpos($auth, 'role=1'), que coincide aunque haya relleno binario intermedio, concediendo acceso de administrador.
Herramienta: hash_extender
- Repositorio: https://github.com/iagox86/hash_extender
- Instalación:
gcc hash_extender.c -o hash_extender -lcrypto - Parámetros clave:
--data: datos originales que se firmaron.--signature: hash original.--append: datos a añadir.--format: algoritmo (md5, sha1, sha256…).--secret: longitud de la clave secreta (puede requerirse fuerza bruta si se desconoce).--out-data-format=html: formato de salida para URL encoding.
⚠️ Solo en laboratorio. Usar contra sistemas en producción sin autorización es ilegal.
Ejemplos
Generación normal de hash SHA-256:
import hashlibmensaje = "TryHackMe"h = hashlib.sha256(mensaje.encode()).hexdigest()# h = "9e897fb7e8832e7d6e5f63a4bdbd0cd6496f53cb3f54b5abf84217d9f4ca5397"Implementación vulnerable de firma (no usar en producción):
import hashlib# VULNERABLE: no usar hash(secret + mensaje) para firmasdef firma_vulnerable(secreto, mensaje): return hashlib.sha256((secreto + mensaje).encode()).hexdigest()Implementación segura con HMAC:
import hmac, hashlibdef firma_segura(clave, mensaje): return hmac.new(clave.encode(), mensaje.encode(), hashlib.sha256).hexdigest()Pitfalls
- “SHA-256 es seguro, lo usaré para firmar”: SHA-256 directo sobre
secreto || mensajees vulnerable a LEA. La seguridad del algoritmo no compensa la estructura explotable de Merkle-Damgård. - “Si no conozco la longitud del secreto, el ataque falla”: hash_extender permite iterar sobre longitudes de secreto posibles (1–255 bytes). Si la respuesta del servidor varía entre longitudes válidas e inválidas, se puede determinar la longitud por fuerza bruta.
- “Solo funciona si el secreto va al principio”: correcto,
H(mensaje || secreto)no es vulnerable a LEA pero sí puede ser vulnerable a otros ataques. HMAC es la solución robusta. - “SHA-3 también es vulnerable”: SHA-3 usa construcción esponja, no Merkle-Damgård. No es vulnerable a LEA.
- “HMAC mitiga pero el servidor puede seguir mostrando errores útiles”: las side-channel responses (respuestas de tiempo diferente o errores detallados) pueden seguir siendo explotables aunque se use HMAC.
Diagrama
sequenceDiagram
participant A as Atacante
participant S as Servidor
Note over A: Conoce: H(secret||"1.png"), longitud del secret
A->>A: Calcula padding para "1.png" con su longitud
A->>A: hash_extender: extiende con "/../4.png"
A->>A: Obtiene nueva firma válida
A->>S: GET /product.php?file=1.png[padding]/../4.png&sig=nueva_firma
S->>S: sign("1.png[padding]/../4.png", $SECRET)
S->>S: Firma coincide ✅
S->>A: Responde con contenido de 4.png
Referencias
- TryHackMe — Length Extension Attacks: https://tryhackme.com/room/lenghextensionattack
- hash_extender (iagox86): https://github.com/iagox86/hash_extender
- OWASP A02 — Cryptographic Failures: https://owasp.org/Top10/A02_2021-Cryptographic_Failures/
- NIST FIPS 180-4 — Secure Hash Standard: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf
- Ambionics — SHA-256 Length Extension: https://www.ambionics.io/blog/length-extension-attack-on-hmac
Ver también: Cryptographic Failures, Padding Oracle Attack, Insecure Randomness