Una vez que hemos repasado todos estos entresijos de la parte teórica del proceso de
"Salto de Canal" en las redes WiFi que vimos en la primera parte de este artículo, ya estamos preparados para crear una pequeña herramienta que realice ese trabajo, así que vamos a ver en esta parte cómo hacerlo. Comencemos con las problemáticas que hemos visto anteriormente una a una.
|
Figura 16: Hacking Wi-Fi: Cómo funciona el "Salto de Canal" (Parte 2 de 2) |
A la hora de hacer un sniffing, tenemos que poder “
escuchar” en todos los canales para poder capturar todos los paquetes que viajan por el aire, pero como esto no es posible, puesto que las interfaces inalámbricas tan solo pueden estar escuchando en un canal concreto en un momento determinado, lo que tenemos que hacer es ir cambiando de canal a intervalos reducidos de tiempo. De esta forma, aunque no estemos en todos los canales, virtualmente parecerá que sí.
También es importante recordar que la técnica de salto de canal no persigue capturar en sí todos los paquetes que viajan por el aire, más bien persigue el objetivo de localizar o detectar los dispositivos vivos que están trasmitiendo por el medio. Y, una vez localizados, centrarse en un objetivo concreto, es decir, realizar el
sniffing a un solo canal.
Por lo comentado hasta ahora, el tiempo que pasemos en un canal es muy importante, de ahora en adelante lo llamaremos “
timming”.
Es importante ser conscientes de que muchas estaciones o clientes no están continuamente transmitiendo. Por lo que debemos de utilizar un “
timming” lo suficientemente pequeño para barrer toda la banda de frecuencia, pero al mismo tiempo lo suficientemente grande para llegar a capturar los paquetes transmitidos. En las
PoCs que he creado he utilizado un “
timming” de
0.4 y
0.6. Pero es posible utilizar tiempos menores.
El solapamiento
A la hora de ir saltando de canal, lo más coherente como primera impresión, por sencillez, sería pensar en recorrer mediante un bucle todos los canales de formas secuencial. Es decir, recorrer los canales desde el
1 pasando por el
2, 3, 4... hasta recorrer los
14 canales. Sin embargo, esto no sería lo más eficiente. Como comentamos en los puntos anteriores, la banda de
2.4 Ghz tiene el inconveniente de los solapamientos entre canales - peor todavía si se utiliza el estándar
IEEE 802.11n que utiliza un ancho de banda de
40 Mhz -. El solapamiento provoca que sea posible capturar tráfico que pertenece a los otros canales contiguos. Esto no interesa.
Para evitar este problema se suele ir saltando, como mínimo, de tres en tres canales. Si se analiza el funcionamiento de
airodump-ng se puede corroborar que sigue un mecanismo basado en saltos no secuenciales.
|
Figura 17: Arrays de canales en airodump-ng |
En el
“header” de airodump-ng (
aquí el C) se pueden ver los
ARRAYs de las listas predefinidos con saltos de canales no secuenciales según el estándar utilizado. Está sería una de las formas correctas. Es posible, utilizando una imagen que muestre los solapamientos entre canales de los estándares
IEEE 802.11 bgna buscar otra serie de saltos sin solapamiento.
Canales comunes y no comunes
Otro de los problemas que podemos encontrarnos es que, según la región o el país, vamos a poder utilizar unos canales u otros, dependiendo de la interfaz que se utilice y de la configuración de la región. Por lo que al definir una lista con los canales debemos de tener en cuenta cuales son los canales comunes a todos los países y cuáles no.
Ordenarlos de forma que si un canal no común no se utiliza no rompa la eficiencia ante el solapamiento de la lista. Es decir, si tenemos la siguiente lista:
1, 14, 2. Y no utilizamos el canal
14. Al final se va a realizar el salto del canal 1 al 2 y esto no sería correcto al ser canales contiguos y solapables. Recordad que los canales comunes en todos los países van desde el
1 hasta el
11. El
12 y
13 se utilizan en la mayoría de países y el
14 solo en
Japón.
¿Qué canales?
Por el mismo problema que el caso anterior, es posible que no todos los canales funcionen al realizar el cambio de canal (aparezcan errores). Por lo que se estaría realizando saltos a canales no válidos. La solución más óptima, en mi opinión, sería comprobar antes de realizar el sniffing que canales son válidos y cuáles no.
¿Qué bandas?
Lo mismo que el caso anterior, pero en esta ocasión referente a las bandas de frecuencia y a los canales. También se podrá solucionar haciendo una comprobación previa.
Mi módulo, SaltoCanal
El objetivo que se persigue es crear un módulo independiente que pueda ser utilizado por otras herramientas de forma totalmente modular y abstracta. Que esté pensando para utilizar en una
Raspberry Pi con la interfaz inalámbrica que trae de serie bajo la distribución modificada de
Kali Linux. Como lenguaje de programación he decido utilizar
Python. Por diversos motivos. Entre ellos:
- Es el recomendado por los fundadores de la Raspberry Pi.
- Por ser un lenguaje de programación de alto nivel. Un lenguaje de sintaxis sencilla y clara.
- Es un lenguaje con gran documentación y herramientas.
- Es fácil de aprender. Cualquiera que no conozca el lenguaje pero que sepa programar puede comprender fácilmente el código. Por lo que facilita el aprendizaje a terceros.
- Es un lenguaje interpretado o de script, fuertemente tipado y dinámico, es multiplataforma y es orientado a objetos.
- Además, es un lenguaje bastante potente y con muchas librerías que nos ayudan a realizar casi cualquier cosa.
Otro de los motivos más importantes es que se integra muy bien con
Scapy. Librería que estoy utilizando para el desarrollo del proyecto que tengo entre manos. Aquí os dejo el
enlace a GitHub del código del script:
Este código está sujeto a cambios, no puedo decir que esté testeado a fondo. Por lo que seguro que habrá que corregir algunas cosas.
SaltoCanal
Utiliza los siguientes módulos:
- Thread de threading.
- Os.
- Sys.
- Popen, PIPE de subprocess.
- SIGINT, signal de signal.
- Sleep de time.
Y un
módulo propio, manejo_interfaz, para realizar ciertas operaciones que son
comunes sobre las interfaces inalámbricas. Las constantes que utiliza son dos listas de canales ordenadas mediante un sistema ideal para evitar el solapamiento:
- LISTA_CANALES_24GHZ = [1, 6, 11, 14, 2, 7, 3, 8, 4, 12, 9, 5, 10, 13]
- LISTA_CANALES_5GHZ = [36, 38, 40, 42, 44, 46, 52, 56, 58, 60, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165]
DN = open(os.devnull, 'w')
Esta constante se utilizará para descartar la salida cuando se invoque a
popen.
La clase SaltoCanal
El modulo es una clase que hereda de
threading.Thread. Sus métodos son:
Métodos públicos:
__init__: Para instanciar el objeto.
comprobar_canales: Para comprobar que canales podemos utilizar.
fijar_canal: Para fijar la interfaz en un canal concreto.
tiempo_canal: El “timming”, el tiempo que se utiliza un canal al realizar el salto de canal.
lista_VIC: Very Important Channel. Crea una lista con los canales más importantes para
el usuario.
fijar_canales: Para fijar los canales en una lista dada por el usuario.
pausar: Para pausar el hilo.
continuar: Para continuar con el hilo si está pausado.
terminar: Para finalizar el hilo.
run: Para ejecutar el hilo.
Métodos privados:
__get_pausar: Devuelve la variable pausa.
__lista_canales_valida: Para comprobar que los datos de entrada del __init__ son
correctos.
__comprobar_interfaz: Comprueba que existe la interfaz proporciona por el usuario y
que está se encuentra en modo MONITOR o RFMON.
__cambiar_canal: Método que cambia el canal de la interfaz mediante un proceso.
__comprobar_canales: Comprueba los canales válidos que se pueden utilizar y devuelve
una lista de ellos.
Pasemos ahora a detallar cada método.
__init__()
Como ya sabréis es un método reservado para instanciar los objetos de la clase (el constructor en Java). Por ejemplo, sc = SaltoCanal(“wlan1”). A este método solo es obligatorio pasarle la interfaz. Todas las demás variables son optativas.
- La variable espera se utiliza para indicar el tiempo de escucha en un canal concreto.
- La variable check se utiliza para realizar la comprobación de canales. Es decir, para verificar aquellos que funcionan y descartar los que no.
- Las variables _24Ghz y _5Ghz indican que listas de bandas de frecuencia se van a utilizar.
- Por último, verbose, para que la clase imprima por pantalla información al respecto.
Como el objetivo es utilizar esta clase desde otros scripts puede resultar más eficiente que sea mudo. Por lo que nos bastará por comprobar los códigos de salida para conocer el motivo. Dentro del método se verifican que los datos de entrada sean coherentes, es decir, que al menos se pase una de las bandas de frecuencia, esto se hace con el método privado: “__lista_canales_valida()”.
También comprobamos que la interfaz facilitada por el usuario es correcta o existe y está en modo monitor o RFMON. Para ello se llama al método privado “__comprobar_interfaz()” que a su vez utilizará otros métodos (existe_interfaz() y esta_modo_monitor()) utilizando un módulo externo que fue creado por mí y que tiene como nombre manejo_interfaz. Con ellos verificaremos que existe la interfaz y que está en modo monitor. Miraros este módulo para ver cómo se comprueban estas cosas.
Cabe resaltar que es aquí donde se inicializa el hilo (“Thread”) y que se crea como daemon. Que básicamente es para que el hilo principal pueda terminar sin esperar a nadie más. Se inicializan el resto de variables que utilizaremos para el correcto funcionamiento del hilo.
comprobar_canales()
Este método se utiliza para comprobar que canales se pueden utilizar y cuáles no. Por lo que devolverá una lista con los canales válidos. Este proceso solo se realiza si el check está a True. Para ello, utiliza el método privado “__comprobar_canales()”.
__comprobar_canales():
Este método recorre la lista de canales que se le pasan para verificar si son válidos. Utilizando el método “__cambiar_canal()” que devuelve True o False si existen algún error. En caso de no existir, se guarda en una lista el canal, en caso contrario, se descarta.
También comprueba si todos los canales han fallado, por lo que si esto ocurre el programa finaliza con un error, puesto que no existen canales válidos.
__cambiar_canal():
Este método recibe un canal y lanza un Popen. Un Popen es un módulo que nos permite lanzar programas externos y tener cierto control sobre ellos. Mediante la variable del módulo “stderr” comprobamos si existen errores.
Como se puede observar, estamos utilizando iw para realizar el cambio de canal, como comentamos anteriormente. La sintaxis sería: “iw dev self.interfazset channel canal”, siendo la variable interfaz la facilitada por el usuario, y canal el canal que queremos utilizar. No hay más magia en todo esto.
fijar_canal()
Este método permite fijar un canal en vez de andar saltando de canales. Solo funcionará si el hilo está parado.
tiempo_canal()
Este método permite cambiar el “timming”, el tiempo que pasaremos utilizando un canal.
fijar_canales()
Este método fija el salto de canales a una lista proporcionada por el usuario. Puede resultar útil cuando el usuario tan solo quiere realizar un sniffing a tan solo a una pequeña lista de canales concretos o fijar una lista de canales propia.
lista_VIC()
Very Important Channel. Este método me parece también muy interesante. Como comentamos en la teoría, existen canales más importantes que otros, como son el canal 1, 6 y 11 que no se solapan entre ellos, por lo que puede interesar pasar más tiempo en ellos porque podrían estar más poblados.
Bueno, en realidad, este es uno de sus usos, pero puede tener muchos dependiendo de la imaginación de cada uno. Al habilitar este método y proporcionarle una lista y un tiempo determinado, el hilo detectara los canales que pertenezcan a esta lista y esperara el tiempo facilitado por el usuario.
run()
Este es un método de la clase “Thread”. Una vez que se lance el hilo se ejecutará lo que está dentro de este método. En nuestro caso un bucle que recorre infinitamente una y otra vez toda la lista de canales, provocando el salto de canal.
sc = SaltoCanal(“wlan1”, check=True, _24Ghz = True, _5Ghz=True, verbose=True) sc.start()
PoC – Proof of Concept.
Una vez que tenemos creado nuestro “
bicho” es hora de comprobar que todo funciona correctamente. Para ello, ponemos la interfaz en modo monitor. En los ejemplos estoy utilizando una distribución de
Kali Linux un tanto peculiar. Esta distribución modificada, entre otras cosas, permite poner la interfaz
Wi-Fi que viene por defecto con la
Raspberry Pi 3 en modo monitor.
Hablaros sobre todo esto escapa del objetivo principal de este artículo. Para los interesados aquí os dejo ciertas referencias al
proyecto NexMon y la
URL donde podéis descargaros las
imágenes de Kali Linux modificada. Para poner la tarjeta de la Raspberry Pi en modo monitor tan solo tenemos que utilizar este comando:
monstart Para parar el modo monitor, bastaría con:
monstop
Como veis, todo muy sencillo, pero ¡ojo!, si se utilizan varias tarjetas inalámbricas, hay que cerciorarse bien cuál es la interfaz que está en modo monitor. Se puede hacer con
iwconfig o
iw dev
Una vez que se tiene la interfaz en modo monitor se puede comprobar que todo funciona correctamente utilizando un
sniffer. Existen varias posibilidades, yo me he decantado por
Wireshark por venir ya preinstalado, por ser un viejo conocido (aka
Ethereal) y por la interfaz gráfica, para que todo sea más visual en las capturas de pantalla.
Para realizar el
sniffing con Wir
eshark antes se debe de indicar la interfaz por la cual se quiere capturar tráfico. Es decir, la interfaz que esté en modo monitor. Si todo es correcto, irán apareciendo los paquetes capturados en
Wireshark.
Probando salto_canal.py.
Existen varias formas de lanzar este módulo. La primera forma es simplemente ejecutándolo directamente con
python saltocanal.py. Recordad que si utilizáis este método deberéis de crear en el “
main” algo como esto:
sc = SaltoCanal(“wlan1”)
sc.start()
raw_input('Presiona enter para finalizar...')
El
raw_input es fundamental, de lo conterario el programa y el hilo finalizaran y no se podrá testear. Pero si quieres también puedes probarlo ejecutándolo a través de la consola de
Python. Para ello se lanza la consola de
Python mediante un comando
python y desde allí de importa el módulo. (Para ello se aconseja lanzar la consola de
python en el mismo directorio que
salto_canal.py). Y se prueban los métodos. Como se aprecia en las siguientes capturas, todo parece funcionar correctamente.
|
Figura 19: Preobando el módulo de Salto de Canal en Python en una Raspberry Pi 3 |
Conclusiones:
Como hemos visto, crear un
script que realice el salto de canal no es complejo. Lo fundamental es conocer los problemas que pueden aparecer y buscarle soluciones óptimas. Esto solo es posible analizando y estudiando el funcionamiento de las cosas. Gracias al
Open Software existen multitud de herramientas de código abierto que pueden ayudarnos en este proceso.
A la hora de auditar una red
WLAN puede que las herramientas más conocidas no nos sirvan. Bien por ser algo muy concreto y especifico o porque necesitamos automatizar el proceso. Crear nuestras propias herramientas nos facilitará muchísimo las cosas, además de permitirnos tener un mayor control de lo que estamos haciendo.
Crear herramientas modulares y abstractas nos facilitarán la reutilización de las mismas en casi cualquier escenario. Incluso pueden darnos nuevas ideas. Una vez solucionado el problema del salto de canal, ya se puede empezar a jugar con:
python + scapy + dot11 y dejar volar nuestra imaginación. ¡¡happy hacking!!.
Si tenéis cualquier inquietud no dudéis en poneros en contacto conmigo.
Autor: Enrique Andrade - NETTinG