En este artículo voy a explicar cómo preparé un ataque de diccionario dirigido al sistema de autenticación de routers, switches o dispositivos de red utilizando Python. Con este ataque se va a intentar averiguar los usuarios y contraseñas para acceder al panel de administrador de un dispositivo, utilizando archivos de texto con listas de usuarios y listas de contraseñas, es decir, es un ataque de diccionario.
Estos diccionarios se pueden crear manualmente, por medio de herramientas, o encontrar por Internet los ya creados. Hay diccionarios de todo tipo, desde listas generadas en GitHub, hasta diccionarios generados con passwords reales filtradas ordenadas por popularidad. En este caso, como idea, puedes buscar en la siguiente web: https://wiki.skullsecurity.org/Passwords
La mayoría de los routers vienen con usuarios por defecto y muchos de los dueños no suelen cambiar la contraseña que viene configurada por defecto. Es por esto por lo que se aplica este ataque fácilmente desde hace mucho tiempo - no solo con los routers -.
Una PoC de BruteForce en Python
He preparado un script en Python para realizar este ataque, que he probado solo en routers CISCO y Huawei. A continuación se puede ver el código, hay que tener en cuenta que esta versión va a recorrer ambos archivos en su totalidad, lo que puede ser lento si los archivos son extensos, al final mostraré un pequeño cambio para parar cuando encontremos la primera combinación exitosa.
Por supuesto, no es una herramienta profesional con multithreading y organización probabilística o que utilice un sistema de medición de latencias para acelerar o decelerar el número de peticiones en paralelo. Es solo una PoC para probar algo que no solo tiene que ver con las contraseñas por defectos, sino con las protecciones de número de intentos fallidos. Como se verá, no hay ninguna protección en la mayoría de los sistemas testeados contra los ataques de fuerza bruta, incluso sin son como éste.
Ahora voy a comentar un poco el código: lo primero que hacemos es importar los módulos que necesitamos (urllib.request, http.client, sys). He creado un par de funciones, que se explican por partes:
- Función get_realm: recibe un parámetro, que es la dirección IP del objetivo. Se encarga de realizar una petición GET al objetivo para conseguir el valor de la cabecera www-Authenticate, por ejemplo de la siguiente devolvería myRealm, si no se puede conseguir el valor, se acaba el script:
Se comprobará la respuesta, si se obtiene un código 200 es que todo fue bien, por lo que tenemos usuario y contraseña, y se muestra que fue correcto, en caso contrario el login no es válido y saltará una excepción en la siguiente línea:
- Main: Por último tenemos la parte main del script, donde se pregunta al usuario la dirección IP y los ficheros (que son abiertos, si algo va mal se informa y se sale del programa), y con esta información se llama a la función attack vista antes. Los archivos de texto que he usado aquí son pequeños y ambos contienen el mismo contenido, por ejemplo en la siguiente imagen se puede ver el de usuarios:
Si ejecutamos el código sobre un router de prueba que tiene cambiada la contraseña, tenemos la siguiente salida:
Ahora vamos a ejecutarlo contra un router en el que se encontrarán 2 combinaciones válidas, aquí esta la captura:
Existe una librería distinta a la usada aquí, que te permitirá también realizar conexiones HTTP de manera más sencilla: request. Por si no la conocías, puedes echarla un vistazo. Como comente antes, para que el script acabe en la primera combinación exitosa de usuario y contraseña, hay que hacer una pequeña modificación en la función attack, borrando la variable find y teniendo el siguiente código en el if que comprueba si el código de respuesta es 200:
Llega el momento de despedirse. Este solo es un ejercicio para los que estamos aprendiendo que he querido compartir. Por supuesto, no solo faltan los controles que he indicado al principio, sino que se podrían añadir fases de fingerprinting del dispositivo para probar solo las contraseñas de esos modelos, se podrían detectar la existencia de sistemas de autenticación con 2FA, detectar errores por límites de intentos y bloqueos de cuenta, o incluso si son vulnerables a algún exploit conocido que leakee usuarios. Cuanto más aprendas, más puedes ampliar estos ataques contra los sistemas de login. Puedes seguir aprendiendo a escribir scripts en Python que se encuentren destinados al hacking con dos libros que utilizo yo: Python para Pentesters y Hacking con Python. Hasta la próxima.
Autor: Josué Encinar García (@JosueEncinar). Ingeniero de Software, estudiante del Máster Universitario en Seguridad de Tecnologías de la Información y de las Comunicaciones en la Universidad Europea de Madrid. Analista de Seguridad en Accenture.
Figura 1: Cómo hacer tu primer ataque de diccionario a un router con Python |
Estos diccionarios se pueden crear manualmente, por medio de herramientas, o encontrar por Internet los ya creados. Hay diccionarios de todo tipo, desde listas generadas en GitHub, hasta diccionarios generados con passwords reales filtradas ordenadas por popularidad. En este caso, como idea, puedes buscar en la siguiente web: https://wiki.skullsecurity.org/Passwords
Figura 2: Passwords en Skullsecurity |
La mayoría de los routers vienen con usuarios por defecto y muchos de los dueños no suelen cambiar la contraseña que viene configurada por defecto. Es por esto por lo que se aplica este ataque fácilmente desde hace mucho tiempo - no solo con los routers -.
- Default Passwords: Adelante por favor
- Gracias por tu password, routerSin embargo, si se cambia las contraseña que viene por defecto, y se pone una compleja - de cierta longitud y combinación de números, letras minúsculas, mayúsculas y símbolos - entonces este mecanismo tendrá pocas probabilidades de éxito.
Una PoC de BruteForce en Python
He preparado un script en Python para realizar este ataque, que he probado solo en routers CISCO y Huawei. A continuación se puede ver el código, hay que tener en cuenta que esta versión va a recorrer ambos archivos en su totalidad, lo que puede ser lento si los archivos son extensos, al final mostraré un pequeño cambio para parar cuando encontremos la primera combinación exitosa.
Por supuesto, no es una herramienta profesional con multithreading y organización probabilística o que utilice un sistema de medición de latencias para acelerar o decelerar el número de peticiones en paralelo. Es solo una PoC para probar algo que no solo tiene que ver con las contraseñas por defectos, sino con las protecciones de número de intentos fallidos. Como se verá, no hay ninguna protección en la mayoría de los sistemas testeados contra los ataques de fuerza bruta, incluso sin son como éste.
Figura 3: Código de BF para la PoC en Python |
Ahora voy a comentar un poco el código: lo primero que hacemos es importar los módulos que necesitamos (urllib.request, http.client, sys). He creado un par de funciones, que se explican por partes:
- Función get_realm: recibe un parámetro, que es la dirección IP del objetivo. Se encarga de realizar una petición GET al objetivo para conseguir el valor de la cabecera www-Authenticate, por ejemplo de la siguiente devolvería myRealm, si no se puede conseguir el valor, se acaba el script:
WWW-Authenticate: Basic realm="myRealm"- Función attack: recibe 3 parámetros, la dirección IP del objetivo, y 2 ficheros (que son abiertos antes de pasarlo, por comodidad). Creo una variable booleana, para mostrar información al final si no se encuentra una combinación con éxito, llamo a la función get_realm y se va a recorrer los dos ficheros (usuario y contraseñas) con dos bucles for, para comprobar cada posible combinación. Dentro del bucle se van a crear las conexiones, para la autenticación pasamos los siguientes datos: Realm, IP, Usuario y Contraseña
Se comprobará la respuesta, si se obtiene un código 200 es que todo fue bien, por lo que tenemos usuario y contraseña, y se muestra que fue correcto, en caso contrario el login no es válido y saltará una excepción en la siguiente línea:
pag = ur.urlopen("http://" + str(ip))Entonces, se informa de que la combinación usuario y contraseña no es correcta.
- Main: Por último tenemos la parte main del script, donde se pregunta al usuario la dirección IP y los ficheros (que son abiertos, si algo va mal se informa y se sale del programa), y con esta información se llama a la función attack vista antes. Los archivos de texto que he usado aquí son pequeños y ambos contienen el mismo contenido, por ejemplo en la siguiente imagen se puede ver el de usuarios:
Figura 4: Ficheros users.txt |
Si ejecutamos el código sobre un router de prueba que tiene cambiada la contraseña, tenemos la siguiente salida:
Figura 5: Resultados de un router con las contraseñas por defecto cambiadas |
Ahora vamos a ejecutarlo contra un router en el que se encontrarán 2 combinaciones válidas, aquí esta la captura:
Figura 6: Router con dos aciertos de combinaciones |
Existe una librería distinta a la usada aquí, que te permitirá también realizar conexiones HTTP de manera más sencilla: request. Por si no la conocías, puedes echarla un vistazo. Como comente antes, para que el script acabe en la primera combinación exitosa de usuario y contraseña, hay que hacer una pequeña modificación en la función attack, borrando la variable find y teniendo el siguiente código en el if que comprueba si el código de respuesta es 200:
Figura 7: Comprobación de salida con éxito |
Llega el momento de despedirse. Este solo es un ejercicio para los que estamos aprendiendo que he querido compartir. Por supuesto, no solo faltan los controles que he indicado al principio, sino que se podrían añadir fases de fingerprinting del dispositivo para probar solo las contraseñas de esos modelos, se podrían detectar la existencia de sistemas de autenticación con 2FA, detectar errores por límites de intentos y bloqueos de cuenta, o incluso si son vulnerables a algún exploit conocido que leakee usuarios. Cuanto más aprendas, más puedes ampliar estos ataques contra los sistemas de login. Puedes seguir aprendiendo a escribir scripts en Python que se encuentren destinados al hacking con dos libros que utilizo yo: Python para Pentesters y Hacking con Python. Hasta la próxima.
Autor: Josué Encinar García (@JosueEncinar). Ingeniero de Software, estudiante del Máster Universitario en Seguridad de Tecnologías de la Información y de las Comunicaciones en la Universidad Europea de Madrid. Analista de Seguridad en Accenture.
Nice post
ResponderEliminarNo veo muy bien el código ya que (al menos desde el móvil) sale bastante borroso. Pero diría que con la librería requests se haría el código bastante más legible y más corto.
ResponderEliminarSi ya se que no está en la librería estandar... pero es que (bajo mi punto de vista) lo peor que tiene Python es: urllib, urllib2, httplib... son terrorificas. Creo que a todas les hace falta una capa para que el programador haga una petición de manera sencilla y que sea todo legible... y eso es requests (http para humanos)
Para muestra un botón:
https://gist.github.com/kennethreitz/973705
Dónde se puede descargar el script?
ResponderEliminarEste comentario ha sido eliminado por el autor.
ResponderEliminar