Existe un malentendido común de que el hash y el encriptación son lo mismo. No lo son. El hash es irreversible. Tomemos el siguiente ejemplo:
$ echo-n Password123 | md5sum
42f749ade7f9e195bf475f37a44cafcb-
Pasamos la cadena "Password123" al algoritmo MD5 (algo), que realiza las operaciones matemáticas y devuelve el hash codificado hexadecimal generado. La única forma de obtener el mismo valor de salida hash es introducir algo en bruto. Hay conflictos, pero podremos hablar más adelante.
La salida de la mayoría de los algoritmos de hash es una cadena binaria de longitud fija codificada hexadecimalmente. Otros, como este ejemplo, usan cadenas codificadas en base64 como salida. Tenga en cuenta que la longitud es siempre la misma:
{SHA} uNF8eZRJ8jmr8WTjyocRJPVpe7w =
{SHA} lqdu/Zr6o2dgIER8Up1/7lcUtgw =
{SHA} qYUOwLMlDEuukA5HCT4LR1kQzco =
{SHA} MXZBCpyWJ7TTs1w2kgGJslwNwTg =
{SHA} 2sAPLaUh9Mz0bI + XxKEg7qyABe8=
TL; Dr.
No quiero hablar demasiado de cifrado (porque esas cosas son para libros), pero es importante ser capaz de distinguir entre cadenas hash y cadenas cifradas. El cifrado generalmente rellena la cadena para cumplir con una longitud específica antes de que ocurra el cifrado. También requiere una clave (o contraseña) para descifrar. Si está usando una contraseña cifrada, la cadena cambiará dependiendo de la longitud de la entrada. Si ve un montón de contraseñas de texto cifrado, la longitud varía y es posible que esté tratando con cifrado en lugar de hash. AES-256-CBC Ejemplo Cadenas cifradas y texto simple asociado (la clave es "ASDF"):
foobar | U2FsdGVkX19G + KtytNHdj6yH2AVvX26pEmtunS/PRnU = foobarfoobar | U2FsdGVkX18sPpIvN6nVh68lOUCcb3gR2fKbCCnBxog = foobarfoobarfoobar | U2FsdGVkX1/EOnUt57TCW4Rh0EdNnWX + ldatuqv2xexeaeoww0xg/EXJUe9aSUz $ cat contraseñas_encriptadas U2FsdGVkX19G + KtytNHdj6yH2AVvX26pEmtunS/PRnU = U2FsdGVkX18sPpIvN6nVh68lOUCcb3gR2fKbCCnBxog = U2FsdGVkX1/EOnUt57TCW4Rh0EdNnWX + lDatuQv2xEXXeAeowW0XG/EXJUe9aSUz $ para i en `cat encrypted_passwords`; do echo $i | openssl enc -base64 -d -aes-256-cbc -pass pas:asdf; echo; hecho foobar foobarfoobar foobarfoobarfoobar
Ahora podrías pensar: podrías tener razón. Sin embargo, el hecho de que el material clave tenga acceso al sistema significa que esencialmente una contraseña maestra de texto simple se encuentra en algún lugar, ya sea como clave RSA o contraseña o contraseña en un archivo, incrustada en una base de datos, codificada en una aplicación o en algún lugar de la memoria. pfft, nadie ' va a usar asdf como clave para cifrar las contraseñas de sus usuarios '
Usando la misma cadena de MD5:
foobar | 3858f62230ac3c915f300c664312c63f foobarfoobar | 59faa421729e846dd800dce59943bfc0 foobarfoobarfoobar | 1352aadab322d1a033c27964be0965db
La contraseña hash está lejos de ser perfecta, de hecho es un poco mala, pero es peor que el cifrado por lo que intenta lograr. Los usuarios seleccionan el requisito mínimo absoluto con más frecuencia que no y también pueden usarlo en múltiples sitios. Muchos "hacks" no son en realidad más que ataques de reutilización de credenciales. Si el compromiso inicial es el uso de cifrado, entonces el único esfuerzo que el atacante debe hacer es encontrar la clave que descifra todas las contraseñas. Para los hash, al menos necesitan hacer un esfuerzo para descifrarlos. Cuando se utiliza con algoritmos modernos como sha512crypt, bcrypt, scrypt o argon2, los valores de hash pueden requerir un gran esfuerzo para descifrar.
Añadir sal es añadir una cadena a la contraseña antes de hash. La sal de cada hash debe ser única, generalmente seleccionada al azar, ya que el punto es hacer que el mismo valor de hash de texto claro "contraseña" tenga un valor diferente cada vez. Esto hace que la vida de los descifrados de contraseñas sea difícil, ya que para comprobar la palabra "contraseña" para cada usuario de 1.000 usuarios, cada usuario tiene una sal única, y tienen que hacer el trabajo 1.000 veces-una vez por usuario/sal. Esto también significa que no pueden usar un diccionario precompilado o una tabla arco iris de manera eficiente (por lo general...), ya que requieren un cada sal personalizado.
Los sitios web a veces arruinan esto y usan sal genérica para todos los usuarios; Esto va en contra del propósito.
El siguiente es el hash SHA1 con sal:
b353977827f67a4ae0318f3a9447fae1c13d9d90:b8d18ca |___________________________________________| hash | sal | separador
El texto claro de este hash es "contraseña". Su valor de sal es "b8d18ca" y se usa en la API de SHA1 ($salt.$pass). Esto significa que el algoritmo obtiene el texto claro de la contraseña, genera salt y lo agrega delante del texto claro. Cuando un sitio web o una aplicación intenta verificar su contraseña en el futuro, toma su contraseña de texto claro como entrada, lee el valor salt en el Hash almacenado, lo agrega delante de la contraseña que elija y compara el Hash generado con el Hash almacenado. Cracking Si no se sabe que parte de él es sal, el hash producirá el siguiente texto simple:
b8d18capassword
Dado que el algoritmo hace la entrada de texto simple, sal y los valores hash generados pueden permanecer transparentes para el usuario. Al hackear, si el algoritmo es sal, necesitamos conocer sal para que podamos proporcionarlo cuando se genera el candidato Plain Text.
Si se aplica adecuadamente, la salinación puede hacer que el agrietamiento sea más demorado. Con sales aleatorias, obligas a Cracker a perder tiempo tratando de descifrar valores hash que no coinciden con sales. Esto completa aproximadamente el esfuerzo requerido para la velocidad del dispositivo/número de sales, ya que necesitamos generar un candidato para cada sal. Si la sal es estática, entonces las operaciones matemáticas son las mismas... speed_of_device/1. Otra forma de ver esto:
nuestro GTX 980 cracks SHA1 ($salt.$pass) a 3576.8 MH/s o 3.5 mil millones candidatos por segundo Nuestra hashlist contiene 1000 únicas sales 3.500.000.000 / 1000 = 3.500.000 candidatos por segundo
Esto es tres órdenes de magnitud más lento, con una pérdida del 99,9%. Cuando se usa sal estática, se ve así:
Our GTX 980 cracks SHA1 ($salt.$pass) at 3576.8 MH/s o 3.5 mil millones candidatos por segundo Nuestra hashlist contiene 1 Sal única 3.500.000.000 / 1 = 3.500.000.000 candidatos por segundo
Si esto no tiene sentido, siga leyendo, tendremos un hermoso gráfico más adelante...
Otra mejora común en comparación con simplemente "hash this plaintext" es que "hash this plaintext, luego hash ese resultado, luego hash ese resultado" se repite miles de veces. Esto permite que el programa de descifrado de contraseñas haga miles de veces cuando intente una sola contraseña de candidato. Esto se llama iteración, bucle o costo variable. Algunos algoritmos de hash de contraseñas utilizan rondas de iteración codificadas; Otros Git. entonces hacerlo configurable dentro de una parte del Hash en sí. Por ejemplo, md5crypt () usa MD5, incluyendo salt, y hace exactamente 1000 bucles. sha512crypt () utiliza sha512, incluye una sal y bucle un número configurable de veces (por defecto 5.000).
Las iteraciones afectan principalmente el costo del ciclo de cálculo del algoritmo de hash, no su uso de memoria u otros factores. Estos también son ataques importantes al diseñar optimizados para resistir ciertos tipos de tipos de hash, pero esto es demasiado maleza para discutir aquí.
Veamos algunos ejemplos para demostrar el impacto de la elección del algoritmo de hash, ya sea salado, usando múltiples iteraciones, etc. Supongamos que un atacante ha recopilado 1.000 hash de usuarios de algún sitio web infectado y solo quiere realizar un simple ataque, probando cada hash de contraseña-143 millones de contraseñas candidatas.
El tipo de hash utilizado por un sitio web infectado tendrá un gran impacto en el tiempo necesario para que el atacante pase por este ataque. Este es un gráfico (relativo, aproximadamente) de cuántos segundos tardan en completar ese ataque, dependiendo del tipo de hash utilizado, donde las tarjetas gráficas estándar:
Pues eso no sirve! Los tipos de hash más fuertes son mucho más lentos, pero los tipos más rápidos son simplemente aplastados hasta que no hay nada. Intentemos de nuevo la misma escala de datos usando el tiempo del eje X logarítmico. A medida que las barras se mueven de izquierda a derecha, aumentarán la potencia de 10:
Así que algunos puntos principales son: Cuando quieres descifrar algunos hash de contraseña, una sola ronda es más fácil que múltiples rondas y sin sal que con sal. Por el contrario, cuando ciertas empresas o sitios web anuncian una violación de datos que contiene datos de usuarios, a) la contraseña preferiblemente ha sido hash, no solo texto simple; b) Están preferiblemente salados y no solo hash; c) Sería mejor que hubieran estado usando potentes hash de múltiples rondas saladas en lugar de solo una sola ronda.
Antes de intentar descifrar un hash de contraseña dado, corresponde al descifrador averiguar qué algoritmo de hash se utiliza para implementarlo. Identificar un tipo de hash suele ser simple, pero no siempre. Los Crackers a menudo hacen conjeturas fundamentadas basadas en pistas como la longitud de hash y el formato. Al final, la única manera de estar seguro de que la adivinación del tipo de hash es correcta es si el hash está descifrado o no.
Hay algunos excelentes recursos para esta tarea aquí y aquí, y ambos muestran cómo son los hash comunes.
El paquete "hash-identifier" (disponible aquí) está disponible en Kali Linux para ayudar a identificar tipos de hash desconocidos.
Un conflicto ocurre cuando dos entradas diferentes dan lugar a la misma salida hash. Esto es malo (obviamente). Para las contraseñas, esto podría significar que probablemente no haya descifrado su contraseña real, pero como he encontrado una entrada que produce el mismo valor hash, puedo usar el valor de texto simple para engañar al sistema para que piense que la contraseña es legítima.
Microsoft Office utiliza un algoritmo en su protección de documentos que ha sido propenso a conflictos durante años. No es raro encontrar múltiples conflictos para un solo hash, todos ellos desbloqueando el documento.
Una vez que se encuentra un conflicto, el algoritmo se rompe prácticamente. Si ocurre una vez, es estadísticamente probable que vuelva a ocurrir. Lo único que nos impide es el tiempo y la capacidad de procesamiento. A medida que los algoritmos se vuelven más robustos, generar algoritmos candidatos y comparar las salidas hash para buscarlos requiere más capacidad y tiempo. Como resultado, los diseñadores son cada vez más buenos para crear algoritmos que son menos propensos a conflictos.