Home Assistant: Seguimiento de Personas con Wi-Fi Usando Kismet

Parece ser que el seguimiento de las personas se ha convertido en un mercado multimillonario (https://goo.gl/T1XZS8), el cual se puede usar para crear perfiles sobre personas (conocer los hábitos de una persona y monetizar en función de éstos) o para optimizar las tiendas y lugares dónde va la gente. Por ejemplo, si una tienda de ropa puede rastrear tus movimientos (y recordar dónde has estado en visitas anteriores), pueden crear un perfil con los tipos de ropa que te gusta y pueden bombardearte posteriormente con anuncios personalizados. El seguimiento de personas se puede realizar de muchas maneras, desde el reconocimiento facial hasta el seguimiento por wifi/bluetooth, con una precisión variable. Al igual que con cualquier tecnología, el seguimiento se puede utilizar para hacer el bien (por ejemplo, encontrar personas sepultadas tras un terremoto) o el mal (acechar a tu vecina de al lado).

En mi caso, quiero seguirle la pista a la niñera para saber si está en casa o no, de esta forma sé si tengo que ir a recoger a mi hijo al parque. Esto es bastante fácil de hacer con el seguimiento wifi y Home Assistant. El problema que tengo es que el teléfono de mi niñera no se conecta a mi red wifi, así que necesito usar una forma pasiva de monitorización.

Ya hemos comentado cómo funciona el wifi (https://goo.gl/yWD2j1) y también cómo se puede detectar (https://goo.gl/uEsdMo). En pocas palabras: los clientes y los puntos de acceso transmiten regularmente su SSID o sondean buscando cualquier SSID de una determinada área. Todo el tráfico inalámbrico (incluso el tráfico encriptado) tiene información de capa 2 (direcciones MAC) sin cifrar y ésta puede ser rastreada. Para escuchar el tráfico wifi, debes tener una tarjeta inalámbrica que admita el modo monitor (los adaptadores wifi HardKernel lo admiten). Normalmente, las direcciones MAC son únicas por dispositivo y se pueden utilizar para rastrear un dispositivo específico, de modo que cualquier persona que tenga una tarjeta WiFi con modo monitor puede rastrearte (como estamos a punto de ver).

Instalación del súper vanguardista Kismet

La forma más sencilla de empezar a escuchar el espectro wifi es instalar kismet. Kismet se encarga de poner tu adaptador wifi en modo monitor y, además, puede registrar todo el tráfico detectado. Para acceder a la nueva interfaz de usuario y también para tener una REST API, necesitarás instalar kismet desde la fuente en lugar de hacerlo desde un administrador de paquetes (tanto Ubuntu 16.04 como 18.04 tienen versiones demasiado antiguas de kismet). Tienes instrucciones generales sobre ello en: https://goo.gl/qjwLKb.

Primero necesitarás instalar algunas herramientas de desarrollo:

$ sudo apt-get install build-essential git libmicrohttpd-dev \
pkg-config zlib1g-dev libnl-3-dev libnl-genl-3-dev libcap-dev \
libpcap-dev libncurses5-dev libnm-dev libdw-dev libsqlite3-dev \
libprotobuf-dev libprotobuf-c-dev protobuf-compiler \
protobuf-c-compiler
$ sudo apt-get install python python-setuptools python-protobuf \
python-sqlite python-requests
La compilación de kismet necesitará más memoria RAM de la que probablemente tengas, de modo que no es mala idea activar el intercambio de memoria swap basado en disco. Yo opte por 1G swap para mi C2, pero si tienes más espacio disponible, puedes crear un archivo swap más grande:
$ dd if=/dev/zero of=/swap bs=1M count=1000
$ mkswap /swap
$ swapon /swap
A continuación, puedes hacerte con la última copia del desarrollo de Kismet, compilarla e instalarla:
$ git clone https://www.kismetwireless.net/git/kismet.git
$ cd kismet
$ ./configure
$ make -j 4
$ sudo make suidinstall
Una vez hecho esto, puede desactivar el intercambio swap que creaste y recuperar tu espacio en disco:
$ sudo swapoff /swap
$ sudo rm -f /swap
Kismet se instalará en /usr/local, con su configuración ubicada en /usr/local/etc/kismet.

Puedes crear un nuevo script de inicio systemd para kismet:

$ cat /etc/systemd/system/kismet.service
[Unit]
Description=Kismet wifi monitor

[Service]
Type=forking
ExecStart=/usr/local/bin/kismet -c wlan0 --no-curses-wrapper --daemonize -n
WatchdogSec=3600
Restart=always

[Install]
WantedBy=multi-user.target
$ sudo systemctl enable kismet
$ sudo systemctl start kismet
El script de inicio systemd inicia kismet como un demonio, sin registro, vinculado a wlan0 (que se pondrá en modo monitor). Yo he tenido algunos problemas con los puertos USB de mi C2 (principalmente porque he estado ejecutando varios gadgets desde un hub no alimentado) y, a veces, el adaptador wifi se bloqueaba y necesitaba reiniciarse. Si reinicio kismet cada hora, el problema desaparece, esto es lo que hace precisamente WatchdogSec.

Una vez iniciado, puedes conectarte a su interfaz web en http://:2501/. Tienes acceso de solo lectura sin autentificarte, pero deberás crear un usuario si quieres cambiar la configuración. Cuando inicies kismet por primera vez, se generará y almacenará una contraseña aleatoria para el usuario kismet en /root/.kismet/kismet_httpd.conf.

Figure 1 - Kismet UI
Figura 1 - UI de Kismet

Conocer la MAC

Para rastrear a alguien a través de wifi, necesitarás conseguir su dirección MAC de una forma u otra. Puedes solicitarla o utilizar la ingeniería social para averiguarla (p. Ej., Solicitar ver la configuración de red para solucionar algún problema ficticio), o tendrás que trabajar un poco en el caso de que no tengas acceso en absoluto al dispositivo que quieres rastrear.

Si estás atascado en el último caso, tendrás que hacer algunas suposiciones:

  • La persona rastreada tiene el wifi abierto y hacer solicitudes de sondeo
  • La persona rastreada tiene una MAC estática
  • Saber cuándo la persona rastreada se encuentra dentro del alcance de detección

En este caso, aquí tienes la estrategia a seguir. Inicia kismet en modo monitor y haz que se registre el tráfico ambiental en un archivo (base de datos sqlite3). Detén la captura antes de que la persona de interés se encuentre dentro del alcance y realiza una nueva captura cuando la persona esté cerca. Deja la captura activa durante el mayor tiempo posible (al menos 10-15 minutos) y detenla cuando la persona ya no se encuentre cerca. A continuación, extrae las direcciones MAC de ambos conjuntos de datos y marca las diferencias. Te interesan las MAC que aparecen cuando el objetivo estaba presente pero que no se encuentran en el primer conjunto de datos (elimina las MAC encontradas en el primer conjunto de datos del segundo). Deberías quedarte con un listado más pequeño de MAC, una de las cuales es la MAC del objetivo. Puedes afinar aún más este listado teniendo en cuenta los registros de fecha y hora: elimina las MAC que aparecen después de que el objetivo ya no se encontrase cerca o antes de que aparezca el objetivo. Si aún cuentas con una lista de varias MAC y no puedes excluir algunas basándote en el fabricante (por ejemplo, todos son teléfonos Samsung), tendrás que repetir el proceso en otro momento y ver qué MAC del nuevo registro son los mismas que las posibles MAC del objetivo. El proceso de eliminación debe terminar con solo una MAC que aparece en todas las capturas y no es "regular". Si estás haciendo esto en un área "tranquila" (por ejemplo, una casa), encontrará la MAC con bastante rapidez. Si, en cambio, estás haciendo esto en un área concurrida, tendrás que registrar el tráfico del ambiente en varias ocasiones.

Veamos el plan en acción.

Primero necesitas llevar a cabo la captura. Para activar esto, edita /usr/local/etc/kismet_logging.conf y cambia log_prefix=/tmp/.

A continuación, edita el servicio systemd y elimina el parámetro de la línea de comandos "-n" para que el registro finalice:

$ sudo sed -i 's/--daemonize -n/--daemonize/' \
/etc/systemd/system/kismet.service
$ sudo systemctl daemon-reload
$ sudo service kismet restart
Ahora obtendrás archivos de registro por hora en /tmp con los dispositivos que ha visto kismet. Una vez que tenga suficientes datos, puedes desactivar el registro y reiniciar kismet editando el servicio systemd y agregando "-n".

Después, deberás dividir los archivos que has recopilado en dos grupos. El directorio "0" contendrá los archivos donde se sabe que el objetivo no ha estado presente, mientras que el directorio "1" contendrá los archivos donde el objetivo podría haber estado presente. Puedes hacer esta división teniendo en cuenta el tiempo (tienes intervalos de una hora por defecto).

$ mkdir 0 1
$ sudo mv /tmp/Kismet-20180718-07-33-00-1.kismet 0/
$ sudo mv /tmp/Kismet-20180718-10-33-03-1.kismet 1/
Ahora viene el trabajo duro. Necesitamos extraer todos las MAC de todos los archivos de ambas carpetas y compilar dos listas: MAC de la carpeta 0 y de la carpeta 1. Podemos obtener datos del registro log de kismet utilizando sqlite3 con una sintaxis SQL. Como sqlite3 no admite comodines para los nombres de archivos, debemos hacer algunas artimañas con bash y repetirlas sobre cada archivo.
$ sudo apt-get install sqlite3 bc
$ for file in 0/*.kismet; do sqlite3 -csv "$file" 'select \
devmac,first_time,last_time from devices;' | tee -a 0/0.dump; done
$ for file in 1/*.kismet; do sqlite3 -csv "$file" 'select \
devmac,first_time,last_time from devices;' | tee -a 1/1.dump; done
Para ambos directorios, hemos descargado la MAC, la hora de inicio y la hora de finalización de Kismet. El siguiente paso es unir todos los datos (ya que tener múltiples archivos da lugar a entradas duplicadas). Utilizaremos sort + uniq y conservaremos solo las direcciones MAC. En mi caso, terminé con 701 MAC que sabía que no eran el objetivo, y 229 MAC que podrían ser el objetivo.

Llegados a este punto, tenemos que reducir aún más esta lista potencial eliminado las MAC que sólo han aparecido un breve periodo de tiempo (durante menos de 100 segundos) porque es probable que pertenezcan a personas o coches que han pasado de largo. Esto reduce aún más el número de MAC ajustándose a 152 en mi caso.

$ cat 0/0.dump | cut -f 1 -d ',' | sort -u > 0/0.mac
$ while read line; do start=`echo $line | cut -f 2 -d ','`; \
end=`echo $line | cut -f 3 -d ','`; difference=`echo $end-$start|bc`; if [ "$difference" -gt 100 ]; then echo "$line" | tee -a 1/1_filtered.dump; fi; done < 1/1.dump $ cat 1/1_filtered.dump | cut -f 1 -d ',' | sort -u > 1/1.mac
Ahora comienza el proceso de eliminación: eliminamos las líneas coincidentes de los dos archivos. Para esto podemos usar grep -v para imprimir las líneas que no coinciden y buscamos las contenidas de 0/0.mac dentro de 1/1.mac:
$ grep -v -f 0/0.mac 1/1.mac > potential.mac
Esto me deja con solo 27 MACs para seguir investigando. Podría filtrar por el proveedor del dispositivo (si supiera cual es). Una forma de mantener solo los dispositivos Samsung es buscar su MAC en la base de datos OUI. Puedes instalar una copia local de la base de datos con el paquete ieee-data y puede buscar todas las MAC y conservar únicamente las registradas en Samsung.
$ sudo apt-get install ieee-data
$ while read line; do match=`echo $line | cut -c 1-8 | sed 's/://g' | xargs -n 1 -I{} grep {} /usr/share/ieee-data/oui.txt | grep -i Samsung`; if [ -n "$match" ]; then echo "$line"| tee -a samsung.mac; fi; done <potential.mac
Reduzco a 4 las MACs tras aplicar este filtro, así que me estoy acercando bastante. Para afinar aún más, necesito realizar más escuchas cuando el objetivo esté cerca y encontrar qué MAC de del nuevo registro se encuentran en el registro anterior hasta que me quede solo con una. O bien, podría monitorizar las 4 y ver dentro de Home Assistant cuál de ellas actúa correctamente.

Añadir un device_tracker personalizado en Home Assistant

La ventaja del nuevo kismet que acabas de instalar es que puede hacerle consultar a través de su REST API y obtener una respuesta JSON de los nuevos dispositivos que coincidan con tus criterios de búsqueda. La documentación de la REST API está disponible aquí: https://goo.gl/JFpnZM.

La idea es implementar un device_tracker personalizado como un módulo en Home Assistant que cogerá una lista de direcciones MAC o una lista de SSID y preguntará a una instancia de kismet si vio estas MACs/SSIDs en los últimos 30 segundos. Si Kismet los ha visto, reportará sus nombres, que a su vez se transmitirán a Home Assistant.

Actualmente, kismet device_tracker se puede usar como un componente personalizado. Es de esperar que, en el futuro, cuando la REST API se estabilice, pueda fusionarse directamente en Home Assistant. Puedes instalarlo siguiendo estos pasos:

$ sudo su - homeassistant
$ cd .homeassistant
$ mkdir -p custom_components/device_tracker
$ cd custom_components/device_tracker
$ wget -O kismet.py https://goo.gl/WPGZZA
Necesitarás editar configuration.yaml y añadir el componente:
device_tracker:
- platform: kismet
interval_seconds: 30
host: 192.168.1.15
port: 2501
consider_home: 420
clients:
- 84:98:66:47:cf:b9
- d0:31:69:38:f2:99
ssids:
- DIGI
Para una depuración adicional (aunque con ruido), puedes configurar el componente para depurar también dentro del programa registrador:
logger:
default: error
logs:
custom_components.device_tracker.kismet: debug
Una vez que reinicies Home Assistant, el componente se conectará periódicamente a la instancia de kismet y consultará los dispositivos que enumeraste. Obtendrá resultados para el último período "interval_seconds" (por ejemplo, durante los últimos 30 segundos), de modo que incluso si el dispositivo móvil estuvo activo durante un tiempo en ese intervalo, se detectará y se informará de ello. La duración de interval_seconds solo afecta a la rapidez con que se ve un dispositivo, no si se ve o no. Los parámetros tienen los siguientes significados:

  • interval_seconds - con qué frecuencia se solicita actualizaciones desde l servidor kismet
  • host - la IP/FQDN del servidor kismet (127.0.0.1 por defecto)
  • port - el puerto donde se ejecuta kismet (2501 por defecto)
  • consider_home - ¿durante cuánto tiempo se debe considerar que un cliente permanece en casa si no se ha visto? (7 minutos es aceptable para clientes con wifi abierto, aunque no esté conectado a una red. Puede depender de un dispositivo a otro)
  • clients - una lista de direcciones MAC para buscar. Puede ser una expresión regular
  • ssids - una lista de SSID para buscar. Puede ser una expresión regular

Los dispositivos que sean detectados se agregan a known_devices.yaml, al cual se puede acceder como una entidad dentro de Home Assistant. Una vez descubiertos los dispositivos, puede personalizar su nombre y añadirles una imagen editando known_devices.yaml

Figure 2 - known_devices.yaml entry
Figura 2 - Entrada known_devices.yaml

Puedes añadir las entidades para ser rastreadas dentro de un grupo y mostrarlas en la interfaz de usuario principal de Home Assistant

group:
people:
name: People
view: yes
entities:
- device_tracker.the_nanny
- device_tracker.samsungj3
- device_tracker.nexus5
Figure 3 - People tracking
Figura 3 - Seguimiento de personas

Si estás utilizando la interfaz de usuario personalizada (https://github.com/andrey-git/home-assistant-custom-ui/) con Home Assistant también puede mostrar la última hora modificada (por ejemplo, "hace 2 minutos") debajo del nombre de la entidad para contar con una indicación rápida de cuánto tiempo hace que una persona llegó o se fue. Para hacerlo, asegúrate de estar en la última versión de CustomUI (ejecuta ./update-custom-ui.sh desde dentro de ~homeassistant/.homeassistant) y añade lo siguiente en la configuración:

homeassistant:
customize:
device_tracker.the_nanny:
custom_ui_state_card: state-card-custom-ui
show_last_changed: true

Conclusión

Entonces, ¿qué tan funciona? Depende del dispositivo que quieras rastrear. Los dispositivos más antiguos/más baratos no intentan ocultar su MAC y se detectan con facilidad (como mi Samsung J3). Los dispositivos más nuevos/caros utilizan MACs aleatorias para hacer solicitudes de sondeo y son más difíciles de concretar. Sin embargo, no es imposible. Todos los teléfonos usan su dirección MAC real cuando se conectan a un punto de acceso conocido. Por lo tanto, si (independientemente) transmites una lista de nombres de puntos de acceso populares del área del objetivo (por ejemplo, Starbucks, McDonalds, etc.), puede convencer a su wifi para que se delate e intente conectarse a tu punto de acceso. Este método dejará rastros, porque todos esos puntos de acceso wifi serán visibles en la lista de redes para todos los clientes, lo cual levantará sospechas, aunque este artículo te ayudará a empezar: https://goo.gl/rXg2so.

Dependiendo del comportamiento del teléfono, es posible que entre en modo reposo de vez en cuando y es posible que se pierdan algunas solicitudes de sondeo (especialmente si el teléfono tiene batería), pero debería ser bastante visible cuando su pantalla esté encendida o el usuario esté haciendo una llamada. Para mejorar la precisión, es posible que necesites añadir más oyentes kismet alrededor de tu casa para cubrir más canales o puntos ciegos.

Figure 4 - Presence data over time
Figura 4 - Datos de presencia en el tiempo

¿Qué puedes hacer para evitar la detección y el seguimiento? Sencillo. Apaga tu wifi cuando no la utilices. Si no tienes lo último en teléfono movil (Android P parece haber incluido las MAC aleatorios), puedes usar aplicaciones de terceros como Pri-Fi (https://play.google.com/store/apps/details?id=eu.chainfire.pryfi) por chanfire (el creador de SuperSU) para hacer los mismo. Aunque dependiendo de la tecnología de la persona que está rastreando, la mayoría de la gente no se molestará en ocultarse.

Be the first to comment

Leave a Reply