Detección de orígenes de tráfico con Scapy – Parte 1

¡Buenas a todos y cuánto tiempo! Hoy vengo a traeros una entrada bastante sencillota acerca de detección de orígenes de tráfico. Lo haremos utilizando Scapy, aprovechando que bien se ha encargado Nebu de introduciros en los conceptos básicos y no tan básicos en entradas anteriores: parte 1, parte 2.

A grandes rasgos, lo que haremos será utilizar Scapy para crear un sniffer muy, muy básico y que se quedará a la escucha en una interfaz de red. Esto podremos invocarlo de múltiples maneras: desde la consola  en cualquier momento, en un script de arranque en el init, desde /etc/network/interfaces al arranque de una interfaz… Intentaremos hacer el script de la forma más agnóstica posible para que pueda ser invocado desde cualquier sitio.

Los orígenes que establezcamos para la detección pueden ser prácticamente cualquier cosa. En nuestro caso, ya que nos gusta mucho el tema, elegiremos una lista actualizada con las IPs de los nodos de salida TOR conocidos. Esto tiene múltiples aplicaciones, siendo la principal detectar tráfico proveniente de TOR para evitar potenciales ataques (¡que no tiene por qué!). Simplemente guardaremos la lista (que podéis encontrar aquí), y por simplificar eliminaremos la cabecera explicativa (nos ahorramos ignorarlas en la lectura).

Entramos ya en materia. Lo primero será definir la función principal del script, que abrirá la lista de direcciones origen y realizará un recorrido por el mismo guardando las direcciones de su interior en una lista.

Acto seguido, ejecutaremos la función sniff de Scapy y le diremos que comience a leer el tráfico de la interfaz eth0 (puede ser cualquiera),  y que solamente inspeccione el tráfico TCP. La razón de esto, en nuestro ejemplo, es que la red TOR solamente soporta TCP como protocolo de transporte (sin contar DNS). Dependiendo de las direcciones que queramos detectar, podemos jugar con este filtro e incluso dejarlo vacío. Por último, en el campo prn de la función introduciremos la función que queramos ejecutar sobre cada uno de los paquetes inspeccionados, que en nuestro caso será react.

Aquí entra en juego algo un poco más complejo y con lo que tendremos que jugar. Para explicaros primero os pongo aquí la definición de la función react:

Como veis, la función no ejecuta directamente su funcionalidad, que es la de buscar dentro de la lista la IP origen/destino del paquete que hemos inspeccionado, y de estar en dicha lista, imprimir que se ha detectado el tráfico. En su lugar, define una función read_pkt(pkt) que recibe el propio paquete como argumento.

La razón de esto es que el parámetro prn del método sniff debe recibir una función. Por tanto, debemos escribir react en forma de referencia a dicha función, y no react(), dado que esto lo que haría es invocar a la funcion y devolver algo (o nada en este caso), de manera que este algo o nada sería lo que recibe sniff. Por tanto, no podríamos introducir como argumento de react la lista de direcciones que hemos leído.

Una de las formas de resolver esto es leer desde la misma función react el fichero con la lista, pero esto conllevaría un gasto computacional demasiado grande, dado que por cada paquete inspeccionado tendríamos que abrir, leer y cerrar el fichero.

La otra solución es la quusamos: dentro de react definimos una función read_pkt, al cual le pasamos el paquete como argumento. Tras esto, react devuelve la referencia a esta función a sniff, parámetro incluido, y ésta la ejecuta. De esta forma hemos solucionado el problema de poder pasar la lista de direcciones como argumento.

¡Y ya tenemos el script! Podemos invocarlo desde la misma línea de comandos (como root, necesario para inspeccionar la interfaz de red). Empecemos con las pruebas.

Utilizando también scapy, forjaremos un paquete cuyo origen sea nuestra dirección IP y un puerto TCP cualquiera, y cuyo destino sea una de las IPs de la lista de nodos salida de TOR.

Se han detectado correctamente tres paquetes. ¿Por qué tres? Podemos verlo fácilmente utilizando Wireshark para ver lo que ha pasado si hemos capturado lo ocurrido por ejemplo con tcpdump.

Como se ve, se ha enviado un paquete de nuestra IP al nodo salida como apertura de un handshake TCP (SYN). Éste ha confirmado la recepción del mismo, realizando el siguiente paso del handshake (SYN/ACK). Sin embargo, dado que hemos terminado de enviar paquetes, le contestamos a esta confirmación con un RST terminando la conexión.

La siguiente prueba será justo la contraria. Desde otro host de la red utilizaremos scapy simulando que somos el nodo salida, y esperaremos la respuesta.

En este caso vemos solamente dos paquetes. Veamos por qué, de nuevo, en Wireshark:

El primer paquete se recibe correctamente, con la flag SYN como intento de conexión. La respuesta, dado que el puerto no está abierto, es un RST/ACK, indicando que allí no se puede acceder.

Y esto es todo por hoy, compañeros. Espero que os haya gustado y os sirva para aprender. Un saludo!!