Etude d'une balance connectée
En août 2017, je m’étais amusé à pirater ma balance connectée de marque Withing afin de récupérer directement mes mesures de poids sans passer par l’interface Withings.
L’idée mise en place était une technique classique de man in the middle, exécutée from scratch pas à pas (l’exercice fut didactique).
Aujourd’hui, 8 ans plus tard, je remets la main par hasard sur ce projet que j’avais un peu oublié.
Je reproduis ci-dessous pour garder une trace. A noter que la plupart des informations ont été anonymisées… mais après 8 ans et un renouvellement intégral de mon matériel informatique (box, pc, raspberry etc.), il n’y a plus grand chose de sensible de toutes façon. Et je me suis depuis débarrassé de cette balance (coucou la Quadrature du Net).
- Liste des outils utilisés
- Introduction
- Installation du système
- Mise en place du point d’accès WiFi
- Un premier sniffing du réseau
- Sniffing de la balance
- Pistes pour continuer
Liste des outils utilisés
- hostapd
- iptables
- isc-dhcp-server
- systemctl
- syslog
- tcpdump
- lsof
- netcat
- nmap
- arp
- dig
Introduction
Je dispose depuis quelques temps d’une balance Withings Body WS-50. Cette balance fait partie des objets dits “connectés” : lorsque je me pèse, la balance envoie mon poids aux serveurs Withings. Je dois par la suite me connecter à ces serveurs pour voir l’évolution de mon poids.
Je trouve dommage de ne pas pouvoir récupérer directement les informations de la balance pour en faire ce que je souhaite et j’ai donc eu envie de capturer les trames que cette balance envoie régulièrement.
Pour ce faire, je vais utiliser un vieux Raspberry Pi que je vais reconfigurer en mode point d’accès.
Je pense procéder en deux étapes.
Tout d’abord il faut faire du Reverse Engineering sur la balance afin de déterminer comment les informations utiles sont envoyées aux serveurs Withings. Cela se décompose en plusieurs étapes :
- Mettre en place un point d’accès Wi-Fi sur le Raspberry via hostapd
- Mettre en place un partage de connection entre les interfaces Wifi et Ethernet du Rasberry
- Filtrer les accès au Raspberry via Iptables et filtrage par adresse MAC
- Tester la connection internet d’un portable
- Tester la connection de la balance au Raspberry
- Capture des trames émises par la balance via tcpdump sur le Raspberry
Dans un second temps, il faudra automatiser la récupération de ces informations. J’essaierai de faire ça le plus proprement possible via la programmation d’un service. Les étapes seront donc :
- Mise à jour des règles d’Iptables (inutile de garder le partage de connection Internet…)
- Programmation d’un service pour gérer la capture des trames et l’extraction des informations utiles
- Eventuellement mise en forme des données de poids via un petit script Python
Je dispose du matériel suivant :
- un “vieux” Raspberry Pi B embarquant 512 Mo de RAM
- un dongle WiFi qui traînait chez moi
- une balance connectée Wihtings Body WS-50
- deux pc sous Ubuntu qui, placés à deux endroits différents de mon réseau, me permettront de vérifier que tout se passe comme convenu.
Au final, la topologie du réseau que je souhaite mettre en place est résumée ci-dessous (les IPs sont anonymisées).
Installation du système
Nous récupérons la dernière version de Raspbian Jessie sur www.raspberrypi.org. Deux versions de Rasbian Jessie1 sont désormais proposées : Desktop et Lite. La version Lite, comme son nom l’indique, est livrée avec le strict minimum applicatif et n’intégre pas d’environnement graphique. C’est cette version que j’ai choisi pour notre bridge.
On prépare tout d’abord la carte SD avec l’incontournable commande dd
. L’option conv=sync,noerror
est un petit raffinement qui permet en cas d’erreur de padder le bloc de données avec des 0. Ainsi seul le bloc où l’erreur survient est illisible et ça ne décale pas le reste des données. Bon, personnellement en cas d’erreur je relance la commande ou alors je change de carte SD…
$ sudo dd bs=1m if=2017-07-05-raspbian-jessie-lite.img
of=/dev/rdisk2 conv=sync,noerror
On installe ensuite la carte SD dans le raspberry et on boot. L’utilisateur par défaut s’appelle pi
et son mot de passe est raspberry
, le serveur ssh n’est pas activé et le clavier est en qwerty… Bref, y’a du boulot !
Passer en Azerty, mettre à jour le timezone et activer le serveur ssh
La première étape est de lancer la commande raspi-config
pour passer en azerty, régler le timezone sur Europe/Paris et d’activer le serveur ssh. On en profitera également pour renommer la machine “donutbridge”.
$ sudo raspi-config
Petite subtilité de raspbian : il faut créer un fichier ssh dans /boot/ pour activier le serveur !
$ sudo touch /boot/ssh
On édite avant de rebooter le fichier /etc/ssh/sshd_config
, essentiellement pour changer le port par défaut de ssh
On vérifie au reboot que le service ssh est bien lancé :
$ systemctl status ssh
ssh.service - OpenBSD Secure Shell server
Loaded: loaded
Active : active (running)
Changer le nom et le mot de passe de l’utilisateur par défaut
Changer le nom et le mot de passe de l’utilisateur principal est étonnament une tâche assez délicate. Il faut commencer par autoriser le login root avec sudo passwd root
puis on utilise la commande usermod
. L’option -l
donne le nouveau login, -d
définit l’emplacement du nouveau $HOME
et enfin -m
indique à usermod
qu’il faut déplacer le répertoire utilisateur initial.
$ mkdir /home/donut
$ usermod -l donut -m -d /home/donut pi
On se déloggue de root et on se loggue en tant que donut : ça marche !
Première chose à faire : désactiver le login root via sudo passwd -l root
. On remarque au passage que l’utilisateur donut est toujours sudoer, usermod
fait bien les choses.
Il ne reste plus qu’à changer les droits de /home/donut
et à supprimer /home/pi
$ sudo chown -R donut:pi /home/donut
$ sudo rm -rf /home/pi
Mise en place du point d’accès WiFi
On va commencer par voir ce qu’il se passe lorsqu’on branche notre dongle WiFi
$ lsusb
[...]
Bus 001 Device 005: ID 0bda:8176 Realtek Semiconductor Corp. RTL8188CUS 802.11n WLAN Adapter
[...]
Bon le dongle semble être correctement détecté. Vérifions qu’il supporte le mode point d’accès, AP :
$ iw list
[...]
Supported interface modes:
* IBSS
* managed
* AP
* monitor
* P2P-client
* P2P-GO
[...]
Installation de Hostapd
On installe ensuite hostapd :
$ sudo apt install hostapd
On copie le fichier de configuration par défaut de hostapd
$ cd /etc/hostapd/
$ sudo cp /usr/share/doc/hostapd/examples/hostapd.conf.gz ./
$ sudo gunzip hostapd.conf.gz
On prendra également soin d’indiquer l’emplacement de ce fichier de configuration dans le fichier /etc/default/hostapd
:
DAEMON_CONF="/etc/hostapd/hostapd.conf"
Le fichier de configuration contient plusieurs paramètres que j’ai configuré ainsi :
interface=wlan0
driver=nl80211
logger_syslog=-1
logger_syslog_level=2
logger_stdout=-1
logger_stdout_level=2
ctrl_interface=/var/run/hostapd
ctrl_interface_group=0
ssid=bridge
country_code=FR
hw_mode=g
channel=1
beacon_int=100
dtim_period=2
max_num_sta=255
rts_threshold=2347
fragm_threshold=2346
macaddr_acl=1
accept_mac_file=/etc/hostapd/hostapd.accept
auth_algs=1
ignore_broadcast_ssid=0
wpa=2
wpa_passphrase=totorototoro
wpa_key_mgmt=WPA-PSK
wpa_pairwise=CCMP
rsn_pairwise=CCMP
On remarquera le “channel=1” qui a été choisi particulièrement pour ne pas interférer avec le WiFi de la maison. Le champ macaddr_acl
permet de définir la politique de gestion des adresses MAC (liste noire, liste blanche ou désactivé). Je n’ai pas vu d’impact pour le moment… Enfin, le champ ignore_broadcast_ssid
permet de ne pas diffuser le ssid : pratique en conditions opérationnelles, pour ajouter encore un peu de sécurité !
On tente notre première connexion : on lance manuellement le serveur côté Raspberry et on tente de s’y connecter via un portable. Ca passe crème !
$ sudo systemctl stop hostapd # lancement en manuel
$ sudo hostapd ./hostapd.conf
Configuration file: ./hostapd.conf
Using interface wlan0 with hwaddr 00:13:ef:d0:2e:bc and ssid "test"
wlan0: interface state UNINITIALIZED->ENABLED
wlan0: AP-ENABLED
wlan0: STA 9c:f3:87:aa:fe:62 IEEE 802.11: associated
wlan0: AP-STA-CONNECTED 9c:f3:87:aa:fe:62
wlan0: STA 9c:f3:87:aa:fe:62 RADIUS: starting accounting session 597E4C38-00000000
wlan0: STA 9c:f3:87:aa:fe:62 WPA: pairwise key handshake completed (RSN)
Filtrage par adresse MAC via Hostapd
Commençons maintenant les bonnes pratiques : on va mettre en place un filtrage par adresses MAC directement dans hostapd. Toujours dans notre fichier de configuration hostapd.conf
nous indiquons :
macaddr_acl=1
accept_mac_file=/etc/hostapd/hostapd.accept
Le fichier hostapd.accept
contiendra uniquement les adresses MAC de mon portable et de la balance.
Comme indiqué plus haut, cela n’a pas l’air d’avoir d’impact pour le moment : je peux tout à fait me connecter avec un autre poste. A faire : regarder la doc de Hostapd en détail pour voir à quel moment le filtrage se fait…
Serveur DHCP
A ce stade, les équipements peuvent se connecter sur le réseau “bridge” mais ils ne peuvent pas faire grand chose d’autre. Pour commencer il leur faut une adresse IP. Etant donné que seule la balance est sensée se connecter sur “bridge” on pourrait passer par un adressage fixe mais qui peut le plus peut le moins : on va passer par un serveur DHCP qui écoutera en permanence sur wlan0 en attente de datagramme “DHCP Discover”. On le définiera de telle sorte que deux postes tout au plus pourront se connecter en même temps sur l’interface.
On va tout d’abord définir un réseau d’accès en 192.168.8.0 sur l’interface wlan0
$ sudo ifconfig wlan0 down
$ sudo ifconfig wlan0 192.168.10.1 netmask 255.255.255.0 up
$ ifconfig
eth0 Link encap:Ethernet HWaddr b8:27:eb:9e:fa:cd
inet addr:192.168.0.38 Bcast:192.168.0.255 Mask:255.255.255.0
inet6 addr: fe80::328c:d511:1ca0:895d/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:10439 errors:0 dropped:1 overruns:0 frame:0
TX packets:3542 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:2023402 (1.9 MiB) TX bytes:596809 (582.8 KiB)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
wlan0 Link encap:Ethernet HWaddr 00:13:ef:d0:2e:bc
inet addr:192.168.10.1 Bcast:192.168.10.255 Mask:255.255.255.0
UP BROADCAST MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:8 overruns:0 frame:0
TX packets:0 errors:0 dropped:41 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:28355 (27.6 KiB) TX bytes:11913 (11.6 KiB)
Alors là, ça marche bien mais ce n’est pas perenne. Pour que le système se souvienne, il faut éditer le fichier /etc/network/interfaces
et ajouter les lignes :
auto wlan0
iface wlan0 inet static
address 192.168.10.1
netmask 255.255.255.0
On rédémarre ensuite le réseau avec :
$ sudo systemctl daemon-reload
Le serveur DHCPD n’étant pas installé par défaut, on l’installe avec $ sudo apt install isc-dhcp-server
. Alors là, le serveur échoue lamentablement au démarrage, ce qui est normal : il est configuré par défaut pour gérer eth0…
On modifie le fichier de configuration /etc/dhcp/dhcpd.conf
pour définir le réseau ainsi que la plage d’adresse IP disponibles :
option domain-name-servers 192.168.10.0;
authoritative;
# Declaration du subnet
subnet 192.168.10.0 netmask 255.255.255.0 {
option domain-name "WiFi.localhost";
option routers 192.168.10.1;
option subnet-mask 255.255.255.0;
option broadcast-address 192.168.10.0;
option domain-name-servers 192.168.10.1;
range dynamic-bootp 192.168.10.10 192.168.10.11;
}
On remarquera au passage que le domain-name-servers pointe vers la box Internet (192.168.0.254). Ceci signifie que lorsqu’une machine du réseau 192.168.10.0 demandera une résolution d’adresse (du genre “quelle est l’IP de www.forum.ubuntu.org ?), le raspberry lui répondra en substance “oh je ne sais pas trop, demande à la box Internet”. C’est une solution simple qui nous évite de devoir mettre en place un serveur cache DNS mais il a un coût : si 50 machines sur 192.168.10.0 demandent l’IP de www.forum.ubuntu.org, notre raspberry devra relayer 50 fois cette demande à la box.
Quoiqu’il en soit on prendra soin de définir l’interface à gérer dans /etc/default/isc-dhcp-server
:
DHCPD_CONF=/etc/dhcp/dhcpd.conf
INTERFACES="wlan0"
On redémarre les services hostapd et isc-dhcp-server via systemctl et cette fois-ci losqu’on se connecte via le portable, on a une IP en 192.168.10.0 !
Parallèlement nous pouvons vérifier l’ensemble des machines connectées sur l’interface wlan0 avec hostapd_cla
. Cette commande va nous retourner un certain nombre d’informations par poste connecté, dont son adresse MAC. La commande arp
permet dans un second temps de voir la correspondance Adresse MAC / Adresse IP.
$ sudo hostapd_cli all_sta
Selected interface 'wlan0'
9c:f3:87:aa:fe:62
flags=[AUTH][ASSOC][AUTHORIZED]
aid=0
capability=0x0
listen_interval=0
supported_rates=
timeout_next=NULLFUNC POLL
dot11RSNAStatsSTAAddress=9c:f3:87:aa:fe:62
dot11RSNAStatsVersion=1
dot11RSNAStatsSelectedPairwiseCipher=00-0f-ac-4
dot11RSNAStatsTKIPLocalMICFailures=0
dot11RSNAStatsTKIPRemoteMICFailures=0
hostapdWPAPTKState=11
hostapdWPAPTKGroupState=0
rx_packets=0
tx_packets=0
rx_bytes=0
tx_bytes=0
connected_time=11
$ arp | grep 9c:f3:87:aa:fe:62
192.168.10.10 ether 9c:f3:87:aa:fe:62 C wlan0
Arrivé à ce stade c’est un peu mieux mais on est loin d’avoir terminé… Il nous reste à établir le partage de la connection Internet. Ca tombe bien, c’est l’enjeu de la section suivante.
Néanmoins avant de passer à la section suivante, il est intéressant de regarder un moment les log de notre serveur DHCP.
$ tail -f /var/log/syslog | grep -i dhcp
Aug 2 06:30:43 donutbridge dhcpd: DHCPDISCOVER from 00:13:ef:d0:2e:bc (donutbridge) via wlan0
Aug 2 06:30:44 donutbridge dhcpd: DHCPOFFER on 192.168.10.10 to 00:13:ef:d0:2e:bc (donutbridge) via wlan0
[...]
Tiens, des messages DHCP Discover sont envoyés par l’adresse MAC 00:13:ef:d0:2e:bc ? Si on regarde la sortie de notre ifconfig (cf. les sections précédentes), on se rend compte que cela correspond à notre interface wlan0 ! Notre serveur DHCP tente régulièrement d’adresser une IP à wlan0, ce n’est pas du tout correct !
Pourquoi est-ce que wlan0 émet régulièrement des datagrammes DHCP Discover ? La réponse se trouve grâce à systemctl :
$ sudo systemctl status dhcpcd.service
dhcpcd.service - dhcpcd on all interfaces
Notre système embarque un client DHCP qui, par défaut, écoute sur TOUTES les interfaces (donc également sur wlan0 !). Il nous faut changer ce comportement pour être plus propre. Il suffit de rajouter la ligne suivante dans /etc/dhcpcd.conf
:
# Donut 2017-08-02 : we DO NOT listen on wlan0 interface
denyinterfaces wlan0
On recharge ensuite la configuration avec systemctl daemon-reload
. A présent si on regarde les logs de dhcpd, on ne voit plus passer de datagrammes DHCPDISCOVER sur wlan0 ! Passons maintenant au partage de connection proprement dit.
IP Forwarding et règles de routage
Pour commencer, il faut autoriser sur notre Raspberry l’IP Forwarding, c’est-à-dire la capacité à trasmettre sur une interface (ex: wlan0) des trames reçues sur une autre interface (ex: eth0). Encore une fois deux solutions existent : la temporaire et la pérenne.
Pour activer l’IP Forwarding le temps de la session, il suffit de mettre un “1” dans le fichier /proc/sys/net/ipv4/ip_forward
. pour la solution pérenne, il faut éditer le fichier /etc/sysctl.conf
et ajouter la ligne :
# Uncomment the next line to enable packet forwarding for IPv4
net.ipv4.ip_forward=1
A ce stade, les interfaces devraient être correctement configurées et notre Rasberry devrait savoir où envoyer n’importe quel paquet qu’il reçoit. Vérifions cela :
$ route
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
default 192.168.0.254 0.0.0.0 UG 202 0 0 eth0
192.168.0.0 * 255.255.255.0 U 202 0 0 eth0
192.168.10.0 * 255.255.255.0 U 0 0 0 wlan0
Comme nous le voyons, il sait que :
- les paquets à destination du réseau 192.168.10.0 sont à envoyer sur l’interface wlan0
- les paquets à destination du réseau 192.168.0.0 sont à envoyer sur l’interface eth0
- tous les autres paquets (principalement à destination d’internet donc) devront être envoyé au routeur par défaut, ici 192.168.0.254, autrement dit ma box internet… qui est accessible sur l’interface eth0
A ce stade, les routes sont correctes et le Rasberry est autorisé à faire de la redirection de paquet. Si depuis le réseau 192.168.10.0 je ping une machine sur 192.168.0.0, la machine destinataire devrait voir arriver le ping. Elle va y répondre mais notre émetteur ne recevra jamais la réponse.
Regardons cela plus en détail et rappelons-nous la topologie actuelle de notre réseau (voir la figure en début d’article). J’utilise deux PC additionnels que je place judicieusement sur le réseau :
- $PC_1$, d’IP 192.168.10.11, est placé au même niveau que la balance,
- $PC_2$, d’IP 192.168.0.39 est placé au même niveau que l’interface eth0 du Raspberry.
Les IP de nos différents équipements sont donc résumées dans le tableau ci-dessous
Machine | Interface | IP |
---|---|---|
$PC_1$ | eth0 | 192.168.10.11 |
$PC_2$ | eth0 | 192.168.0.39 |
Raspberry | eth0 | 192.168.0.38 |
Raspberry | wlan0 | 192.168.10.1 |
Box internet | eth0 | 192.168.0.1 |
Maintenant regardons ce qu’il se passe si, à ce stade de nos développements, nous
- essayons de pinger $PC_2$ depuis le Raspberry
- essayons de pinger $PC_2$ depuis $PC_1$
Voici ce que nous obtenons dans le premier cas : la colonne de gauche représente le Raspberry, celle de droite $PC_2$. Je me sers de la commande ping
pour envoyer des pings et tcpdump
pour écouter (remarquez l’option -p icmp
qui me permet de n’afficher que les trames du protocole icmp auquel ping appartient). On remarque non seulement $PC_2$ reçoit bien les ping du Raspberry, mais le Raspberry reçoit les réponses de $PC_2$ !
Raspberry :
$ ping -c 3 192.168.0.39 # Terminal du raspberry
PING 192.168.0.39 (192.168.0.39) 56(84) bytes of data.
64 bytes from 192.168.0.39: icmp_seq=1 ttl=64 time=0.469 ms
64 bytes from 192.168.0.39: icmp_seq=2 ttl=64 time=0.521 ms
64 bytes from 192.168.0.39: icmp_seq=3 ttl=64 time=0.534 ms
--- 192.168.0.39 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 0.469/0.508/0.534/0.028 ms
Terminal de $PC_2$
$ sudo tcpdump -p icmp # Terminal de PC_2
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on enp7s0, link-type EN10MB (Ethernet), capture size 262144 bytes
23:29:17.783149 IP 192.168.0.38 > 192.168.0.39: ICMP echo request, id 2107, seq 1, length 64
23:29:17.783160 IP 192.168.0.39 > 192.168.0.38: ICMP echo reply, id 2107, seq 1, length 64
23:29:18.785152 IP 192.168.0.38 > 192.168.0.39: ICMP echo request, id 2107, seq 2, length 64
23:29:18.785171 IP 192.168.0.39 > 192.168.0.38: ICMP echo reply, id 2107, seq 2, length 64
23:29:19.786414 IP 192.168.0.38 > 192.168.0.39: ICMP echo request, id 2107, seq 3, length 64
23:29:19.786437 IP 192.168.0.39 > 192.168.0.38: ICMP echo reply, id 2107, seq 3, length 64
Maintenant, refaisons la même manip mais cette fois-ci c’est $PC_1$ qui envoie les pings. On s’aperçoit bien que $PC_2$ reçoit bien les pings et qu’il y répond, ce qui prouve que le routage et l’IP Forwarding du Raspberry fonctionnent bien comme il faut. En revanche, le echo reply ne parvient jamais à $PC_1$, car ni $PC_1$ ni le Rasberry ni même la box Internet ne savent où diable se cachent les machines en 192.168.10.XX. Il nous manque bien une étape, et c’est la NAT.
Terminal de $PC_1$
$ ping -c 3 192.168.0.39 # Terminal de PC_1
PING 192.168.0.39 (192.168.0.39) 56(84) bytes of data.
Request timeout foricmp_seq 1
Request timeout foricmp_seq 2
Request timeout foricmp_seq 3
--- 192.168.0.39 ping statistics ---
3 packets transmitted, 0 received, 100% packet loss
Terminal de $PC_2$
$ sudo tcpdump -p icmp # Terminal de PC_2
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on enp7s0, link-type EN10MB (Ethernet), capture size 262144 bytes
23:29:42.560148 IP 192.168.10.11 > 192.168.0.39: ICMP echo request, id 22340, seq 1, length 64
23:29:42.560161 IP 192.168.0.39 > 192.168.10.11: ICMP echo reply, id 22340, seq 1, length 64
23:29:43.549379 IP 192.168.10.11 > 192.168.0.39: ICMP echo request, id 22340, seq 2, length 64
23:29:43.549394 IP 192.168.0.39 > 192.168.10.11: ICMP echo reply, id 22340, seq 2, length 64
23:29:44.549742 IP 192.168.10.11 > 192.168.0.39: ICMP echo request, id 22340, seq 3, length 64
23:29:44.549756 IP 192.168.0.39 > 192.168.10.11: ICMP echo reply, id 22340, seq 3, length 64
Petit aparté avant de poursuivre : afin de partager la connection Internet, nous aurions pu choisir de mettre en place un pont réseau, c’est-à-dire une interconnection de réseaux de niveau 2 au niveau du Raspberry (donc wlan0 et eth0). Dans ce cas, toutes mes machines connectées sur wlan0 auraient eu une IP en 192.168.0.X attribuée directement par ma box internet. Le serveur DHCP aurait été superflu, de même que le routage NAT. C’est une autre option possible mais qui n’est pas détaillée ici.
Quoiqu’il en soit, regardons comment modifier la NAT pour gérer les machines connectées sur wlan0. Principalement deux solutions existent : la SNAT et l’IP Mascarade. Etant donné que l’IP de mon interface eth0 peut-être définie en statique (via les options du serveur DHCP de ma box Internet), j’ai opté pour la SNAT qui est je pense plus légère.
La commande pour mettre en place la SNAT est la suivante :
$ sudo iptables -t nat -A POSTROUTING -o eth0 -j SNAT --to-source 192.168.0.38
Cette commande demande au Rasberry de modifier sa table NAT (-t nat
), et d’ajouter une nouvelle règle dans la chaîne POSTROUTING (-A POSTROUTING
) pour les paquets s’apprétant à sortir sur son interface eth0 (-o eth0
). Pour ces paquets là, et ces paquets là seulement, on met en place une SNAT (-j SNAT
) et on spécifie que l’IP source du paquet sera celle de l’interface eth0 du Raserry (--to-source 192.168.0.38
).
En clair, cela veut dire que tout paquet qui s’apprête à sortir du Rasberry via son interface eth0 (par exemple le ping du $PC_1$ de tout à l’heure) verra son IP source changée en celle du Raspberry/eth0 et le Raspberry se charge tout seul comme un grand de garder les comptes et, lorsque les paquets retour lui sont adressés, de redispatcher ensuite sur le réseau 192.168.10.0.
Ainsi, après avoir appliqué la règle iptables, refaisons notre manip du ping $PC_1 \to$ Raspberry. Cette fois-ci, on remarque ça marche et que les requêtes reçues par $PC_2$ ne proviennent non plus de $PC_1$ (192.168.10.11) mais du Raspberry (192.168.0.38) !
Terminal de $PC_1$
$ ping -c 3 192.168.0.39 # Terminal de PC_1
PING 192.168.0.39 (192.168.0.39) 56(84) bytes of data.
64 bytes from 192.168.0.39: icmp_seq=1 ttl=64 time=0.469 ms
64 bytes from 192.168.0.39: icmp_seq=2 ttl=64 time=0.521 ms
64 bytes from 192.168.0.39: icmp_seq=3 ttl=64 time=0.534 ms
--- 192.168.0.39 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 0.469/0.508/0.534/0.028 ms
Terminal de $PC_2$
$ sudo tcpdump -p icmp # Terminal de PC_2
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on enp7s0, link-type EN10MB (Ethernet), capture size 262144 bytes
23:29:17.783149 IP 192.168.0.38 > 192.168.0.39: ICMP echo request, id 2107, seq 1, length 64
23:29:17.783160 IP 192.168.0.39 > 192.168.0.38: ICMP echo reply, id 2107, seq 1, length 64
23:29:18.785152 IP 192.168.0.38 > 192.168.0.39: ICMP echo request, id 2107, seq 2, length 64
23:29:18.785171 IP 192.168.0.39 > 192.168.0.38: ICMP echo reply, id 2107, seq 2, length 64
23:29:19.786414 IP 192.168.0.38 > 192.168.0.39: ICMP echo request, id 2107, seq 3, length 64
23:29:19.786437 IP 192.168.0.39 > 192.168.0.38: ICMP echo reply, id 2107, seq 3, length 64
Dernière façon amusante de voir la SNAT en action, nous allons utiliser ncat
. C’est un outil qui permet de mettre en place des sockets réseau très simplement.
Sur notre $PC_2$, nous écoutons sur le port (arbitraire) 52201 via la commande : $ sudo ncat -v -l 52201
.
Sur notre $PC_1$, nous tentons une connection sur ce (mini) serveur via la commande : sudo ncat -v 192.168.0.39 52201
.
Si tout se passe bien, les deux machines se connectent et tout ce qu’on écrit dans le terminal de l’une se retrouvera en miroir dans le terminal de l’autre ! Du côté du client $PC_1$ tout se passe comme si on dialoguait directement avec $PC_2$ d’IP 192.168.0.39 et sur son port 52201. Et comme on s’y attendait, on remarque que $PC_2$ est persuadé de communiquer avec notre Raspberry (d’IP 192.168.0.38, rappelons-le). On comprend désormais mieux le nom d’IP masquerade !
Terminal de $PC_1$ (client)
$ sudo ncat -v 192.168.0.39 52201 # Terminal de PC_1 (client)
found 0 associations
found 1 connections:
1: flags=82<CONNECTED,PREFERRED>
outif en0
src 192.168.10.10 port 64333
dst 192.168.0.39 port 52201
rank info not available
TCP aux info available
Connection to 192.168.0.39 port 52201 [tcp/*] succeeded!
Hello
Coucou
Terminal de $PC_2$ (serveur)
$ sudo ncat -v -l 52201 # Terminal de PC_2 (serveur)
Ncat: Version 7.01 ( https://nmap.org/ncat )
Ncat: Listening on :::52201
Ncat: Listening on 0.0.0.0:52201
Ncat: Connection from 192.168.0.38.
Ncat: Connection from 192.168.0.38:64333.
Hello
Coucou
Bref, tout marche bien dans le meilleur des mondes. Il nous reste néanmoins encore une dernière étape pour iptables : rendre notre régle persistente après un reboot. On va faire ça à l’ancienne avec une démarche à la SystemV. L’intérêt est plus didactique qu’autre chose, vu que je verrai après les scripts d’init systemd, on verra la différence de philosophie ! Si j’ai bien compris de toute façon, c’est systemd qui va gérer notre script systemV en rétro-compatibilité.
La démarche pour SystemV est la suivante. Si je veux créer un nouveau service, je crée un script de lancement dans /etc/init.d/
avec un entête contenant différentes informations comme le runlevel où le service doit être activé et les dépendances (par exemple, pour iptables il faut attendre que le réseau soit activé). Notre script devra également contenir les actions à effectuer lorsqu’on arrête, démarre ou interroge le service. On utilise ensuite la commande update-rc.d mon_service defaults
pour mettre en place le service. Init.d va lire l’entête de notre fichier et placer des liens symboliques dans les différents /etc/rcN.d/
.
Mais dans notre cas, c’est une démarche bien trop lourde : notre commande iptables a vocation à être exécutée une seule fois au démarrage du raspberry. Pour cela, on dispose du script /etc/rc.local/
: il suffit de rajouter notre règle là dedans et le tour est joué !
Voici l’état actuel de notre table NAT :
$ sudo iptables -t nat -L
Chain PREROUTING (policy ACCEPT)
target prot opt source destination
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
SNAT all -- anywhere anywhere to:192.168.0.38
On demande à iptables de sauvegarder l’état actuel des règles dans un fichier de sortie grâce à la commande iptables-save
. Cette commande est optionnelle dans la mesure où notre firewall est pour le moment très simple (une seule règle !) mais bon…
$ sudo sh -c "iptables-save > /etc/iptables.rules"
donut@donutbridge:~$ cat /etc/iptables.rules
# Generated by iptables-save v1.4.21 on Fri Aug 4 07:14:07 2017
*nat
:PREROUTING ACCEPT [18:2088]
:INPUT ACCEPT [18:2088]
:OUTPUT ACCEPT [8:692]
:POSTROUTING ACCEPT [0:0]
-A POSTROUTING -o eth0 -j SNAT --to-source 192.168.0.38
COMMIT
# Completed on Fri Aug 4 07:14:07 2017
# Generated by iptables-save v1.4.21 on Fri Aug 4 07:14:07 2017
*filter
:INPUT ACCEPT [624:77121]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [335:33556]
COMMIT
# Completed on Fri Aug 4 07:14:07 2017
Il nous reste maintenant à ajouter une ligne dans /etc/rc.local/
pour charger notre règle :
# Donut 2017-08-04 : regle iptables pour SNAT wlan0 vers eth0
iptables-restore /etc/iptables.rules
Désormais lorsqu’on redémarre le raspberry, le réseau sera convenablement paramétré pour la SNAT !
Un premier sniffing du réseau
La topologie (simplifiée) de notre réseau est rappelée ci-dessous. Nous allons reprendre l’exemple du serveur minimaliste ncat
de la section précédente afin de voir passer les trames sur le Raspberry. Rappelons que $PC_2$ écoute sur le port 52201 et que $PC_1$ va le contacter. $PC_1$ va envoyer le message “HELLO” auquel le $PC_2$ répondra “COUCOU”.
Les options de notre tcpdump sont les suivantes :
- l’option
-n
impose l’affichage décimal des IP et des ports, - l’option
-X
demande l’affichage hexadécimal et ASCII des trames IP - l’option
-v
de mande à tcpdump d’être plus bavard, en particulier il va décortiquer plus en profondeur le header IP (pour notamment afficher le protocole de niveau supérieur) - l’option
-c N
demande à tcpdump de s’arrêter après avoir reçu N trames - et enfin l’option
-i interface
indique l’interface de capture, par exemple-i wlan0
ou-i any
On peut également spécifier à tcpdump une expression de filtrage comme argument, nous indiquons ici “port not 22 and host 192.168.0.27” qui demande de tout écouter sauf le port 22 (la session ssh qui me permet de piloter le Raspberry) du moment qu’un des interlocuteurs (émetteur ou destinataire) est $PC_2$ (d’IP 192.168.0.27). Pour des raisons de clarté, je ne remets pas les lignes netcat
des clients/serveur mais juste les informations capturées par tcpdump.
Dans un premier temps, on ne capture que la connection entre client et serveur; c’est-à-dire qu’on arrête tcpdump juste après avoir exécuté nc -v 192.168.0.27 52201
sur le $PC_1$. Nous indiquons également à tcpdump de s’arrêter après avoir reçu 3 trames. J’ai remarqué que l’option -i any
rencontrait quelques difficultés pour capturer le tout premier paquet. J’ai donc executé la même commande sur deux shells différents : l’une avec l’option -i wlan0
et l’autre avec l’option -i eth0
. J’ai rajouté un grep ensuite pour ne garder que le header de chaque trame.
Nous obtenons le résultat suivant. Il y a plein de choses à en dire !
Tout d’abord, si on regarde bien, on se rend compte que chaque trame IP est dupliquée. La toute première trame IP est sur l’interface wlan0 et les correspondants sont 192.168.10.10.54064 > 192.168.0.27.52201. On voit que le raspberry émet aussitôt une trame sur sont interface eth0 dont les correpondants sont 192.168.0.38.54064 > 192.168.0.27.52201. Cette comparaison met en évidence le mécanisme de NAT : $PC_2$ cherche à contacter $PC_1$ sur son port 52201, il indique aussi son port de retour (ici 54064). Le Raspberry a modifié l’IP source en sa propre IP (ainsi 192.168.10.10 devient 192.168.0.38), le port source quant à lui n’a pas changé.
Par ailleurs, si on regarde l’entête de chaque trame (enrichi rappelons-le grâce à l’option -v
de tcpdump) on remarque que le protocole de niveau supérieur est le TCP. On s’en rend compte également quand on remarque que les trois premières trames échangées (le -n 3
n’était pas choisi au hasard) ont le flag [S]
, [S.]
et enfin [.]
. Cela correspond aux trois indicateurs SYN, SYN-ACK et ACK qui constituent la fameuse triple poignée de main d’une ouverture de connexion TCP.
$ sudo tcpdump -n -X -c 3 -i wlan0 -v host 192.168.0.27 | grep -A 1 IP
08:53:19.542053 IP (tos 0x0, ttl 64, id 35611, offset 0, flags [DF], proto TCP (6), length 64)
192.168.10.10.54064 > 192.168.0.27.52201: Flags [S], cksum 0xb9ce (correct), seq 1191224222, win 65535, options [mss 1460,nop,wscale 5,nop,nop,TS val 1045703083 ecr 0,sackOK,eol], length 0
08:53:19.543017 IP (tos 0x0, ttl 63, id 0, offset 0, flags [DF], proto TCP (6), length 60)
192.168.0.27.52201 > 192.168.10.10.54064: Flags [S.], cksum 0xd86f (correct), seq 3811497698, ack 1191224223, win 28960, options [mss 1460,sackOK,TS val 11781739 ecr 1045703083,nop,wscale 7], length 0
08:53:19.546340 IP (tos 0x0, ttl 64, id 46676, offset 0, flags [DF], proto TCP (6), length 52)
192.168.10.10.54064 > 192.168.0.27.52201: Flags [.], cksum 0x6840 (correct), ack 1, win 4117, options [nop,nop,TS val 1045703090 ecr 11781739], length 0
$ sudo tcpdump -n -X -c 3 -i eth0 -v port not 22 and host 192.168.0.27 | grep -A 1 IP
08:53:19.542387 IP (tos 0x0, ttl 63, id 35611, offset 0, flags [DF], proto TCP (6), length 64)
192.168.0.38.54064 > 192.168.0.27.52201: Flags [S], cksum 0xc3b2 (correct), seq 1191224222, win 65535, options [mss 1460,nop,wscale 5,nop,nop,TS val 1045703083 ecr 0,sackOK,eol], length 0
08:53:19.542874 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 60)
192.168.0.27.52201 > 192.168.0.38.54064: Flags [S.], cksum 0xe253 (correct), seq 3811497698, ack 1191224223, win 28960, options [mss 1460,sackOK,TS val 11781739 ecr 1045703083,nop,wscale 7], length 0
08:53:19.546498 IP (tos 0x0, ttl 63, id 46676, offset 0, flags [DF], proto TCP (6), length 52)
192.168.0.38.54064 > 192.168.0.27.52201: Flags [.], cksum 0x7224 (correct), ack 1, win 4117, options [nop,nop,TS val 1045703090 ecr 11781739], length 0
Bref tout ceci est plutôt positif. Regardons maintenant si nous pouvons, via tcpdump, récupérer les informations échangées entre $PC_1$ et $PC_2$. Ecouter sur les deux interfaces eth0 et wlan0 n’avait qu’un but didactique pour voir la SNAT en action, nous nous restreindrons désormais à la seule interface wlan0. Voici donc ce qu’on obtient lorsque $PC_1$ envoie le message “HELLO” auquel le $PC_2$ répond “COUCOU”.
Nous retrouvons bien au début notre triple poignée de main, suivie de deux messages avec leur acquittement. On remarque que les chaînes “HELLO” et “COUCOU” apparaissent bien en clair sur la sortie de tcpdump et qu’elles sont en fin de trame IP.
$ sudo tcpdump -n -X -v -i wlan0 host 192.168.0.27
tcpdump: listening on wlan0, link-type EN10MB (Ethernet), capture size 262144 bytes
13:48:51.967582 IP (tos 0x0, ttl 64, id 15450, offset 0, flags [DF], proto TCP (6), length 64)
192.168.10.10.54265 > 192.168.0.27.52201: Flags [S], cksum 0x464a (correct), seq 4251772336, win 65535, options [mss 1460,nop,wscale 5,nop,nop,TS val 1063428825 ecr 0,sackOK,eol], length 0
0x0000: 4500 0040 3c5a 4000 4006 72e8 c0a8 0a0a E..@<Z@.@.r.....
0x0010: c0a8 001b d3f9 cbe9 fd6c e5b0 0000 0000 .........l......
0x0020: b002 ffff 464a 0000 0204 05b4 0103 0305 ....FJ..........
0x0030: 0101 080a 3f62 a2d9 0000 0000 0402 0000 ....?b..........
13:48:51.969090 IP (tos 0x0, ttl 63, id 0, offset 0, flags [DF], proto TCP (6), length 60)
192.168.0.27.52201 > 192.168.10.10.54265: Flags [S.], cksum 0xcfe8 (correct), seq 820279578, ack 4251772337, win 28960, options [mss 1460,sackOK,TS val 16214845 ecr 1063428825,nop,wscale 7], length 0
0x0000: 4500 003c 0000 4000 3f06 b046 c0a8 001b E..<..@.?..F....
0x0010: c0a8 0a0a cbe9 d3f9 30e4 791a fd6c e5b1 ........0.y..l..
0x0020: a012 7120 cfe8 0000 0204 05b4 0402 080a ..q.............
0x0030: 00f7 6b3d 3f62 a2d9 0103 0307 ..k=?b......
13:48:51.971944 IP (tos 0x0, ttl 64, id 37412, offset 0, flags [DF], proto TCP (6), length 52)
192.168.10.10.54265 > 192.168.0.27.52201: Flags [.], cksum 0x5fb8 (correct), ack 1, win 4117, options [nop,nop,TS val 1063428833 ecr 16214845], length 0
0x0000: 4500 0034 9224 4000 4006 1d2a c0a8 0a0a E..4.$@.@..*....
0x0010: c0a8 001b d3f9 cbe9 fd6c e5b1 30e4 791b .........l..0.y.
0x0020: 8010 1015 5fb8 0000 0101 080a 3f62 a2e1 ...._.......?b..
0x0030: 00f7 6b3d ..k=
13:48:58.172315 IP (tos 0x0, ttl 64, id 52612, offset 0, flags [DF], proto TCP (6), length 58)
192.168.10.10.54265 > 192.168.0.27.52201: Flags [P.], cksum 0x63df (correct), seq 1:7, ack 1, win 4117, options [nop,nop,TS val 1063435024 ecr 16214845], length 6
0x0000: 4500 003a cd84 4000 4006 e1c3 c0a8 0a0a E..:..@.@.......
0x0010: c0a8 001b d3f9 cbe9 fd6c e5b1 30e4 791b .........l..0.y.
0x0020: 8018 1015 63df 0000 0101 080a 3f62 bb10 ....c.......?b..
0x0030: 00f7 6b3d 4845 4c4c 4f0a ..k=HELLO.
13:48:58.173811 IP (tos 0x0, ttl 63, id 4645, offset 0, flags [DF], proto TCP (6), length 52)
192.168.0.27.52201 > 192.168.10.10.54265: Flags [.], cksum 0x50a6 (correct), ack 7, win 227, options [nop,nop,TS val 16216396 ecr 1063435024], length 0
0x0000: 4500 0034 1225 4000 3f06 9e29 c0a8 001b E..4.%@.?..)....
0x0010: c0a8 0a0a cbe9 d3f9 30e4 791b fd6c e5b7 ........0.y..l..
0x0020: 8010 00e3 50a6 0000 0101 080a 00f7 714c ....P.........qL
0x0030: 3f62 bb10 ?b..
13:49:02.396522 IP (tos 0x0, ttl 63, id 4646, offset 0, flags [DF], proto TCP (6), length 60)
192.168.0.27.52201 > 192.168.10.10.54265: Flags [P.], cksum 0x4084 (correct), seq 1:9, ack 7, win 227, options [nop,nop,TS val 16217452 ecr 1063435024], length 8
0x0000: 4500 003c 1226 4000 3f06 9e20 c0a8 001b E..<.&@.?.......
0x0010: c0a8 0a0a cbe9 d3f9 30e4 791b fd6c e5b7 ........0.y..l..
0x0020: 8018 00e3 4084 0000 0101 080a 00f7 756c ....@.........ul
0x0030: 3f62 bb10 2443 4f55 434f 550a ?b..$COUCOU.
13:49:02.604305 IP (tos 0x0, ttl 63, id 4647, offset 0, flags [DF], proto TCP (6), length 60)
192.168.0.27.52201 > 192.168.10.10.54265: Flags [P.], cksum 0x4050 (correct), seq 1:9, ack 7, win 227, options [nop,nop,TS val 16217504 ecr 1063435024], length 8
0x0000: 4500 003c 1227 4000 3f06 9e1f c0a8 001b E..<.'@.?.......
0x0010: c0a8 0a0a cbe9 d3f9 30e4 791b fd6c e5b7 ........0.y..l..
0x0020: 8018 00e3 4050 0000 0101 080a 00f7 75a0 ....@P........u.
0x0030: 3f62 bb10 2443 4f55 434f 550a ?b..$COUCOU.
13:49:02.683637 IP (tos 0x0, ttl 64, id 61743, offset 0, flags [DF], proto TCP (6), length 52)
192.168.10.10.54265 > 192.168.0.27.52201: Flags [.], cksum 0x2bb0 (correct), ack 9, win 4117, options [nop,nop,TS val 1063439532 ecr 16217452], length 0
0x0000: 4500 0034 f12f 4000 4006 be1e c0a8 0a0a E..4./@.@.......
0x0010: c0a8 001b d3f9 cbe9 fd6c e5b7 30e4 7923 .........l..0.y#
0x0020: 8010 1015 2bb0 0000 0101 080a 3f62 ccac ....+.......?b..
0x0030: 00f7 756c ..ul
13:49:02.683664 IP (tos 0x0, ttl 64, id 44468, offset 0, flags [DF], proto TCP (6), length 52)
192.168.10.10.54265 > 192.168.0.27.52201: Flags [.], cksum 0x2b7c (correct), ack 9, win 4117, options [nop,nop,TS val 1063439532 ecr 16217504], length 0
0x0000: 4500 0034 adb4 4000 4006 019a c0a8 0a0a E..4..@.@.......
0x0010: c0a8 001b d3f9 cbe9 fd6c e5b7 30e4 7923 .........l..0.y#
0x0020: 8010 1015 2b7c 0000 0101 080a 3f62 ccac ....+|......?b..
0x0030: 00f7 75a0 ..u.
Maintenant que nous maîtrisons bien la manipulation de tcpdump, passons à l’espionnage de la balance !
Sniffing de la balance
Rappelons le fonctionnement de la balance :
- quand je me pèse, mon poids s’affiche sur la balance (normal),
- après un court instant, la balance me reconnaît et affiche mes initiales sur son écran,
- régulièrement, la balance mesure le taux de CO2 dans l’air
A ce stade, je me pose plusieurs questions :
- Est-ce que la balance chiffre ses données lorsqu’elle communique avec l’extérieur ? Si c’est le cas, toute mon opération tombe à l’eau !
- Est-ce que la transmission du poids est synchrone avec le moment où je me pèse ? Existe-t’il un délai ?
- A quelle fréquence est-ce que le taux de CO2 est-il mesuré ?
- Est-ce une communication unilatérale ou bien la balance attend-elle un retour du serveur ?
- En particulier, à quel endroit (côté balance ou côté serveur) s’effectue l’identification entre un poids et une personne ?
Il faudra garder tout ça en tête lorsqu’on regardera les trames…
Pour épurer au maximum les trames, je coupe la connexion WiFi de $PC_1$ et je vérfie que je ne le vois plus dans les associations de Hostapd :
$ sudo hostapd_cli all_sta
Selected interface 'wlan0'
9c:f3:87:aa:fe:62
flags=[AUTH][ASSOC][AUTHORIZED]
aid=0
capability=0x0
listen_interval=0
supported_rates=
timeout_next=NULLFUNC POLL
dot11RSNAStatsSTAAddress=9c:f3:87:aa:fe:62
dot11RSNAStatsVersion=1
dot11RSNAStatsSelectedPairwiseCipher=00-0f-ac-4
dot11RSNAStatsTKIPLocalMICFailures=0
dot11RSNAStatsTKIPRemoteMICFailures=0
hostapdWPAPTKState=11
hostapdWPAPTKGroupState=0
rx_packets=0
tx_packets=0
rx_bytes=0
tx_bytes=0
connected_time=20612
[ON COUPE LE WIFI DE PC_1]
$ sudo hostapd_cli all_sta
Selected interface 'wlan0'
Alors voici les trames intéressantes qui sont survenues juste après la pesée. Je remarque au passage que l’association poids-personne se fait vraisemblablement AVANT l’envoi d’une trame…
Tout d’abord, notre balance d’adresse MAC 00:24:e4:0d:34:38 se réveille et demande une IP à la cantonade. Notre serveur DHCP lui en servira une.
14:09:27.665777 IP (tos 0x0, ttl 255, id 0, offset 0, flags [none], proto UDP (17), length 328)
0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, Request from 00:24:e4:0d:34:38, length 300, xid 0x343606f7, Flags [none]
Peu après, notre balance qui a obtenu l’IP 192.168.10.12 demande à notre box internet quelle est l’IP du serveur wbs02-ws.withings.net. Notre box lui répond que ce serveur est accessible à l’adresse 89.30.121.150. Si on est parano, on peut contrôler que c’est bien correct grâce à la commande dig
qui permet de faire des requêtes dns. Vraisemblablement, ce sera avec ce serveur que la balance va communiquer, retenons donc cette adresse elle sera sans doute utile dans la suite.
14:09:28.627479 IP (tos 0x0, ttl 255, id 2, offset 0, flags [none], proto UDP (17), length 67)
192.168.10.12.49153 > 192.168.0.254.53: 0+ A? wbs02-ws.withings.net. (39)
[...]
14:09:28.628502 IP (tos 0x0, ttl 63, id 38040, offset 0, flags [DF], proto UDP (17), length 112)
192.168.0.254.53 > 192.168.10.12.49153: 0 2/0/0 wbs02-ws.withings.net. CNAME ws.withings.net., ws.withings.net. A 89.30.121.150 (84)
$ dig wbs02-ws.withings.net
; <<>> DiG 9.10.3-P4-Ubuntu <<>> wbs02-ws.withings.net
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 35231
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;wbs02-ws.withings.net. IN A
;; ANSWER SECTION:
wbs02-ws.withings.net. 926 IN CNAME ws.withings.net.
ws.withings.net. 1561 IN A 89.30.121.150
;; Query time: 0 msec
;; SERVER: 127.0.1.1#53(127.0.1.1)
;; WHEN: Sun Aug 06 14:19:31 CEST 2017
;; MSG SIZE rcvd: 95
Les trois trames suivantes sont la triple poignée de main TCP avec le serveur 89.30.121.150. On se rend compte que la balance communique bien en TCP avec son serveur et pas en UDP comme je l’espérais… Mais pire, on remarque que le port de destination est le 443 et ça correspond à de l’https, autrement dit un port http sécurisé et chiffré… Je ne risque donc hélas pas de voir passer en clair les informations de ma balance.
14:09:28.649462 IP (tos 0x0, ttl 255, id 3, offset 0, flags [none], proto TCP (6), length 44)
192.168.10.12.49153 > 89.30.121.150.443: Flags [S], cksum 0xe961 (correct), seq 672401143, win 8400, options [mss 1400], length 0
0x0000: 4500 002c 0003 0000 ff06 1e60 c0a8 0a0c E..,.......`....
0x0010: 591e 7996 c001 01bb 2814 06f7 0000 0000 Y.y.....(.......
0x0020: 6002 20d0 e961 0000 0204 0578 `....a.....x
14:09:28.651938 IP (tos 0x0, ttl 48, id 0, offset 0, flags [DF], proto TCP (6), length 44)
89.30.121.150.443 > 192.168.10.12.49153: Flags [S.], cksum 0xd24f (correct), seq 3580817429, ack 672401144, win 29200, options [mss 1460], length 0
0x0000: 4500 002c 0000 4000 3006 ad63 591e 7996 E..,..@.0..cY.y.
0x0010: c0a8 0a0c 01bb c001 d56e f015 2814 06f8 .........n..(...
0x0020: 6012 7210 d24f 0000 0204 05b4 `.r..O......
14:09:28.684596 IP (tos 0x0, ttl 255, id 4, offset 0, flags [none], proto TCP (6), length 40)
192.168.10.12.49153 > 89.30.121.150.443: Flags [.], cksum 0x3b4d (correct), ack 1, win 8400, length 0
0x0000: 4500 0028 0004 0000 ff06 1e63 c0a8 0a0c E..(.......c....
0x0010: 591e 7996 c001 01bb 2814 06f8 d56e f016 Y.y.....(....n..
0x0020: 5010 20d0 3b4d 0000
Pour tout n’est pas perdu pour autant mais l’affaire se complique drôlement… Le petit espoir que j’ai est que la balance ne semble communiquer qu’avec 89.30.121.150. En particulier, cela signifie qu’elle n’effectue jamais de demande OCSP à l’autorité tierce qui aurait donné son certificat à 89.30.121.150. Autrement dit, le serveur wbs02-ws.withings.net signe lui même son certificat.
Pistes pour continuer
Ajout d’un DNAT pour faire pointer les requêtes HTTPS vers un serveur local
$ sudo iptables -t nat -A PREROUTING -i wlan0 -p tcp --dst 89.30.121.150 --dport 443 -j DNAT --to-destination 192.168.0.27:443
$ sudo iptables -t nat -L
Chain PREROUTING (policy ACCEPT)
target prot opt source destination
DNAT tcp -- anywhere 89.30.121.150 tcp dpt:https to:192.168.0.27:443
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
SNAT all -- anywhere anywhere to:192.168.0.38
Serveur HTTPS sur ma machine 192.168.0.38 :
$ sudo ncat -v --ssl -l 443
Ncat: Version 7.01 ( https://nmap.org/ncat )
Ncat: Generating a temporary 1024-bit RSA key. Use --ssl-key and --ssl-cert to use a permanent one.
Ncat: SHA-1 fingerprint: 4912 450C 3AA7 782D AAFC BA0B 6842 BABB 2C2B 16C8
Ncat: Listening on :::443
Ncat: Listening on 0.0.0.0:443
Ncat: Connection from 192.168.0.38.
Ncat: Connection from 192.168.0.38:49153.
Ncat: Failed SSL connection from 192.168.0.38: error:1408F119:SSL routines:SSL3_GET_RECORD:decryption failed or bad record mac
On cherche le certificat
$ echo 'Q' | openssl s_client -connect wbs02-ws.withings.net:443 > withings_raw.cert
$ cat withings_raw.cert | sed -n '/BEGIN/,/END/p' > withings.cert
-
nous étions en 2017 ↩