Uno de los mecanismos de autenticación más utilizados son las contraseñas. Aunque es importante recordar que una contraseña no está cifrada en el sentido estricto de la palabra. Pero una vez que se “cifra” es imposible descifrarla, ya que el proceso se lleva a cabo a través de una función de un solo sentido o hash.
Linux, por ejemplo, utiliza MD5 para cifrar las contraseñas almacenadas en /etc/passwd. Cuando es necesario autenticar a un usuario, la clave que se introduce se cifra y el resultado se compara con lo que se encuentra almacenado, si coincide la autenticación tiene éxito, en caso contrario se despliega un mensaje de error.
El ataque más común sobre las contraseñas es el de fuerza bruta y una variante de éste, el ataque por diccionario. El primero consiste en probar todos los caracteres que pueden constituir una clave de acceso. El segundo se basa en reunir todas las posibles contraseñas en un archivo y probar cada una de ellas.
De los dos, este último tipo de ataque es más eficiente, pero menos preciso. Aunque en ambos casos es necesario cifrar todas las posibles contraseñas y comparar el resultado contra lo almacenado en el archivo. Esto se tiene que hacer cada vez que se desee romper una clave.
Una alternativa consiste en calcular todos los valores hash generados al momento de cifrar las posibles contraseñas y almacenarlos en una tabla. Una vez construida ésta, un atacante sólo tendría que consultarla para encontrar la contraseña asociada a una función de un solo sentido.
Esta opción fue propuesta, por primera vez, en el artículo A Cryptanalytic Time Memory Trade-Off, publicado por Martin Hellman en 1980. En 1982 Rivest mejoró la técnica anterior introduciendo el concepto de puntos distinguidos. Y en el 2003 Philippe Oechslin propuso otra optimización basada en lo que se conoce como función de reducción.
Sin embargo, hay dos puntos a considerar cuando se habla de generar todos los hash de un conjunto de caracteres. El primero es el tiempo que tomara hacer el cálculo, aunque con los procesadores de hoy en día y si se distribuye la tarea en varias computadoras, esto no es un serio problema.
El otro punto a considerar es el espacio necesario para almacenar toda la información generada. Hay que considerar que se requieren archivar todos los hashes y todas las combinaciones que produjeron estos, lo cual podría representar teras y teras de espacio en disco.
El juego de optimizar
Una opción para reducir el espacio requerido es no almacenar todas las posibles combinaciones y su correspondiente hash, sino sólo algunas de ellas. Pero se deben almacenar de tal forma que se pueda deducir las que no están almacenadas a partir de las que si lo están. Esto se logra generando cadenas de hash a partir de funciones de reducción.
Una función de reducción toma un hash como entrada y lo mapea a una contraseña. Se puede elegir cualquier función, siempre y cuando cumpla con lo anterior. Por ejemplo, en el caso de la contraseña “hola”, el resultado de aplicarle MD5 es 4d186321c1a7f0f354b297e8914ab240, una función de reducción toma este último valor como entrada y produce otro, quizá: 777005.
La generación de una cadena hash empieza calculando el hash de una contraseña elegida. El valor calculado pasa a la función de reducción y la clave de acceso obtenida se cifra para tener un nuevo hash, el cual pasa, otra vez, a la función de reducción.
Esto se repite varias veces, generalmente unas 10,000 veces. Al final se desecha toda la cadena con excepción de la primera contraseña y el último hash calculado, los cuales son almacenados dentro de una tabla. De esta forma una cadena que contiene miles de funciones de un solo sentido, se representa en un texto y un hash. Al final la tabla contara con entradas parecidas a lo siguiente:
|
Contraseña inicial cadena
|
Ultimo hash calculado
|
|
aeiouxyz
|
b54ef7e50cc945e8b33dd26b19e5be3b
|
|
9h8a7e4r
|
67862fbc5b1bce2e37e3b8daea42096c
|
|
cachafas
|
14f80f35ff534c14f5d406aceb96680a
|
|
:
|
:
|
|
77toto99
|
e803ffd00a2f275ffe393f184640c079
|
Cuando es necesario conocer la contraseña asociada a un determinado hash se procede de la siguiente forma: se busca la función de un solo sentido en la tabla generada, y si no aparece, se aplica la función de reducción al hash y se cifra su resultado. Esto último se repite hasta que el hash aparece en la tabla.
Una vez encontrada, se conoce la cadena que cuenta con la contraseña que produjo el hash. Todo lo que resta por hacer es volver a generar dicha cadena y almacenar la clave de acceso cuando ésta surja durante el proceso de generación.
Las dos implementaciones más importantes del trabajo de Oeschslin son: el proyecto RainbowCrack y la herramienta Ophcrack. El primero se encuentra documentado en la página: http://www.antsight.com/zsl/rainbowcrack, en la que es posible encontrar ejemplos de tablas generadas para diferentes algoritmos de cifrado de contraseñas, (LanManager con diferentes conjuntos de caracteres, MD5, etc) y con diferentes conjuntos de caracteres, así como software para generar las tablas y usarlas.
Mientras que la herramienta Ophcrack se puede encontrar en la página de SourceForge (http://ophcrack.sourceforge.net/es.index.php), ésta incluye una interfaz gráfica GTK+ y corre bajo Windows, Mac OS X (CPU Intel) y también en Linux. Sin embargo no cuenta con el generador de tablas y requiere un espacio mínimo de 9Gb en disco.
En la misma pagina se encuentra un CD live que, de acuerdo a lo documentado en el sitio Web, contiene un sistema Linux completo (SLAX), ophcrack para Linux y las tablas Rainbow para contraseñas alfanuméricas.
No obstante, conviene recordar que este método funciona siempre y cuando se puedan generar todas las posibles claves. Esto no es valido para los sistemas que utilizan un “salto” al calcular la función de un solo sentido de las contraseñas. El salto es un parámetro adicional para calcular el hash, el cual se almacena junto con este último para autenticar después al usuario. Ya que el salto no se conoce hasta la verificación de la contraseña, no es posible generar una tabla que incluya este factor.
Las rainbow tables son una herramienta rápida para obtener contraseñas a partir de valores hash, pero sólo funcionan en claves calculadas sin saltos. De manera que es importante tomar en cuenta esto y no usar este tipo de contraseñas o reforzarlas con una autenticación de dos o tres factores, que incluya otros mecanismos como biométricos o tokens.
Roberto Gómez es ingeniero en sistemas electrónicos con maestría en sistemas computacionales por el ITESM; doctor en ciencias computacionales por la Universidad de París; profesor-investigador y asesor de tesis a nivel licenciatura y maestría en el TEC y consultor de seguridad computacional. rogomez@itesm.mx |