
Hashes mágicos – "colisiones" de hash de PHP
Regístrate con contraseña 1 y luego inicia sesión con contraseña 2. Si consigues entrar, entonces el almacenamiento usa el algoritmo especificado para aplicar hash a la contraseña y PHP usa == para compararlas (para MD5, SHA-1 y texto plano).
Para MD5, SHA-1 y la familia SHA-2 se usa el truco conocido desde hace tiempo (en realidad es una funcionalidad documentada; consulta y ) según el cual en PHP ; aquí solo se usa con fines . Cualquier contraseña con cualquier otra contraseña de la lista. Este es un truco distinto al de las ; basta con ver la diferencia entre .
'0e1' == '00e2' == '0'Estos son todos los algoritmos con hashes mágicos:
md5(md5(password))En palabras de @0xb0bb, «hay otras aplicaciones para los hashes mágicos además de la comparación de contraseñas (como capas de caché o datos derivados de la salida de una función hash) en las que estos algoritmos conocidos por ser inseguros, menos conocidos y pseudo-hash se pueden encontrar con mayor facilidad».
Para texto plano se usan varios trucos de conversión. La primera contraseña coincidirá únicamente con la segunda. Los trucos están agrupados por versiones de PHP que los permiten.
bcrypt trunca las contraseñas a una longitud máxima de 72 caracteres. Las contraseñas coinciden si los primeros 72 caracteres de ambas contraseñas coinciden.
descrypt (crypt DES tradicional de UNIX) trunca las contraseñas a una longitud máxima de 8 caracteres. Las contraseñas también coinciden si los primeros 8 caracteres de ambas contraseñas coinciden; consulta la sección «General cross-check».
Si usas una contraseña de más de 64 bytes y le aplicas hash con PBKDF2-HMAC-SHA1, primero se pre-hashea con SHA1, de modo que PBKDF2-HMAC-SHA1(password1) === PBKDF2-HMAC-SHA1(password2) porque sha1(password1) === bin2hex(password2). El mismo pre-hasheo se aplica en el caso de PBKDF2-HMAC-SHA224 y PBKDF2-HMAC-SHA256.
Por ahora solo hay un hash mágico en cada uno de ellos, gracias a Norbert Tihanyi; con suerte, se añadirán más en el futuro.
Usa === al comparar cualquier cosa* en PHP, no ==. Y usa password_hash() y password_verify() para el hash de contraseñas en PHP; no uses MD5 ni SHA-1. *Usa hash_equals() al comparar hashes.
Todo empezó con este tweet. Generé QNKCDZO y 240610708 en febrero de 2014 y desde entonces se ha extendido por todo internet. Solo búscalo en Google.
Allá por 2014 usé mi portátil, algunos bucles for (¿o foreach?), muchos ciclos de CPU y un ventilador externo, pero hoy en día puedes/debes usar una GPU y un hashcat modificado para ello. Consulta este artículo de Carl Löndahl y 0xb0bb.
Chick3nman y compañía también están trabajando en su versión de hashcat; permanece atento.
Si necesitas una colisión real alfanumérica, aquí tienes una colisión MD5 alfanumérica de 72 bytes con una diferencia de 1 byte, incluso de tan solo 1 bit, por Marc Stevens:
md5("TEXTCOLLBYfGiJUETHQ4hAcKSMd5zYpgqf1YRDhkmxHkhPWptrkoyz28wnI9V0aHeAuaKnak")
=
md5("TEXTCOLLBYfGiJUETHQ4hEcKSMd5zYpgqf1YRDhkmxHkhPWptrkoyz28wnI9V0aHeAuaKnak")
Ten en cuenta que si te registras con la primera contraseña e inicias sesión con la segunda, podría significar que el sitio usa bcrypt(md5($password)), no solo md5($password). Este tipo de envoltura de hash se usa a veces al actualizar el hash de contraseñas, pero solo debería usarse de forma temporal.
Consulta el Proyecto HashClash de Marc si te interesan estas colisiones reales o si quieres crear las tuyas propias.
Colisiones reales de hash LM por @solardiz (#35, ¡gracias!):
db82323cb0693862: 2275490 o 0/*LUZ@44b3b60db75c15c1: 2716388 o 1}DC<XT585e239d32df1998: 8351762 o $;)5D|XConsulta el tweet para saber cómo generar más.