AIRE (I) – Introducción y recogida de datos mediante sonda

Buenas a todos! Hacía tiempo que quería hablar de un proyecto en el que estuve trabajando como trabajo de fin de máster el año pasado junto a mi compañero Javier (perfil de github) y gracias a nuestro tutor Pablo González (@pablogonzalezpe). Después de un tiempo y de estarlo revisando, tenemos planificado liberarlo dentro de poco y nada a falta de algunos detalles. ¿Y hay mejor lugar para hablar de ello que la madriguera? 🙂

El proyecto, inicialmente titulado Air Profiling: Perfilado de un dispositivo a través de los paquetes de red, trata de demostrar dos hechos. El primero es la facilidad con la que puede obtenerse información relevante e identificativa de un usuario de tecnologías móviles. Podrán extraerse datos acerca de las aplicaciones y servicios utilizados, información acerca del propio dispositivo e incluso algunos de los intereses del usuario.

El segundo es que, a pesar de los esfuerzos de los desarrolladores por proteger la privacidad de la información del usuario, siempre podrá extraerse una cierta cantidad de información acerca de la misma una vez obtenido el tráfico de red del dispositivo.

El resultado de unos meses de trabajo fue una solución a modo de prueba de concepto que llamamos AIRE: Automated Inspection and Recognition Engine (porque somos así de chulos). La intención fue crear un sistema completo capaz de capturar el tráfico del dispositivo mediante una red inalámbrica, extraer datos del mismo, analizarlos y mostrarlos de forma gráfica e intuitiva.

El fin último es poder realizar un perfilado del dispositivo y de los patrones de comportamiento de la persona que se ubica detrás del teléfono móvil.

Sin más dilación, pongámonos manos a la obra 🙂

UPDATE: He publicado en mi GitHub todos los ficheros de configuración que utilizo más abajo para facilitar el copypasteo 🙂

https://github.com/hartek/AIRE-Probe

UPDATE2: Aquí la segunda parte!!

AIRE (II) – Instalación y uso del sistema de análisis

Fase 1: Extracción y almacenamiento

La primera fase del proyecto consistió en desarrollar una herramienta que permita falsear un punto de acceso WiFi público y almacene de forma independiente cada una de las sesiones completas de tráfico de los dispositivos conectados al mismo.

Como solución, montamos una Raspberry Pi 3 con un punto de acceso creado con adaptador de red inalámbrica USB (en concreto éste) y que recogerá las sesiones completas de tráfico. Procedo ahora a describir el proceso completo para poder montar este sistema por vosotros mismos y que podáis ver cómo funciona 🙂

Instalación previa de software

El primer paso será la instalación del software hostapd, que podemos realizar desde los mismos repositorios del sistema como administrador. Además, instalaremos el paquete isc-dhcp-server, que nos permitirá levantar un servicio DHCP. De este modo la asignación de direcciones IP a los dispositivos conectados, como hemos comentado, será independiente.

sudo apt install hostapd isc-dhcp-server

Instalación de hostapd y isc-dhcp-server en la Raspberry

Configuración del servicio DHCP

Lo primero a la hora de configurar el servicio DHCP en nuestra sonda será editar el fichero /etc/dhcp/dhcpd.conf. Este fichero contiene la configuración del daemon que maneja el servicio DHCP.

Estos son los cambios a realizar dentro del fichero:

  • Debemos comentar las líneas correspondientes a domain-name y option domain-name-servers. No necesitamos tener un nombre de dominio o asignar otros.
  • Quitamos el comentario de la línea correspondiente a authoritative. De esta forma, declaramos que somos el servidor DHCP principal de este segmento de red.
  • Agregamos por último las siguientes líneas, de manera que establecemos la propia configuración del servicio:
subnet 11.0.0.0 netmask 255.255.255.0 {
    range 11.0.0.10 11.0.0.20;
    option broadcast-address 11.0.0.255;
    option routers 11.0.0.1;
    default-lease-time 600;
    max-lease-time 7200;
    option domain-name "local";
    option domain-name-servers 8.8.8.8
}
Configuración del servicio DHCP (1)
Configuración del servicio DHCP (2)

De esta forma, estamos configurando estos elementos:

  • Rango IP (range): El rango de direcciones IP en el que realizará el servidor las asignaciones. En nuestro caso repartiremos direcciones IP en el rango 0.0.10-11.0.0.20, un total de 11 direcciones.
  • Dirección de broadcast (option broadcast-address): La dirección de broadcast de la red, en nuestro caso 11.0.0.255, siguiendo la nomenclatura usual.
  • Puerta de enlace predeterminada (option routers): La puerta de enlace de la red, es decir, hacia dónde se dirigirá el tráfico con objetivo el exterior.
  • Tiempo estándar de asignación de direcciones (default-lease-time): Tiempo que tiene reservada el servidor una dirección IP para un cliente. Se usa si no lo especifica el cliente. Lo establecemos a 600 segundos.
  • Tiempo máximo de asignación de direcciones (max-lease-time): Similar al anterior, pero establece el tiempo máximo de reserva, independientemente de la petición del cliente. Lo establecemos en 7200 segundos.
  • Nombre del dominio (option domain-name): Nombre de dominio del servidor DHCP, simplemente el nombre del host. Simplemente introducimos local.
  • Servidores DNS (option domain-name-servers): Servidor DNS al que redirigir las peticiones de resolución de nombres. Queremos no depender de la puerta de enlace que utilicemos como salida a Internet, así que introducimos el servidor DNS público de Google (8.8.8.8).

Por último, debemos editar el fichero /etc/default/isc-dhcp-server e introducir en la línea Interfaces la interfaz de red inalámbrica que utilizaremos para el punto de acceso, en nuestro caso wlan1.

Establecer una IP fija para la interfaz inalámbrica

Necesitamos establecer una IP fija, que no varíe, para la interfaz inalámbrica del punto de acceso. De esta manera, los clientes podrán saber dónde se encuentra siempre la puerta de enlace predeterminada.

Lo primero es desactivar temporalmente la interfaz inalámbrica, en nuestro caso wlan1, con el siguiente comando:

sudo ifconfig wlan1 down

Tras ello, editaremos el fichero /etc/network/interfaces y agregaremos, o editaremos de existir ya un apartado para wlna1, las siguientes líneas:

iface wlan1 inet static
address 11.0.0.1
netmask 255.255.255.0

En caso de que existan, eliminaremos o comentaremos las líneas correspondientes a wpa-roam y iface default inet dhcp, elementos de conexión en modo cliente que no necesitaremos en nuestra configuración.

La configuración de wlan1 debería quedar así:

Configuración de IP fija de la sonda

Por último, levantamos de nuevo la interfaz de red con la nueva dirección IP:

ifconfig wlan1 11.0.0.1 up

Configuración del punto de acceso

Procedemos ahora a la creación del punto de acceso en sí. El primer paso es crear un fichero en la dirección /etc/hostapd/hostapd.conf. Debemos rellenar unas pocas líneas de configuración. Dependiendo de nuestro hardware y la configuración concreta de seguridad que queramos configurar, podría quedar de la siguiente manera:

Configuración del punto de acceso

Vemos que contiene tanto configuración básica de la red inalámbrica como una configuración de seguridad mediante WPA2-CCMP y configuración hardware.

NOTA: La prueba de concepto del proyecto se basa en la inseguridad de redes inalámbricas abiertas. Sin embargo, para las pruebas, y dado que se harán en un entorno personal, se ha configurado una seguridad WPA2 para evitar irrupciones de sujetos no invitados durante el desarrollo y recogida de datos para la experimentación. En caso de querer realizar pruebas reales, simplemente habría que eliminar las líneas anteriores relacionadas con WPA/WPA2 y la red quedaría como abierta.

Explicación de la configuración del punto de acceso

Debemos rellenar ahora el fichero /etc/hostapd/hostapd-psk con la clave de cifrado de la red. La clave de cifrado, que estableceremos como probe1_profiling a modo de ejemplo, deberá introducirse en dicho fichero o bien en formato ASCII o bien en formato de clave hexadecimal de 256 bits.

Esta clave hexadecimal, que utilizaremos por cuestiones de seguridad, se haya combinando la clave en formato ASCII con el SSID de la red y pasando esta combinación por el algoritmo de hash SHA1 un número de 4096 veces y produciendo la salida de 256 bits.

La generación de esta clave la realizaremos mediante la herramienta wpa_passphrase, incluida en Raspbian de forma predeterminada con WPA Supplicant, que contiene diversas utilidades de gestión de redes WPA. La contraseña, por poner un ejemplo, será probe1_profiling.

sudo wpa_passphrase "probe1" "probe1_profiling"
Obtención de la passphrase WPA

Dicha clave la copiamos en el fichero /etc/hostapd/hostapd-psk de la siguiente manera, estableciéndola como clave única de la red:

Establecimiento de la passphrase en la configuración

Habiendo ya completado esta configuración, nos dirigiremos al fichero /etc/default/hostpapd. Dentro de éste, en la línea correspondiente a DAEMON_CONF, introduciremos nuestro fichero de configuración localizado en /etc/hostapd/hostapd.conf:

Establecimiento del fichero de configuración de hostapd en el daemon

Configuración de la NAT y la redirección IP

Para realizar la redirección del tráfico entre nuestra red inalámbrica e Internet, debemos configurar un servicio NAT y activar la redirección IPv4 entre las dos interfaces de red.

El primer paso es agregar o editar la siguiente línea en el fichero /etc/sysctl.conf, de manera que activamos al inicio la redirección en IPv4:

net.ipv4.ip_forward=1
Activación de la redirección IPv4

Para activarla en el mismo momento sin necesitar un reinicio, podemos ejecutar el siguiente comando como root:

echo 1 > /proc/sys/net/ipv4/ip_forward
Activación de la redirección IPv4 en el sistema corriendo

Ahora debemos configurar la NAT entre la interfaz que nos ofrece el acceso a Internet (tomaremos eth0 como referencia) y la interfaz del punto de acceso inalámbrico (wlan1 en nuestro caso). Esto podemos hacerlo mediante los siguientes comandos, que configurarán diversas líneas de iptables:

sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
sudo iptables -A FORWARD -i eth0 -o wlan1 -m state --state RELATED,ESTABLISHED -j ACCEPT
sudo iptables -A FORWARD -i wlan1 -o eth0 -j ACCEPT
Configuración de las reglas IPTABLES

Estas líneas realizan las siguientes acciones:

  1. Activar una NAT tipo MASQUERADE cuyo destino es la interfaz eth0.
  2. Realiza un reenvío desde la interfaz eth0 hacia wlan1 si el estado de la conexión en cuestión es RELATED o ESTABLISHED, es decir, si es referente a una conexión ya establecida. Así permitimos solo las conexiones iniciadas desde dentro (red local) hacia fuera (Internet).
  3. Realiza un reenvío desde la interfaz wlan1 hacia eth0 sea cual sea, permitiendo cualquier conexión hacia el exterior.

Podemos hacer persistente esta configuración guardando estos comandos iptables en un fichero de script localizado en /etc/firewall-probe.sh con permisos de ejecución. Agregamos la siguiente línea al fichero /etc/network/interfaces en el apartado de configuración de la interfaz eth0. Así haremos que dicho script se ejecute tras la activación de la misma, junto a cualquier otra regla que tengamos configurada:

post-up /etc/firewall-probe.sh
Configuración de las IPTABLES en un script
Establecimiento del script de inicio de IPTABLES al arranque de la interfaz

NOTA: Ignorad el fichero de OpenVPN, configuramos también un servicio para acceso remoto pero está fuera del scope del proyecto 🙂

Inicio de los servicios en el arranque

El último paso de configuración para nuestro equipo de recogida de tráfico es establecer que los servicios asociados a hostapd y isc-dhcp-server arranquen con el inicio del sistema. Podemos realizar esto mediante los siguientes comandos:

sudo update-rc.d hostapd enable
sudo update-rc.d isc-dhcp-server enable
Activación de los servicios en el arranque

A partir del siguiente reinicio, tendremos nuestro punto de acceso totalmente configurado para funcionar.

Guardado del tráfico de red

Para guardar todo el tráfico que pasa por la interfaz de red de nuestra sonda, necesitaremos realizar un volcado de dicho tráfico de manera constante a un fichero. Para ello vamos a utilizar un script que comience a escuchar el tráfico tras el levantamiento de punto de acceso.

Junto a la herramienta hostapd se encuentra la utilidad hostapd_cli, que permite al invocarse la ejecución de un script cada vez que un cliente se conecta y desconecta. Evidentemente, debe invocase con el daemon de hostapd ya en funcionamiento.

Utilizaremos hostapd_cli para establecer que cada vez que un cliente se conecte a nuestro punto de acceso se comience a guardar en un fichero el tráfico correspondiente.

Lo primero será editar el fichero /etc/hostapd/hostapd.conf de manera que establezcamos la opción de configuración ctfl_interface a la dirección /var/run/hostapd. En ella se encuentra de forma predeterminada la interfaz de control utilizada por hostapd_cli para comunicarse con hostapd.

Establecimiento de la de interfaz de control de hostapd

Ahora, crearemos un fichero /etc/hostapd/sniffer.sh, que contendrá el script a ejecutarse cada vez que un cliente se conecte o desconecte del punto de acceso. Dicho script, al ser llamado mediante hostapd_cli, recibirá como argumentos la interfaz en la que se efectúa la conexión o desconexión, el tipo de evento (conexión o desconexión) y la dirección MAC de la estación cliente.

#!/bin/bash

if [[ $2 == "AP-STA-CONNECTED" ]]
then
        echo "Cliente $3 conectado en $1" >> /tmp/sniffer_log
        tcpdump -U -i $1 ether host $3 -s 0 -w "/home/pi/capturas/$3__`date +%d-%m-%Y__%T.pcap`" &
        pid=$!
        (flock -e 200
                echo "$pid $3" >> /tmp/sniffer_pids
        ) 200>/tmp/lock
fi

if [[ $2 == "AP-STA-DISCONNECTED" ]]
then
        echo "Cliente $3 desconectado en $1" >> /tmp/sniffer_log
        (flock -e 200
                line=`cat /tmp/sniffer_pids | grep $3`
                pid=`echo $line | cut -f 1 -d ' '`
                kill $pid
        ) 200>/tmp/lock
        (flock -e 200
                cat /tmp/sniffer_pids | egrep -v '^$3 .*$' > /tmp/sniffer_pids
        ) 200>/tmp/lock
fi

El script, al llamarse, comprobará si el evento es de conexión o desconexión. Si es de conexión, comenzará una captura mediante la herramienta tcpdump por la interfaz correspondiente y sobre la dirección MAC del cliente, guardando la captura en un fichero cuyo nombre será dicha dirección MAC seguida de la fecha y hora del comienzo de la captura. Este detalle de agregar la fecha al nombre previene que tcpdump sobrescriba el fichero al realizar un dispositivo varias conexiones.

Además, guardará el PID del proceso de tcpdump en un fichero temporal, en una línea que contiene el PID y la MAC del cliente. En el evento de desconexión, se enviará una señal de finalización al proceso leyendo su PID de dicho fichero temporal, y eliminando la línea correspondiente.

Las condiciones de carrera al haber varias instancias de sniffer.sh se previenen utilizando la herramienta flock. Esta establece una política de bloqueo mediante un cerrojo en /tmp/lock, de manera que solamente una instancia del script podrá acceder de forma simultánea al fichero /tmp/sniffer_pids que controla los procesos de captura.

Asimismo, el script guardará en un fichero de log /tmp/sniffer_log las conexiones y desconexiones que se vayan produciendo.

Seguidamente, configuraremos la herramienta hostapd_cli como un servicio del sistema que se ejecutará al inicio una vez esté activo el servicio de hostapd. Crearemos para esto el fichero /etc/init.d/hostpapd_cli, con permisos de ejecución y con el siguiente contenido:

#!/bin/sh

### BEGIN INIT INFO
# Provides: hostapd_cli
# Required-Start: $remote_fs hostapd
# Required-Stop: $remote_fs
# Should-Start:
# Should-Stop:
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Enables the sniffer on probe access point
# Description:
### END INIT INFO

PATH=/sbin:/bin:/usr/sbin:/usr/bin
DAEMON_SBIN=/usr/sbin/hostapd_cli
NAME=hostapd_cli
DESC="hostapd cli"
PIDFILE=/var/run/hostapd_cli.pid

[ -x "$DAEMON_SBIN" ] || exit 0
DAEMON_OPTS="-B -a /etc/hostapd/sniffer.sh"
. /lib/lsb/init-functions

case "$1" in
  start)
    log_daemon_msg "Starting $DESC" "$NAME"
    start-stop-daemon --start --oknodo --quiet --exec "$DAEMON_SBIN" \
      -- $DAEMON_OPTS >/dev/null
    log_end_msg "$?"
    ;;
  stop)
    log_daemon_msg "Stopping $DESC" "$NAME"
    start-stop-daemon --stop --oknodo --quiet --exec "$DAEMON_SBIN"
    log_end_msg "$?"
    ;;
  restart|force-reload)
    $0 stop
    sleep 4
    $0 start
    ;;
  status)
    status_of_proc "$DAEMON_SBIN" "$NAME"
    exit $?
    ;;

  *)
    N=/etc/init.d/$NAME
    echo "Usage: $N {start|stop|restart|force-reload|status}" >&2
    exit 1
    ;;
esac
exit 0

Con esto tendremos el servicio configurado y listo para ser ejecutado tras un reinicio del sistema 🙂 Ahora, cada vez que un dispositivo se conecte a nuestro punto de acceso, comenzará una escucha en exclusiva para su dirección MAC y se guardará en nuestra sonda.

Espero que de momento os vaya gustando el proyecto. Como os comentaba, pronto liberaremos la parte de la aplicación AIRE en sí, una aplicación web basada en pila ELK y Django. Esperamos no tardar mucho en dejarlo decente :P! Un saludo y que os sirva!!

 

PD: Algunos enlaces que me ayudaron mucho, dado que siempre es educado nombrar referencias 🙂

https://learn.adafruit.com/setting-up-a-raspberry-pi-as-a-wifi-access-point/overview

http://jorisvr.nl/wpapsk.html

https://wiki.alpinelinux.org/wiki/How_to_setup_a_wireless_access_point

https://www.ibm.com/developerworks/library/l-wifiencrypthostapd/

https://albertomolina.wordpress.com/2009/01/09/nat-con-iptables/

http://wiki.excito.com/w/index.php?title=Controling_Homeautomation_devices_using_wifi_presence

http://www.kfirlavi.com/blog/2012/11/06/elegant-locking-of-bash-program/

PD2: Para poneros los dientes largos, algunas capturas de la solución:

 

 

6 comentarios en «AIRE (I) – Introducción y recogida de datos mediante sonda»

  1. Yo estuve trasteando en algo parecido con FruityWifi, creando un AP que pasaba por bettercap y tcpdump, aunque el TLS da mucho la lata.
    Esperamos con ansia más!

    1. Hola nope, gracias por el comentario! Realmente la infrastructura es muy similar a FruitiWifi, la piña o soluciones similares, pero de forma más «casera». TLS no permite examinar el contenido, pero sí los endpoints, así que aun así se puede inferir información. Un saludo!

  2. Excelente trabajo Hartek! Supongo que el próximo paso que realizasteis fue el de interpretar el fichero y reestructurarlo para enviarlo a logstash, almacenarlo en elasticsearch y por último visualizarlos con la aplicación web kibana, ¿Verdad?

    En la penúltima imagen de la presentación enseñáis las aplicaciones encontradas en la sonda. ¿Para hacer este trabajo os fijáis en las cabeceras del paquete wireless? ¿Hasta que punto habéis llegado capturando la información?

    ¡La verdad es que la práctica me ha llamado la atención!

    1. Buenas JonVii, muchas gracias por el comentario!! Efectivamente en posteriores pasos integramos la pila ELK, pero no utilizamos Logstash. Tras una fase de extracción de datos relevantes almacenamos los resultados en SQLite, y estos datos más tarde se analizan de forma periódica con la lógica de perfilado, guardando los resultados directamente en ElasticSearch y utilizando Kibana para visualizar resultados.
      El reconocimiento de aplicaciones se realiza en esta última fase de análisis. Hacemos inspección capa a capa TCP/IP tomando datos relevantes (agentes de usuario, endpoints…) y el algoritmo deduce la aplicación.
      Un saludo!!

      1. Gracias Hartek!

        Muy interesante de verdad!

        Esperando a probarla para ver este gran producto 😀

        Un Saludo.

Los comentarios están cerrados.