Suite mais pas fin de l’article [1/3] – Analyser le traffic d’un smartphone (le hotspot WIFI).
Ici nous allons voir comment enregistrer les paquets de données qui transitent sur votre hotspot. Vous comprendrez vite que l’écran et les boutons sont facultatifs, il ne font qu’appel à des lignes de commande qui peuvent être lancer depuis le terminal du Raspberry en session SSH.
Installation des paquets
Nous allons installer un petit utilitaire réseau très pratique et bien connu des bricoleurs réseau (et accessoirement des petits curieux que les gens on l’habitude d’appeler les PIRATE INFORMATIQUES ! Ouuuhh ! ), j’ai nommé tcpdump
sudo apt-install tcpdump
Et voila, c’est fini !
Enregistrement des paquets
Donc nous imaginons que votre Raspberry est branché, le hotspot est accessible et vous y avais connecté votre superbe smartphone chinois dessus.
Lancer la commande
sudo tcpdump -i wlan0 -s 0 -p
Même sans naviguer sur Internet avec votre smartphone, un certain nombre de lignes devraient apparaître dans votre terminal. Si ce n’est pas le cas, couper la couper avec Ctrl+c puis relancez la en remplaçant wlan0 par Br0.
Les lignes qui défilent correspondent aux paquets échangé entre le smartphone et la box et potentiellement avec Internet. En l’état, ce n’est pas réellement exploitable. Ajoutons donc un paramètre pour enregistrer ce résultats dans un fichier :
sudo tcpdump -i wlan0 -s 0 -p -w mon_tcpdump.pcap
Maintenant, faites-vous un café et naviguer sur votre smartphone à votre guise : application, réseaux sociaux, sites internet…
Je vous conseille de naviguer également sur une site qui n’est pas en https mais en http simple (sans le petit cadenas). Nous verrons dans le troisième volet de cet article le côté pédagogique de cette expérience en http !
Tant que le script n’est pas interrompu par Ctrl+c, tcpdump enregistre les paquets dans le fichier. Attention, en fonction de la navigation, le poids du fichier peut monter trèèèès vite (dites vous juste que les paquets enregistrés représentent l’intégralité de votre navigation, si vous téléchargez un fichier de 10 Mo, il y aura environ 10 Mo de paquets…)
Couper l’exécution du script au bout de quelques minutes, ça suffit pour le moment. Nous avons dorénavant un super fichier .pcap de l’ensemble de la navigation.
A noter qu’il s’agit de l’ensemble des paquets transitant sur le bridge du Raspberry, donc si vous avez connecté un deuxième périphérique dessus, votre fichier ne contiendra pas que vos résultats ! On verra lors de l’analyse qu’il est facile de filtrer ce que l’on souhaite.
Rendre le Raspberry autonome
C’est quand même plus sympa de pouvoir interagir directement avec le Raspberry sans avoir à y brancher un écran et un clavier ou même d’y accéder en SSH via un autre PC.
C’est ici qu’intervient le petit écran LCD et quelques boutons poussoirs. A noter que n’importe quel autre système indicateur peux convenir (une led verte, une led rouge et un bouton par exemple peuvent fair le job : vert quand c’est prêt à enregistrer, rouge quand ça enregistre, et juste un bouton pour lancer/stopper les enregistrements).

Ce que je vous propose c’est au moins 4 boutons.
- Un bouton pour faire afficher l’adresse ip du Raspberry
- Un bouton pour lancer l’enregistrement
- Un bouton pour stopper l’enregistrement
- Un bouton pour éteindre proprement le Raspberry
L’écran LCD va afficher :
- Les statuts du Raspberry (en attente, en enregistrement…)
- Son adresse ip
- Le poids du fichier en cours d’enregistrement (toujours utile pour pas exploser la carte SD…)
Installation des paquets pour gérer les GPIO
sudo apt-get install i2c-tools sudo apt-get install python-smbus pip install RPi.GPIO # Si vous avez une erreur car pip n'est pas installer, exécutez sudp apt-get install python3-pip
Vérifier si les modules de communication sont bien actifs
lsmod | grep i2c_ lsmod | grep spi_
Ces deux commandes doivent vous retourner un résultat positif, si ce n’est pas le cas, activer les modules i2c et spi via le menu principal
sudo raspi-config # Et rebooter le Raspberry sudo reboot
Le programme principal
Créer un fichier dump.py
nano dump.py
et coller le code ci-dessous (alors oui il fonctionne mais je sais qu’il y a pas mal de coquilles, je l’ai fait en mode YOLO, je le mettrai à jour dès que je peux).
import smbus import time import os import signal import subprocess import RPi.GPIO as GPIO # Import Raspberry Pi GPIO library from datetime import datetime # GPIO GPIO.setmode(GPIO.BCM) GPIO.setup(23, GPIO.IN, pull_up_down=GPIO.PUD_UP) #Button to GPIO23 GPIO.setup(24, GPIO.IN, pull_up_down=GPIO.PUD_UP) #Button to GPIO24 GPIO.setup(25, GPIO.IN, pull_up_down=GPIO.PUD_UP) #Button to GPIO25 GPIO.setup(18, GPIO.IN, pull_up_down=GPIO.PUD_UP) #Button to GPIO18 # Define some device parameters I2C_ADDR = 0x27 # I2C device address LCD_WIDTH = 16 # Maximum characters per line # Define some device constants LCD_CHR = 1 # Mode - Sending data LCD_CMD = 0 # Mode - Sending command LCD_LINE_1 = 0x80 # LCD RAM address for the 1st line LCD_LINE_2 = 0xC0 # LCD RAM address for the 2nd line LCD_LINE_3 = 0x94 # LCD RAM address for the 3rd line LCD_LINE_4 = 0xD4 # LCD RAM address for the 4th line LCD_BACKLIGHT = 0x08 # On #LCD_BACKLIGHT = 0x00 # Off ENABLE = 0b00000100 # Enable bit # Timing constants E_PULSE = 0.0005 E_DELAY = 0.0005 #Open I2C interface #bus = smbus.SMBus(0) # Rev 1 Pi uses 0 bus = smbus.SMBus(1) # Rev 2 Pi uses 1 def lcd_init(): # Initialise display lcd_byte(0x33,LCD_CMD) # 110011 Initialise lcd_byte(0x32,LCD_CMD) # 110010 Initialise lcd_byte(0x06,LCD_CMD) # 000110 Cursor move direction lcd_byte(0x0C,LCD_CMD) # 001100 Display On,Cursor Off, Blink Off lcd_byte(0x28,LCD_CMD) # 101000 Data length, number of lines, font size lcd_byte(0x01,LCD_CMD) # 000001 Clear display time.sleep(E_DELAY) def lcd_byte(bits, mode): # Send byte to data pins # bits = the data # mode = 1 for data # 0 for command bits_high = mode | (bits & 0xF0) | LCD_BACKLIGHT bits_low = mode | ((bits<<4) & 0xF0) | LCD_BACKLIGHT # High bits bus.write_byte(I2C_ADDR, bits_high) lcd_toggle_enable(bits_high) # Low bits bus.write_byte(I2C_ADDR, bits_low) lcd_toggle_enable(bits_low) def lcd_toggle_enable(bits): # Toggle enable time.sleep(E_DELAY) bus.write_byte(I2C_ADDR, (bits | ENABLE)) time.sleep(E_PULSE) bus.write_byte(I2C_ADDR,(bits & ~ENABLE)) time.sleep(E_DELAY) def lcd_string(message,line): # Send string to display message = message.ljust(LCD_WIDTH," ") lcd_byte(line, LCD_CMD) for i in range(LCD_WIDTH): lcd_byte(ord(message[i]),LCD_CHR) def print_file(): w = subprocess.check_output("du -sh tcpdump.pcap", shell=True); w = w.split() lcd_string("File : " + w[0],LCD_LINE_2) def main(): # Main program block # Initialise display lcd_init() # Variables cap = False # 'sudo tcpdump -v -i wlan0 -s 0 -p -w tcpdump.pcap' lcd_string("Wait for command",LCD_LINE_1) while True: button_state_stop = GPIO.input(23) button_state_run = GPIO.input(24) button_state_ip = GPIO.input(25) button_state_poweroff = GPIO.input(18) if button_state_poweroff == False and cap == False: lcd_string("Go to sleep",LCD_LINE_1) lcd_string("Bye bye ! ",LCD_LINE_1) time.sleep(2) subprocess.check_output("sudo shutdown -h now", shell=True); time.sleep(1) break if button_state_ip == False and cap == False: ip = subprocess.check_output("ip -4 addr show br0 | grep -oP '(?<=inet\s)\d+(\.\d+){3}'", shell=True); lcd_string("IP address : ",LCD_LINE_1) lcd_string(str(ip),LCD_LINE_2) if button_state_run == False and cap == False: now = datetime.now() dt_string = now.strftime("%Y%m%d-%H%M%S") lcd_string("Run capture now!",LCD_LINE_1) pro = subprocess.Popen('sudo tcpdump -i wlan0 -s 0 -p -w ' + dt_string +'_tcpdump.pcap', stdout=subprocess.PIPE, shell=True, preexec_fn=os.setsid) cap = True time.sleep(2) if button_state_stop == False and cap == True: lcd_string("Stop capture",LCD_LINE_1) os.killpg(os.getpgid(pro.pid), signal.SIGTERM) if cap == True else lcd_string("Erreur",LCD_LINE_1)# Send the signal to all the process groups cap = False time.sleep(1) subprocess.check_output("mv " + dt_string + "_tcpdump.pcap /var/www/html/", shell=True); else: if cap == True: w = subprocess.check_output("du -sh " + dt_string + "_tcpdump.pcap", shell=True); w = w.split() lcd_string("File : " + w[0],LCD_LINE_2) time.sleep(0.5) exit() if __name__ == '__main__': try: main() except KeyboardInterrupt: pass finally: lcd_byte(0x01, LCD_CMD)
Le câblage
A faire…
