Desarrolla tus propias herramientas: “bruteforce”


Desarrollar una herramienta para ataques de fuerza bruta en Python, mediante un algoritmo recursivo.

1. Responsabilidad

El autor declina toda responsabilidad sobre cualquier uso de la información presentada en el mismo.

2. Introducción

En el presente artículo mostraremos cómo desarrollar una simple herramienta de fuerza bruta en el lenguaje de programación: python.
Lo llevaremos a cabo paso por paso, incluyendo el código generado en cada etapa. En nuestro ejemplo afrontaremos la rotura de un algoritmo de resumen (hash) md5.
Entre los objetivos del texto, se encuentran (aunque no exclusivamente):

  • Animar al lector a desarrollar sus propias herramientas: aunque a veces, existan otras que podamos aplicar, esto no siempre es así; Además, ganamos en flexibilidad.
  • Entender un algoritmo recursivo simple: aunque no se trata de un texto sobre programación, dado que utilizar un algoritmo recursivo es un método sencillo para resolver este problema (aunque no necesariamente el más óptimo), aprovechamos para utilizarlo de manera que el lector pueda ver su funcionamiento en un lenguaje como python.
  • Pasar un buen rato 🙂

3. Aclaración

Qué no pretende este artículo:

  • No, no es un texto dedicado a la programación, ni al estilo programando (para eso existen otros textos). Así que si crees que se puede hacer mejor o más limpio, cualquiera de los pasos, te animo a ello.
  • Sí, existen herramientas que ya hacen lo que este ejemplo y quizá sean más eficientes (aunque aquellas, no las hemos diseñado nosotros por lo que adaptarlas a nuestras necesidades, puede ser complicado).

4. Prerequisitos

Se presuponen unos conocimientos mínimos de programación. Al menos, entender las condiciones lógicas, bucles, etc. Nociones sobre el lenguaje python, son recomendables, si bien, no debería ser complicado para el lector, poder adaptar el código a cualquier otro lenguaje con el que se sienta más cómodo, si lo considera necesario.

5. Primeros pasos, definición del algoritmo a crear

Intentaremos plasmar, en lenguaje natural, el objetivo del algoritmo a crear:
Se trata de un programa que podamos usar para atacar por fuerza bruta una contraseña, en nuestro ejemplo, utilizaremos un md5 sin sal (“salt”).
Dada una serie de caracteres debemos ir probando uno a uno y las combinaciones posibles hasta un límite (anchura de palabra) establecido.
Por ejemplo, suponiendo que el rango empezase en la letra “a”, sería algo similar a:
a, b, c, d…
aa, ab, ac…

Decidimos, para nuestro trabajo, limitar la lista de caracteres a aquellos comprendidos entre el carácter ascii(32) y el ascii(127). Obviamente, el lector podrá probar cambiando el rango, por ejemplo limitándolo a letras, números y caracteres especiales comúnmente utilizados, sólo alfanuméricos, etc.

Enfoque recursivo

Pensamos en la siguiente manera de afrontarlo: partiendo de la cadena vacía (‘’) combinamos esa cadena vacía con cada uno de los caracteres del rango. Comprobamos si esa palabra es la que buscamos y, en caso contrario, ejecutamos el mismo proceso pero ahora partiendo con nuestra nueva palabra en lugar de vacío. En caso de que nuestro proceso intente comprobar una palabra con un ancho mayor al límite establecido, terminaremos.
Esta definición recursiva, se puede expresar de la siguiente manera:
Caso Base:

  • Si ancho de palabra es mayor que el límite => termina

Caso Recursivo:Para cada carácter dentro del rango definido:

  • nuevaBase = base + carácter
  • verifica(nuevaBase) Si no es correcto:
    • combina(nuevaBase, ancho + 1)

Para simplificar, de momento dejaremos como algoritmo para verificar (check) el código necesario para imprimir la cadena a probar (así podemos comprobar que se está ejecutando correctamente). Nuestro algoritmo recursivo se llamará combineChars y lo llamaremos, para comenzar con una cadena vacía y un límite de 2 caracteres:

Si lo ejecutamos veremos que obtenemos la lista de cadenas a probar:

El siguiente paso que queremos dar es mejorar nuestro sistema de chequeo, lógicamente este procedimiento dependerá del objetivo (podría tratarse de una petición web que analizaríamos para comprobar un ataque de inyección ciega (SQL, XPath…), ataque por fuerza bruta a un md5 o a un campo contraseña, etc).
Como comentamos al principio, en nuestro ejemplo usamos un md5 sin “salt”.

Añadimos la cadena objetivo y, también, para evitar que el algoritmo continúe verificando otras ramas, cuando ya haya encontrado la palabra a buscar, ejecutamos un sys.exit() (que aunque no es lo más limpio, para nuestro ejemplo sobra. El lector podrá adaptarlo a sus necesidades fácilmente si requiere que no pare la ejecución).
El código queda de la siguiente manera:

Lo ejecutamos con como límite 3 caracteres y obtenemos el siguiente resultado (en esta ocasión, lógicamente, tardará más):

Como retoques finales, eliminamos el texto de la prueba que estamos realizando (para limitar el tiempo perdido), y añadimos una comprobación del tiempo utilizado.
El código resultante es el siguiente:

En nuestra prueba (3 caracteres), obtenemos:

Podemos realizar distintas pruebas para obtener los tiempos requeridos. Por ejemplo, repetimos la prueba con un hash de una palabra de 4 caracteres (“hola”) y un límite de 4; Obtenemos:

Para finalizar, animamos al lector a crear variaciones sobre el código:

  • Cambiar el algoritmo de chequeo (check) por otro (sha, petición web a página de autenticación, SQL-i…)
  • Mejorar el código eliminando las salidas mediante sys.exit y el estilo de programación.

7. Sobre el Autor

Jesús Arnáiz es Consultor de Seguridad en Chase The Sun S.L., entre otros ha trabajado en proyectos de auditoría y consultoría de seguridad, pruebas e intrusión/hacking ético, análisis forense y cumplimiento normativo.
Para contactar con el autor, escribe a: jesus.arnaiz[ARROBA]chasethesun.es.
¿Quieres mantenerte informado sobre nuevas publicaciones como ésta?, Síguenos en Twitter:

 

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

*