08 abril 2007

Crackeando ficheros ZIP

A raíz del último post, me he preguntado cuanto tiempo se tardaría en descubrir claves usando "fuerza bruta" en el caso de que hubiera además que acceder a un fichero que contenga la información encriptada. Un caso típico sería el de intentar descubrir la contraseña de un fichero Zip.

Como era de esperar, los resultados en un caso "normal" no son tan favorecedores para el "atacante" como los que aparecían en el Blog original. En mi caso, un Zip con una contraseña de 3 letras ha tardado más de 10 minutos en encontrarla.

Ha sido un ataque "poco eficiente". En concreto, he usado un programa muy simple y que accedía continuamente a un descompresor externo. En estas circunstancias, ha tardado 11 minutos y 42 segundos en probar 10.159 contraseñas de tres letras. Eso quiere decir que era capaz de probar "sólo" 14,5 contraseñas por segundo (como curiosidad, esos son tiempos medidos en Windows; este mismo fuente compilado bajo Linux, y funcionando en circunstancias similares era capaz de probar 125,3 contraseñas por segundo, casi 9 veces más rápido).

Entonces, saquemos cuentas para claves formadas sólo por letras minúsculas (26) o por cualquier carácter ASCII imprimible de 7 bits (95 símbolos, aunque muchos compresores permiten también usar contraseñas con caracteres extendidos).

Longitud de la contraseña
Cualquier ASCII imprimible
Sólo minúsculas
1 carácter
2 caracteres
3 caracteres
4 caracteres
5 caracteres
6,55 segundos
10,37 minutos
16,42 horas
65,01 días
16,92 años
1,79 segundos
46,62 segundos
20,20 minutos
8,75 horas
9,48 días

Como se ve, en ataques tan simples, una contraseña de 5 símbolos no alfabéticos para un fichero ZIP ya daría una seguridad razonable. Pero sólo contra ataques así de simples.

¿Mejoras posibles? Innumerables, claro. Pero se puede hacer que sea MUCHO más rápido apenas con tres cambios:
  • No usar un descompresor externo, sino una rutina de descompresión que sea parte de nuestro fuente, con lo que se evita la carga debida a la llamada a un programa externo.
  • Si tenemos los datos en memoria, en vez de leer el fichero para cada prueba, también se ganaría mucha velocidad.
  • No escribir en pantalla cada clave que se prueba, y menos todavía usando el modo de consola de Windows.

Queda como reto para quien se atreva con ello... ;-)


Por cierto, el fuente de prueba, para los curiosos, era simplemente así (C estándar, usando un descompresor que usa el parámetro -s para indicar la contraseña y -o para sobreescribir resultados en vez de pedir confirmación si el fichero ya existe):


#include <stdio.h>
#include <stdlib.h>

int main() {
int resultado;
long contador = 0;
char clave[4]="aaa";
char orden[200];
char a,b,c;

for (a='a'; a<='z'; a++)
for (b='a'; b<='z'; b++)
for (c='a'; c<='z'; c++) {
clave[0] = a;
clave[1] = b;
clave[2] = c;
printf("Probando: %s...\n", clave);
sprintf(orden, "unzip -s%s -o 1.zip", clave);
resultado=system(orden);
contador++;
if (resultado == 0) {
printf("\n\nEncontrada. Es: %s\n", clave);
printf("Claves intentadas: %ld\n", contador);
return 0;
}
}
printf("Clave no encontrada!");
return 1;
}