Procedimiento práctico para identificar el formato de una cadena hash
· Actualizado el: · Go Komura · Hash, Seguridad, Contraseñas, Aprovechamiento de activos existentes, Investigación técnica
Hay bastantes situaciones en las que, al ver una cadena como 5f4dcc3b5aa765d61d8327deb882cf99 o $2b$12$... que quedó en un log o en una base de datos, se necesita determinar «de qué hash se trata». En la migración de sistemas existentes, la investigación de métodos de autenticación, el análisis de logs o la integración con sistemas de terceros, no es raro quedarse detenido justo en este punto.
Ahora bien, aquí lo peligroso es decidir de inmediato solo por la longitud.
Ver una cadena hexadecimal de 64 dígitos y afirmar «es SHA-256» es precipitado. SHA3-256, SHA-512/256, BLAKE2s-256 y la salida predeterminada de 32 bytes de BLAKE3 pueden tener exactamente la misma longitud. En cambio, un formato de almacenamiento que incluye hasta el prefijo y los parámetros, como $2b$ o $argon2id$, se puede identificar con bastante precisión solo con la cadena.
En este artículo se usa la palabra hash en un sentido amplio: no solo message digests como MD5, SHA-2 o SHA-3, sino también las representaciones de cadena para almacenar contraseñas, como bcrypt, scrypt, Argon2 o PBKDF2.
El contenido está organizado a partir de documentación oficial publicada hasta abril de 2026: RFC, NIST, crypt(5) de Linux, Apache, Django, Spring Security, entre otros.
El público objetivo es quien se encarga de la migración de sistemas existentes, la investigación de métodos de autenticación o el análisis de logs, y necesita determinar qué es esa «cadena que parece un hash» que tiene delante. Como conocimiento previo basta con saber qué son la notación hexadecimal y Base64.
Además, use el procedimiento de este artículo únicamente con cadenas de entornos que usted mismo administra, o entornos para los que cuenta con autorización explícita para investigar. Extraer el hash de contraseña de la cuenta de otra persona o analizar el hash de un sistema sobre el que no tiene autorización no se justifica aunque el propósito sea una investigación. Los comandos de verificación que se presentan en la segunda mitad del artículo también parten de la base de que se prueban con cuentas de prueba o con muestras creadas por usted mismo.
Índice
- Primero, la conclusión
- Tabla de identificación de un vistazo
- Procedimiento práctico de identificación
- Errores de identificación habituales
- Orden de verificación para confirmar al 100 %
- Resumen
- Servicios relacionados con este tema
- Referencias
1. Primero, la conclusión
Antes que nada, resumamos brevemente la conclusión.
-
Los formatos de almacenamiento con prefijo o separadores son bastante fáciles de identificar solo con la cadena. Ejemplo:
$argon2id$...,$2b$...,$5$...,$6$...,{SHA}...,pbkdf2_sha256$... -
Con solo una cadena hexadecimal o Base64 plana, casi siempre se llega únicamente a «acotar candidatos». Ejemplo:
32 hex = podría ser MD5, pero también podría provenir de MD4 o de un hash NT -
El tipo de carácter es tan importante como la longitud. Si aparecen
+/=es probable que sea Base64 según RFC 4648; si hay.junto con separadores$, es probable que pertenezca a la familiacrypt(3): este tipo de distinciones son útiles. -
Para confirmar al 100 % hace falta el contexto. La respuesta cambia según se trate de
/etc/shadow, de.htpasswd, deauth_userde Django o de Spring Security.
En resumen, «los formatos que se pueden identificar solo con la cadena» y «los formatos en los que la cadena sola solo revela un grupo de candidatos» son cosas distintas. Con solo separar estos dos casos al pensar, el avance de la investigación cambia.
2. Tabla de identificación de un vistazo
Antes de leer la tabla, conviene organizar cuatro términos que aparecen en este artículo como «nombres de formato». Todos se usan en contextos parecidos, pero designan cosas distintas.
| Término | Forma completa | Qué designa |
|---|---|---|
crypt(3) |
- | La función de hash de contraseñas de Unix en sí misma. Es el nombre de una función de la biblioteca C, y se escribe así porque aparece en la sección 3 del man (funciones de biblioteca) |
crypt(5) |
- | La página de manual que describe el formato de cadena que esa función lee y escribe. Corresponde a la sección 5 del man (formatos de archivo), y ahí se documenta un formato como $6$salt$hash |
| MCF | Modular Crypt Format | Nombre habitual para la convención de «colocar $id$ al inicio para indicar el formato». No existe una especificación única; es un nombre que se consolidó como costumbre a medida que crecían las implementaciones de la familia crypt(3) |
| PHC string format | Password Hashing Competition string format | Una especificación que reorganiza el MCF. Define incluso la forma de escribir la versión y los parámetros, como en $argon2id$v=19$m=65536,t=3,p=4$salt$hash |
En pocas palabras: crypt(3) es la función, crypt(5) es la especificación de su formato de salida, MCF es el nombre habitual de ese formato y PHC string format es una nueva formalización de ese mismo formato. Cuando en las tablas siguientes aparezca «PHC string format» o «familia crypt», léalo con esta distinción en mente.
2.1 Formatos que se pueden identificar casi con certeza por el prefijo o los marcadores de formato
En la tabla, «fuerza de la identificación» se usa con este significado.
- Fuerte: se puede identificar casi con certeza solo con la cadena
- Media: los candidatos se acotan bastante, pero hay que prestar atención a las diferencias entre implementaciones
- Débil: no se puede afirmar solo por la longitud o el aspecto
| Aspecto de la cadena | Formato que se debe sospechar primero | Fuerza de la identificación | Notas | Ejemplo |
|---|---|---|---|---|
$argon2id$... |
Argon2id | Fuerte | Formato PHC string format. A menudo le siguen v=, m=, t=, p= |
$argon2id$v=19$m=65536,t=3,p=4$MDEyMzQ1Njc4OWFiY2RlZg$uKZLaN6muIyoyIYr5waqw3y+zaDbe9aLSPj6Ln/rbz4 |
$argon2i$... |
Argon2i | Fuerte | Igual que arriba | $argon2i$v=19$m=65536,t=3,p=4$MDEyMzQ1Njc4OWFiY2RlZg$Kx1koF/7n8EytGJYTS5krh+ag+FlG5ksM4xOsjOSDvo |
$argon2d$... |
Argon2d | Fuerte | Igual que arriba | $argon2d$v=19$m=65536,t=3,p=4$MDEyMzQ1Njc4OWFiY2RlZg$HLIGA+T1bwK8akx3LGOco+Df+PvxX6cIXhycO7O7t6c |
$2a$... / $2b$... / $2y$... |
bcrypt | Fuerte | Costo de 2 dígitos + alfabeto de la familia crypt | $2b$12$9YQ2u/e5Y/ArOnG.gJKxK.0makLATcYLP1q.Nsabzrw7XErYCfoYO |
$1$... |
md5crypt | Fuerte | Formato de almacenamiento de contraseñas MD5 de tipo Unix | $1$vA7mQ9xZ$Erz32JUFnZ9991KdU5.N3. |
$5$... |
sha256crypt | Fuerte | no es SHA-256 plano | $5$rounds=5000$N3v8Kx2Lq9Rt$uOTla5GAHaRH2aHlUSjkrZUBCuFiahQZ36O/seB39r3 |
$6$... |
sha512crypt | Fuerte | no es SHA-512 plano | $6$rounds=5000$N3v8Kx2Lq9Rt$6LUcSUAELX3aC/.60pTB.TFLTQi1mOGRCwKqNCqtRSaXjorxj01HJ9oNni97Kci1uDt7a/Kn4t3OS20Dw/.vi1 |
$7$... |
scrypt (familia crypt) | Fuerte | Se ve en implementaciones de la familia crypt(5) de Linux |
$7$CU..../....k2XAnEHBqQ1Ct2aMXFKNa/$y3Q0e/UlCHacIGWQshgvvz6UIbP.BCja.5BfVWP2Ml8 |
$y$... |
yescrypt | Fuerte | Se ve en distribuciones Linux más recientes | $y$j9T$k2XAnEHBqQ1Ct2aMXFKNa/$OVYXzjlkiQpWT/F1CUE0JrvV4phLY8FB.ofDttnrSQ7 |
$apr1$... |
Apache APR1-MD5 | Fuerte | Frecuente en .htpasswd |
$apr1$vA7mQ9xZ$ZE64.ohiyK11sPZmtnJZQ. |
{SHA}... |
Representación en Base64 de un digest SHA-1 | Fuerte | Frecuente en entornos Apache / LDAP | {SHA}VBPuJHI7uixaa6LQGWx4s+5GKNE= |
{SSHA}... |
SHA-1 con salt | Fuerte | Entornos LDAP | {SSHA}/OczD0GNNkOAUPbYhA3L9fjmcyBCbHVlTWVzYTQyIQ== |
{MD5}... / {SMD5}... |
MD5 / MD5 con salt | Fuerte | Entornos LDAP | {MD5}X03MO1qnZdYdgyfeuILPmQ=={SMD5}fOn1rOv4ZH0OrO/KT9H0fEJsdWVNZXNhNDIh |
pbkdf2_sha256$... |
PBKDF2-HMAC-SHA256 | Media a fuerte | Django y otros; la implementación antepone el nombre del formato | pbkdf2_sha256$600000$N3v8Kx2Lq9Rt$CLxGB+zTiV1IdOt2y4m9JpaAONzHuRTOd96xKQwRQAs |
{bcrypt}$2b$... |
bcrypt | Fuerte | Con el envoltorio {id} de Spring Security |
{bcrypt}$2b$12$9YQ2u/e5Y/ArOnG.gJKxK.0makLATcYLP1q.Nsabzrw7XErYCfoYO |
{pbkdf2}... / {scrypt}... |
Formato con etiqueta de implementación | Media a fuerte | Spring Security y similares; aquí se identifica el formato del envoltorio, más que el algoritmo en sí | {pbkdf2}sha256$600000$Qmx1ZU1lc2E0MiE$4eNuai1qNkgs1kXz3+tBUMzAexVsSUz9SrQKEhbk0Cw{scrypt}ln=14,r=8,p=1$Qmx1ZU1lc2E0MiE$xAgBRhXbMtHB1UHUR0br5bI+1XdXWKbwauiFv5VRQBY |
El punto clave de esta tabla es que los formatos en los que los primeros caracteres tienen significado son «fuertes».
En particular, cuando aparece algo delimitado por $...$, es muy probable que pertenezca a la familia Unix crypt(3) / MCF / PHC, y conviene mirar el prefix antes que la longitud, porque es más rápido.
2.2 Tabla para acotar candidatos por longitud en hexadecimal / Base64 plano
Esta es la tabla que se usa cuando se tiene una simple «cadena digest» sin prefix.
Si la representación mezcla :, - o espacios, primero hay que quitar esos separadores y luego contar la longitud.
| Longitud en bytes | N.º de caracteres hex | N.º de caracteres Base64 (con = / sin =) |
Candidatos principales | Ejemplo |
|---|---|---|---|---|
| 4 | 8 | 8 / 6 | Sumas de verificación como CRC32 | cbf43926 |
| 16 | 32 | 24 / 22 | MD5, MD4, hash NT (basado en MD4) | 5f4dcc3b5aa765d61d8327deb882cf99 |
| 20 | 40 | 28 / 27 | SHA-1, RIPEMD-160 | da39a3ee5e6b4b0d3255bfef95601890afd80709 |
| 28 | 56 | 40 / 38 | SHA-224, SHA-512/224, SHA3-224 | d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f |
| 32 | 64 | 44 / 43 | SHA-256, SHA-512/256, SHA3-256, BLAKE2s-256, salida predeterminada de 32 bytes de BLAKE3 | e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 |
| 48 | 96 | 64 / 64 | SHA-384, SHA3-384, BLAKE2b-384 | 38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b |
| 64 | 128 | 88 / 86 | SHA-512, SHA3-512, BLAKE2b-512, Whirlpool | cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e |
Cómo leer la columna «N.º de caracteres Base64»: esta columna presenta dos casos en paralelo, con y sin el relleno (padding) de =. Como el Base64 de RFC 4648 se ajusta en bloques de 4 caracteres, solo cuando la longitud en bytes original no es múltiplo de 3 se añaden uno o dos = al final. Muchas implementaciones para JWT o para incrustar en URL eliminan ese =, así que un mismo digest puede tener tanto 43 como 44 caracteres. En cambio, cuando la longitud es múltiplo de 3, como en el caso de 48 bytes, no hay padding, por lo que aparece el mismo número en ambos lados, 64 / 64. Al acotar candidatos por longitud, compare siempre con ambos números.
Lo importante aquí es que aunque coincida la longitud, el formato no queda determinado de forma única.
En particular, un hexadecimal de 32 / 64 / 128 dígitos tiene muchos candidatos, y afirmar el formato solo con eso es fácil que resulte equivocado.
2.3 Ejemplos representativos que suelen confundir
| Aspecto de la cadena | Conclusión precipitada habitual | Cómo interpretarla realmente | Ejemplo |
|---|---|---|---|
5f4dcc3b5aa765d61d8327deb882cf99 |
Confirmado como MD5 | Parece MD5, pero también podría ser MD4, un hash NT o un uso de MD5 específico de la aplicación | 8846f7eaee8fb117ad06bdd830b7586c |
Un hexadecimal de 64 dígitos como 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824 |
Confirmado como SHA-256 | Es un candidato de SHA-256, pero también podrían ser SHA3-256 / SHA-512/256 / BLAKE2s-256 / BLAKE3 | e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 |
$6$rounds=5000$salt$hash |
Representación hexadecimal de SHA-512 | No lo es: se trata de una cadena de hash de contraseña llamada sha512crypt | $6$rounds=5000$N3v8Kx2Lq9Rt$6LUcSUAELX3aC/.60pTB.TFLTQi1mOGRCwKqNCqtRSaXjorxj01HJ9oNni97Kci1uDt7a/Kn4t3OS20Dw/.vi1 |
{SHA}VBPuJHI7uixaa6LQGWx4s+5GKNE= |
Algún «SHA» genérico | En el contexto de Apache / LDAP suele referirse a un digest SHA-1 codificado en Base64 | {SHA}VBPuJHI7uixaa6LQGWx4s+5GKNE= |
{bcrypt}$2b$12$... |
Un formato propio llamado {bcrypt} |
Es bcrypt con el envoltorio de Spring Security | {bcrypt}$2b$12$9YQ2u/e5Y/ArOnG.gJKxK.0makLATcYLP1q.Nsabzrw7XErYCfoYO |
3. Procedimiento práctico de identificación
A partir de aquí se organiza, en orden, cómo mirar la cadena en la práctica. Se recomienda el orden prefix → separador → tipo de carácter → longitud → contexto.
3.1 Primero, mire el símbolo inicial
Con apenas el primer carácter hasta unos 10 caracteres, ya se puede acotar bastante.
-
$argon2id$/$argon2i$/$argon2d$Sospeche fuertemente del PHC string format de Argon2. Para seguir sus componentes es útil consultar la columna «Ejemplo» de 2.1. -
$2a$/$2b$/$2y$Sospeche fuertemente de bcrypt. -
$1$/$5$/$6$/$7$/$y$Sospeche de un hash de contraseña de la familia Unixcrypt(3). -
{SHA}/{SSHA}/{MD5}/{SMD5}Sospeche de una representación de la familia LDAP / Apache. -
{bcrypt}/{pbkdf2}/{scrypt}Sospeche de un formato de almacenamiento con etiqueta de implementación, como el de Spring Security.
El truco aquí es fijarse no solo en el «algoritmo en sí», sino también en el «formato de almacenamiento».
Por ejemplo, $6$ no es «un digest de SHA-512», sino «una cadena de hash de contraseña que usa SHA-512». Confundir esto desvía la investigación posterior.
3.2 Cuente el número de caracteres separadores
A continuación, observe separadores como $, :, {}, , o =.
-
Hay varios
$Sospeche de un formato que agrupa parámetros, salt y hash. Argon2, bcrypt, sha256crypt y sha512crypt son ejemplos típicos. -
Empieza por
{nombre}Sospeche de un envoltorio que declara explícitamente el nombre del formato, como en LDAP o Spring Security. -
Una forma como
algo:salt:hashoalgo$iterations$salt$hashSospeche de un formato propio de un framework o de una aplicación. Elpbkdf2_sha256$iterations$salt$hashde Django es un ejemplo típico.
Cuantos más separadores tiene la cadena, más fácil es identificar el formato. En cambio, si solo hay un bloque de hexadecimal o Base64 simple, la ambigüedad es bastante alta.
3.3 Observe el tipo de carácter
El tipo de carácter es tan importante como la longitud.
Representación hexadecimal
Si la cadena está compuesta únicamente por [0-9a-fA-F], sospeche primero de una representación hexadecimal.
En este caso, número de caracteres ÷ 2 = longitud en bytes del valor original.
- 32 hex → 16 bytes
- 40 hex → 20 bytes
- 64 hex → 32 bytes
- 128 hex → 64 bytes
Base64 / Base64url de RFC 4648
Si aparecen + / =, sospeche primero de un Base64 normal.
Si aparecen - _, sospeche de Base64url.
Como a veces se omite el padding =, la longitud puede ser «cualquiera de dos valores posibles», como 43 / 44 u 86 / 88.
radix64 de la familia crypt
Si aparecen . y /, y además hay separadores $...$, es más natural sospechar del alfabeto de la familia crypt antes que de un Base64 normal.
bcrypt, sha256crypt, sha512crypt, md5crypt, yescrypt y scrypt usan este tipo de conjunto de caracteres.
Este punto pasa desapercibido, pero es bastante útil.
Si se interpreta que «tiene un ., así que es un Base64 roto», es fácil pasar por alto bcrypt o la familia crypt(3).
3.4 Cuente la longitud
Después de observar el tipo de carácter, sigue la longitud. La idea es simple.
- Para hexadecimal:
longitud en bytes del original = número de caracteres / 2 - Para Base64:
número de caracteres ≒ 4 × ceil(longitud en bytes del original / 3)Sin embargo, si se omite el padding=, la longitud se acorta entre 0 y 2 caracteres
En esta etapa se acotan los candidatos. Sin embargo, es más seguro no dar el salto de ver un hexadecimal de 64 caracteres y confirmar directamente SHA-256.
3.5 Confirme por el contexto
Lo último que resulta útil es el contexto. Aquí es donde uno se acerca al 100 %.
-
Está en
/etc/shadowSospeche de un formato de hash de contraseña de Linux, como$y$,$6$,$5$o$1$ -
Está en
.htpasswdSospeche de algo de la familia Apache, como$apr1$,{SHA}o bcrypt -
Está en la configuración de Django o en
auth_user.passwordSospeche de un formato de Django, comopbkdf2_sha256$...oargon2$... -
Está en la tabla de autenticación de Spring Security Sospeche de un formato con
{id}, como{bcrypt}...o{pbkdf2}... -
Un hexadecimal de 32 caracteres relacionado con integración SMB / AD Considere fuertemente la posibilidad de un hash NT (basado en MD4)
En la práctica, no son pocos los casos en los que es más rápido observar el producto, el framework o el nombre del archivo de configuración de origen que mirar solo la cadena en sí.
4. Errores de identificación habituales
4.1 Dar por hecho que 64 hex = SHA-256
Esto es bastante habitual. Por supuesto que SHA-256 es un candidato fuerte, pero existen varios formatos con la misma salida de 32 bytes. SHA3-256, SHA-512/256, BLAKE2s-256 y la salida predeterminada de BLAKE3 también tienen la misma longitud.
La longitud sirve para formar un grupo de candidatos, no para confirmar el formato.
4.2 Confundir $6$ con SHA-512 plano
$6$... es el prefijo de sha512crypt.
No es «un digest hexadecimal de SHA-512», sino una cadena de hash de contraseña que incluye salt y rounds.
De la misma manera,
$5$es sha256crypt$1$es md5crypt
En el momento en que aparece un prefijo, ya no se trata de «un simple digest».
4.3 Pensar que {SHA} es «alguno entre SHA-256 o SHA-512»
En el contexto de Apache o LDAP, {SHA} no significa vagamente «algo de la familia SHA».
En la mayoría de los casos designa un digest SHA-1 codificado en Base64. {SSHA} es SHA-1 con salt.
Si se trata {SHA} de forma ambigua, como «algún SHA», solo por su aspecto, se termina cometiendo errores en el código de verificación o en el proceso de migración.
4.4 Tratar el hash de contraseña y el hash de contenido como si fueran lo mismo
Aunque se hable en ambos casos de una «cadena hash», el propósito es distinto.
- Digest para verificar la integridad de un archivo
- Digest para la firma de una API
- Hash / cadena KDF para almacenar contraseñas
Estos tres, aunque se parezcan en el aspecto, se manejan de forma diferente. En particular, el hash de contraseña suele incluir en la cadena el salt, los rounds, el costo de memoria, el paralelismo, etc., y no se puede identificar con la idea de «comparar el digest en bruto».
4.5 Olvidar los XOF y los digests de longitud variable
SHAKE128 / SHAKE256 son XOF, así que se puede elegir libremente la longitud de salida. BLAKE2 también permite cambiar la longitud del digest, y BLAKE3 tiene salida extensible (extendable output).
En otras palabras, la inferencia «como tiene esta longitud, es este formato» falla si se asume demasiado que se trata de un digest clásico de longitud fija.
4.6 Tratar «NTLM» y «hash NT» como si fueran lo mismo
Esto es una cuestión de terminología, pero resulta bastante útil en investigaciones relacionadas con Windows / AD.
- Hash NT: es un valor de 16 bytes que se obtiene codificando la contraseña en UTF-16LE y aplicándole MD4. Aparece como un hexadecimal de 32 dígitos, por ejemplo
8846f7eaee8fb117ad06bdd830b7586c. También en la especificación se define comoNTOWFv1(Passwd, User, UserDom) = MD4(UNICODE(Passwd)). Esta definición aparece tal cual en el apartado de NTLM v1 Authentication de MS-NLMP, citado en la referencia 13. - NTLM: es el nombre del protocolo de autenticación que realiza el desafío/respuesta usando ese valor como clave. No es el nombre de un formato de cadena.
En el terreno se entiende también la expresión «hash NTLM», pero al volcarlo en una tabla de identificación es más preciso escribir hash NT (basado en MD4). Separar estos conceptos evita mezclar la identificación del formato («¿este hexadecimal de 32 caracteres es MD5 o un hash NT?») con la cuestión del protocolo («¿esta comunicación es NTLM o Kerberos?»).
Además, el hash NT no tiene salt. Como una misma contraseña siempre produce el mismo hexadecimal de 32 caracteres, el propio hecho de que «aparezcan hexadecimales de 32 caracteres sin salt alineados en una tabla proveniente de AD» ya es una pista.
5. Orden de verificación para confirmar al 100 %
En una migración o en la integración de autenticación, al final se necesita confirmar el formato. En ese caso, seguir este orden reduce el riesgo de errores.
5.1 Identifique el origen del almacenamiento
Primero, determine de dónde proviene la cadena.
- ¿Del shadow de Linux?
- ¿De la autenticación básica de Apache / Nginx?
- ¿De LDAP?
- ¿De Django / Spring Security?
- ¿De la base de datos de una aplicación propia?
En muchos casos, la especificación del origen de almacenamiento pesa más que la cadena en sí misma.
5.2 Busque el «formato de almacenamiento» en la documentación oficial
A continuación, busque no el nombre del algoritmo, sino el formato de almacenamiento.
Django password formatSpring Security password storage formatcrypt(5) sha512crypt formatApache htpasswd password formats
Usar como palabras clave format / storage / encoding facilita encontrarlo.
5.3 Si hay un texto plano conocido, cotéjelo realmente con el formato candidato
Si dispone de una cuenta de prueba o de un texto plano conocido, lo más rápido es calcular realmente con el formato candidato y comparar. En este caso, para un hash de contraseña es necesario extraer el salt y los rounds de la cadena y recalcular con ellos.
El patrón del procedimiento es el mismo en tres pasos, sea cual sea el formato.
- Extraer el salt y los parámetros de la cadena
- Recalcular con el mismo salt y los mismos parámetros sobre el texto plano conocido
- Comprobar si la cadena resultante coincide exactamente con la cadena original
Verifique un digest sin prefix
Empecemos por «un simple digest». Basta con la biblioteca estándar de Python 3.
# Python 3.8 o superior / solo biblioteca estándar
import base64
import hashlib
target = "5f4dcc3b5aa765d61d8327deb882cf99" # cadena que se quiere identificar
plain = b"password" # texto plano conocido
for name in ("md5", "sha1", "sha256", "sha512", "sha3_256", "blake2s"):
digest = hashlib.new(name, plain).digest()
if digest.hex() == target.lower():
print("coincidencia hex:", name)
if base64.b64encode(digest).decode() == target:
print("coincidencia base64:", name)
En este ejemplo se obtiene coincidencia hex: md5. La forma básica consiste en colocar dentro del for los formatos que aparecen como candidatos en la tabla de 2.2.
Cuando quiera probar el hash NT, terminará escribiendo algo como hashlib.new("md4", "password".encode("utf-16-le")), pero en un Python enlazado con la serie 3 de OpenSSL, el legacy provider está deshabilitado por defecto, así que puede aparecer unsupported hash type md4. Verifique esto de antemano en su propio entorno.
Verifique hashes de contraseña de la familia crypt
$1$ / $5$ / $6$ / $apr1$ se pueden recalcular pasando el salt a openssl passwd. Los ejemplos de la tabla de 2.1 también se pueden reproducir con este método.
# OpenSSL 3.x
openssl passwd -6 -salt N3v8Kx2Lq9Rt password
# $6$N3v8Kx2Lq9Rt$6LUcSUAELX3aC/.60pTB.TFLTQi1mOGRCwKqNCqtRSaXjorxj01HJ9oNni97Kci1uDt7a/Kn4t3OS20Dw/.vi1
openssl passwd -5 -salt N3v8Kx2Lq9Rt password # sha256crypt
openssl passwd -1 -salt vA7mQ9xZ password # md5crypt
openssl passwd -apr1 -salt vA7mQ9xZ password # Apache APR1-MD5
Si la salida coincide con el objeto de identificación, en ese momento quedan confirmados tanto el formato como el texto plano.
Si la cadena lleva rounds=, ese valor también debe pasarse. $6$rounds=5000$... es el valor predeterminado, así que da el mismo digest lo indique o no explícitamente, pero si el valor difiere del predeterminado, como rounds=100000, calcule siempre con ese valor.
En distribuciones de la familia Debian / Ubuntu, también se puede hacer lo mismo con mkpasswd, incluido en el paquete whois (con la forma mkpasswd -m sha512crypt -S N3v8Kx2Lq9Rt password).
Verifique bcrypt o Argon2
En bcrypt y Argon2 el salt está codificado con un alfabeto propio, así que en lugar de extraerlo a mano, es más seguro pasar la cadena completa al verify de la biblioteca.
# pip install "passlib[bcrypt]" argon2-cffi
from passlib.hash import argon2, bcrypt
samples = [
(bcrypt, "$2b$12$9YQ2u/e5Y/ArOnG.gJKxK.0makLATcYLP1q.Nsabzrw7XErYCfoYO"),
(argon2, "$argon2id$v=19$m=65536,t=3,p=4$MDEyMzQ1Njc4OWFiY2RlZg$uKZLaN6muIyoyIYr5waqw3y+zaDbe9aLSPj6Ln/rbz4"),
]
for handler, stored in samples:
# identify indica si es ese formato, verify indica si coincide con el texto plano
print(handler.name, handler.identify(stored), handler.verify("password", stored))
verify lee el cost, los rounds y el salt directamente de la cadena y recalcula por su cuenta, así que no hace falta escribir uno mismo la extracción de parámetros. En el ejemplo de bcrypt de arriba, como el texto plano es password, se devuelve True.
Cabe señalar que el módulo estándar crypt de Python fue marcado como obsoleto y se eliminó en Python 3.13. Si necesita tratar formatos de la familia crypt en la versión 3.13 o posterior, recurra a openssl passwd o a passlib.
5.4 Traduzca el formato candidato a los números de modo de hashcat o a los nombres de john
Cuando no se conoce el texto plano y se quiere trabajar del lado de la herramienta, hay que traducir el nombre del formato al identificador que usa la herramienta, no dejarlo en el nombre del formato. Como aquí es fácil quedarse atascado, se deja una tabla con los casos representativos.
| Aspecto | Formato | Modo de hashcat (-m) |
|---|---|---|
| 32 hex | MD5 | 0 |
| 32 hex (proveniente de AD) | Hash NT | 1000 |
| 40 hex | SHA-1 | 100 |
| 64 hex | SHA-256 | 1400 |
| 128 hex | SHA-512 | 1700 |
$1$... |
md5crypt | 500 |
$apr1$... |
Apache APR1-MD5 | 1600 |
$2a$ / $2b$ / $2y$ |
bcrypt | 3200 |
$5$... |
sha256crypt | 7400 |
$6$... |
sha512crypt | 1800 |
pbkdf2_sha256$... |
Django PBKDF2-HMAC-SHA256 | 10000 |
| Formato de almacenamiento de scrypt | scrypt | 8900 |
El número de modo aumenta con cada nueva versión, así que para formatos más recientes, como Argon2 o yescrypt, verifíquelo en la lista que muestra la ayuda de su propio hashcat.
En John the Ripper se especifica por nombre, no por un número. En la versión base (1.8.0) están disponibles descrypt, bsdicrypt, md5crypt, bcrypt, LM, AFS, tripcode, dummy y crypt; muchos de los demás se agregan en la versión jumbo. Si el nombre del formato que desea usar no está en la versión base, verifíquelo en la documentación de la versión jumbo.
Se repite: use las herramientas mencionadas aquí únicamente con su propio entorno o con entornos para los que cuenta con autorización para investigar.
5.5 Revise el código de la implementación o la configuración
Si el sistema investigado es propio, al final lo más seguro es revisar el código o la configuración.
- Biblioteca utilizada
- Configuración del framework
- Opciones usadas en la generación
- Método de codificación de la salida (hex / Base64 / Base64url / alfabeto crypt)
Revisando esto, casi siempre queda zanjada la cuestión.
5.6 Para el futuro, almacene con una etiqueta de formato
Si usted está en el lado de quien diseña de aquí en adelante, elegir un formato que incrusta el nombre del método en la cadena facilita bastante la migración futura.
- El PHC string format de Argon2
- El
{id}encodedPasswordde Spring Security - El
algo$iterations$salt$hashde Django - Un formato con prefijo de la familia Unix
crypt(3)
Si se hace así, quien lo revise después tendrá menos dudas. Al contrario, un diseño que solo coloca «un simple hexadecimal de 64 caracteres» en la base de datos no es amable con el uno mismo del futuro.
6. Resumen
Al identificar el formato a partir de la representación en cadena de un valor hash, conviene mirar en el siguiente orden.
- Si hay un prefix
- Cuál es el carácter separador
- Cuál es el conjunto de caracteres
- A cuántos bytes equivale la longitud
- Cuál es el contexto del origen de almacenamiento
Lo más importante son estos dos puntos.
- Los formatos de almacenamiento con prefijo son bastante fáciles de identificar
- Un hexadecimal o Base64 plano suele revelar solo un grupo de candidatos
Por eso, en la práctica el criterio queda así.
- Si es
$argon2id$...,$2b$...,$6$...,{SHA}...opbkdf2_sha256$..., se puede avanzar bastante solo con la cadena - Si solo hay un hexadecimal de
32 / 40 / 64 / 128dígitos, piense en «acotar candidatos» y no en confirmar - Si de verdad se necesita confirmar, llegue hasta el producto, la configuración y la implementación del origen de almacenamiento
Si se mira en este orden, la investigación se vuelve bastante más rápida. Al contrario, decidir de inmediato solo por la longitud hace tomar, silenciosamente, un camino más largo.
7. Servicios relacionados con este tema
Consultoría técnica y revisión de diseño
En la identificación del formato de hashes de contraseña que quedaron en una base de datos existente, en la migración de la infraestructura de autenticación o en la investigación de logs de sistemas mixtos Windows / Web, es necesario organizar no solo el aspecto de la cadena, sino también la implementación del origen de almacenamiento y la estrategia de migración. Revisar todo junto, desde la identificación del formato hasta el diseño de la migración, ayuda a reducir errores.
Investigación de fallos y análisis de causas
No es raro encontrarse con una investigación en la que «la verificación no avanza porque no se sabe qué es esta cadena». Separar en qué punto —logs, archivos de configuración, esquema de la base de datos o implementación de la aplicación— queda determinado el formato acelera bastante la identificación de la causa.
8. Referencias
- RFC 1321 - The MD5 Message-Digest Algorithm
- NIST FIPS 180-4 - Secure Hash Standard (SHA-1, SHA-2, SHA-512/224, SHA-512/256)
- NIST FIPS 202 - SHA-3 Standard: Permutation-Based Hash and Extendable-Output Functions
- PHC string format specification
- Argon2 reference implementation
- RFC 7693 - The BLAKE2 Cryptographic Hash and Message Authentication Code (MAC)
- BLAKE3 C README - default output length and extendable output
- crypt(5) - prefixes and hashed passphrase formats
- Apache HTTP Server 2.4 - Password Formats
- slappasswd(8) - RFC 2307 schemes such as {SHA} and {SSHA}
- Django documentation - example of
pbkdf2_sha256$... - Spring Security -
DelegatingPasswordEncoderstorage format{id}encodedPassword - MS-NLMP: NTLM v1 Authentication -
NTOWFv1(Passwd, User, UserDom) = MD4(UNICODE(Passwd)) - hashcat wiki - example hashes (lista de números de modo)
- John the Ripper - command line options (nombres utilizables con
--format=NAME) - passlib -
PasswordHashAPI (identifyyverify) - openssl-passwd(1) -
-1/-apr1/-5/-6y-salt
Artículos relacionados
Artículos recientes con las mismas etiquetas para profundizar en temas cercanos.
Qué hacer antes de desechar un PC con Windows ── Lista de comprobación práctica de eliminación de datos, desvinculación de cuentas y copias de seguridad
Qué hacer antes de desechar, ceder, vender o devolver en leasing un PC con Windows: copias de seguridad, eliminación de datos, BitLocker,...
Selección de la cuenta de un servicio de Windows — Cuándo usar LocalSystem, cuentas virtuales y gMSA
¿Todavía ejecuta sus servicios de Windows con LocalSystem? Compare permisos e identidad en red de las seis cuentas posibles y elija con p...
Auditoría de seguridad en Windows e investigación práctica del registro de eventos — cómo convertirse en un responsable de sistemas capaz de leer el 4625
Guía práctica para investigar fallos de inicio de sesión: directiva de auditoría básica y detallada, subcategorías mínimas, cómo leer 462...
Guía práctica de Windows LAPS — abandone la contraseña de administrador local común a todos los PC
La contraseña de administrador local común permite que un PC comprometido exponga a todos a Pass-the-Hash. Cubrimos la rotación automátic...
Guía práctica del almacén de certificados de Windows — ¿en el de usuario o en el de equipo?
¿En qué almacén debe colocarse un certificado de cliente, en el de usuario o en el del equipo? Esta guía repasa certmgr.msc y certlm.msc,...
Temas relacionados
Estas páginas sitúan el tema en un contexto más amplio de servicios y decisiones.
Temas técnicos de Windows
Portal sobre desarrollo de Windows, investigación de fallos y aprovechamiento de activos existentes.
Servicios relacionados con este tema
El artículo está directamente relacionado con los siguientes servicios.
Consultoría técnica y revisión de diseño
Sirve para distinguir logs, bases de datos, métodos de autenticación y formatos de almacenamiento de sistemas existentes, identificar el formato del hash y ordenar las decisiones de migración o investigación.
Preguntas frecuentes
Preguntas habituales en las consultas sobre el tema del artículo.
- ¿En qué orden conviene mirar una cadena hash para identificar su formato?
- Conviene seguir el orden prefix → carácter separador → tipo de carácter → longitud → contexto. Los formatos en los que los primeros caracteres tienen significado son fáciles de identificar: si empieza por $argon2id$ se puede sospechar fuertemente Argon2, $2b$ bcrypt, $5$ sha256crypt y $6$ sha512crypt. Por el contrario, un hexadecimal o Base64 plano sin prefix solo permite acotar candidatos, así que para confirmarlo hay que revisar finalmente el producto, el framework o la configuración de origen del almacenamiento.
- ¿Se puede afirmar que una cadena hexadecimal de 64 caracteres es SHA-256?
- Afirmarlo sin más es arriesgado. SHA-256 es un candidato fuerte, pero existen otros formatos con la misma salida de 32 bytes, como SHA3-256, SHA-512/256, BLAKE2s-256 o la salida predeterminada de BLAKE3, y la longitud por sí sola no permite distinguirlos. La longitud sirve para formar un grupo de candidatos, no para confirmar el formato. Si se necesita confirmación, hay que llegar hasta la especificación del origen de almacenamiento, el formato documentado oficialmente, el cotejo con un texto plano conocido y la revisión del código o la configuración de la implementación.
- ¿Una cadena que empieza por $6$ es un hash SHA-512?
- No. $6$ es el prefijo de sha512crypt, un formato de almacenamiento de contraseñas de tipo Unix; no es un digest hexadecimal de SHA-512 en sí, sino una cadena de hash de contraseña que incluye salt y rounds. De la misma manera, $5$ es sha256crypt y $1$ es md5crypt. En el momento en que aparece un prefijo, ya no se trata de un simple digest, y confundir esto desalinea la implementación de la migración o del código de verificación.
- ¿Qué se puede saber a partir del tipo de carácter?
- El tipo de carácter es una pista tan importante como la longitud. Si solo aparecen caracteres en el rango 0-9a-fA-F, se trata de una representación hexadecimal, y la mitad del número de caracteres es la longitud en bytes del valor original. Si aparecen + / =, hay que sospechar Base64 según RFC 4648; si aparecen - o _, Base64url. Si aparecen puntos y barras junto con separadores $, es más natural sospechar un alfabeto de la familia crypt, como bcrypt o sha512crypt, en lugar de un Base64 normal. Si se interpreta una cadena con puntos como un Base64 roto, se pueden pasar por alto los formatos de la familia crypt.
Perfil del autor
Página de presentación del autor del artículo.
Go Komura
Representante de KomuraSoft LLC
Especializado en desarrollo de software para Windows, consultoría técnica e investigación de fallos, sobre todo en proyectos con sistemas existentes y errores difíciles de reproducir.