1. Introduction

Aujourd’hui, en Suisse, 95% des foyers possèdent une connexion internet qu’ils payent mensuellement auprès de leur opérateur. Ils s’assurent d’avoir une connexion internet adéquate dans toute leur maison de façon à ce que tous les habitants puissent avoir du réseau n’ importe où et n’importe quand. Mais comment être certain que les habitants de ce foyer sont les seuls à utiliser ce réseau? N’y aurait-il pas un imposteur qui se servirait de cette connexion internet quotidiennement? Le moyen de résoudre ce problème serait de savoir à tout moment quels sont les appareils connectés sur le réseau et recevoir une notification lorsque un utilisateur étranger s’y connecte.

2. Matériel et méthodes

Peu de matériel est nécessaire à la réalisation de ce projet.

2.1 Matériel

  • Un RaspBerry pi
  • Un routeur
  • Un appareil extérieur qui permettrait d'accéder au site web (connexion internet requise)

2.2. Méthode

Mon projet à pour but de faciliter la surveillance de son propre réseau internet. Tout d’abord lorsqu’un appareil se connecte à internet, celui-ci passe par un routeur. Le routeur lui attribue une adresse IP unique qui va lui permettre de se connecter à internet. Je vais ensuite utiliser l'outil de scan "nmap" depuis le RPi afin de pouvoir voir qui se trouve sur le réseau. Ensuite je vais devoir attribuer un nom au différentes machines de manière à identifier les différents appareils. Le RPi va générer une page web qui me permettra de pouvoir voir à tout moment qui utilise le réseau et lorsque une machine n'est pas répertoriée le RPi m'enverra une alerte au moyen d'un email. Il est bien sûr envisageable de trouver d'autre moyen d'alerte.

2.2.1. Mise en place et scan Nmap

Tout d'abord il va falloir installer l'outil principal à la réalisation de ce projet : nmap. Linux est la plateforme la plus communément utilisé pour exécuter ce software, et par conséquent fonctionne parfaitement sous le système d'exploitation Raspbian. Nmap est un scanneur de port libre, il permet de récupérer des informations diverses et variées mais néanmoins précises, sur les différents ports ouverts d'une machine connectée. Nmap peut aussi collecter des informations plus approfondies notamment le système d'exploitation de la machine spécifiée. Le but est de pouvoir vérifier la sécurité de nos machines et de détecter d'éventuelles failles de sécurités via les ports ouverts. Pour cela, nmap envoie des "packets" et récolte les informations que ces "packets" renvoient. L'installation de nmap est très simple il suffit de taper dans une fenêtre du terminal la ligne suivante :

sudo apt-get install nmap

Pour mon projet il faut que je scan toutes les machines qui sont sur le réseau et je dois obtenir leur adresse MAC. J'utilise alors la requête :

nmap -sP 192.168.1.*

Le -sP signifie ping scan et "*" est l'équivalent de noter 0-255 qui signifie explicitement de scanner toutes les adresses du réseau. L'adresse MAC s'obtient uniquement lorsque cette commande est exécutée en tant que super utilisateur. Si vous n'êtes pas en super utilisateur il faut essayer :

sudo nmap -sP 192.168.1.*

Voilà maintenant, nous parvenons à connaître toutes les machines présentes sur notre réseau.

2.2.2. Répertorier les machines connues

Maintenant que nous pouvons voir les différentes machines sur notre réseau, il est nécessaire d'identifier les machines connues autrement dit, qui ont l'autorisation d'être sur le réseau. Pour cela, j'ai "manuellement" configurer un fichier avec toutes les adresses MAC des machines connues. Mon routeur est un routeur swisscom, j'ai donc été voir toutes les machines répertoriées en tapant "192.168.1.1"dans la barre de recherche et j'ai pu me connecter à l'interface que propose swisscom afin de gérer son routeur. J'ai pu ensuite voir les différentes machines et j'ai créé un fichier qui s'appelle SCAN_BRUT qui contient toutes les adresses MAC qui ont été vérifiées. Le fichier s'appelle SCAN_BRUT car je me suis facilité la tâche en faisant un scan nmap un jour de haute activité sur le réseau et je l'ai ensuite comparé avec les adresses qui se trouvaient sur le routeur pour être sur d'avoir les bonnes machines.

nmap -sP 192.168.1.* > SCAN_BRUT

2.2.3. Créer des fichiers de MAC adresse

J'ai pensé à créer différentes listes de MAC adresse avec python afin de les comparer facilement. Pour cela, j'ai du créer des fichier avec uniquement les adresses MAC. J'ai créé deux fichier, le premier "SCAN_BRUT" qui contient toutes les adresses connues et le deuxième "SCAN_MAC" qui résulte d'un scan nmap que mon fichier python exécute. Pour pouvoir créer des listes avec uniquement les MAC adresses j'ai du utiliser la fonction magic du terminal "grep" qui permet de séléctionner toutes les lignes qui contiennent l'attribut que nous lui avons donner ( ici "MAC" ). Pour le fichier SCAN_MAC j'ai donc :

nmap -sP 192.168.1.* | grep MAC > SCAN_MAC

Ceci ne suffit pas. Avec cette requête j'obtiens la ligne entière où se trouve l'adresse MAC alors qu'il me faut uniquement l'adresse. Il faut encore affiner la requête et on obtiens :

nmap -sP 192.168.1.* | grep MAC | cut -c 14-30 > SCAN_MAC

La fonction "cut" nous permet de sélectionner précisément les caractères que nous voulons. Grâce à cela j'obtiens un fichier composés purement de MAC adresse en une seule colonne. J'aurais pu rentrer à la main dans un fichier toutes les adresses connues mais j'ai préféré faire :

grep MAC SCAN_BRUT | cut -c 14-30 > MAC_TOTAL

ce qui me créé un fichier à partir du scan brut et me donne un fichier avec seulement les adresses connues. Dans mon programme, pour que je puisse exécuter ces commandes dans le terminal je dois importer le module "os" et grâce à la fonction "os.system" je peux créer mes fichiers en utilisant nmap :

import os
os.system("nmap -sP -n 192.168.1.* | grep MAC | cut -c 14-30 > SCAN_MAC")
os.system("grep MAC SCAN_BRUT | cut -c 14-30 > MAC_TOTAL")

2.2.4. Configurer les fichiers en listes

Afin d'insérer le contenu d'un fichier dans une liste, il faut l'ouvrir puis le lire avec les fonctions "open" et "read" respectivement. Imaginons notre fichier se trouve dans /root/Desktop/MAC_TOTAL et que nous appelons notre liste "list_total" on a :

list_total = open('/root/Desktop/MAC_TOTAL').read().splitlines()

La fonction "splitlines" permet de séparer les valeurs que va contenir notre liste par rapport aux différentes lignes de notre fichier. J'ai créé une deuxième liste qui s'appelle "list_scan" et qui contient toutes les adresses MAC scannées.

Avant d'avoir configuré mes fichiers en liste j'ai essayé les modules "filecmp" pour la comparaison de fichier mais je ne suis pas arrivé à un résultat qui me convenait. J'ai aussi essayé "difflib" mais en vain, ces deux modules comparent les fichiers de façon beaucoup plus avancée qu'il ne me faut. Je suis alors tombé sur le module de "sets" qui sert à faire des opérations mathématiques, notamment en utilisant des listes. Le problème à résoudre était de savoir si "list_scan" se trouvait dans "list_total". Si c'était le cas, alors il n'y a pas d'intru et dans le cas contraire, me donner l'adresse MAC de l'intru en question. Je m'y suis pris de la façon suivante :

from sets import Set

#   transforme les listes en sets pour pouvoir les comparer
list_total = Set (open('/root/Desktop/MAC_TOTAL').read().splitlines())     
list_scan = Set (open('/root/Desktop/SCAN_MAC').read().splitlines())

intru = list_scan - list_total     #   la différence de list_scan par rapport a list_total

if intru == Set() :
 print ("pas d'intru")
else:
 print (intru)

2.2.5. Who's Home?

Pour savoir à tout moment qui est à la maison j'ai pensé à quelque chose de simple, attribuer des noms aux machines principales des habitants et voir si elles se trouvent dans le scan. J'ai choisis de prendre les adresses MAC des téléphones portables :

robin_galaxy = 'B0:72:BF:C6:FC:B3'
zoe_galaxy = '04:D6:AA:OD:08:52'
abdul_galaxy ='04:D6:AA:62:DC:96'
carole_iphone = '48:4B:AA:D5:A0:07'

J'ai ensuite simplement testé les valeurs dans la liste du scan :

if robin_galaxy in list_scan:
 print ('rob home')
else:
 print ('rob not home')
if zoe_galaxy in list_scan:
 print ('zoe home')
else: 
 print ('zoe not home')
if abdul_galaxy in list_scan:
 print ('abdul home')
else:
 print ('abdul not home')
if carole_iphone in list_scan:
 print('carole home')
else:
 print('carole not home')

2.2.6. Base de données

J'ai voulu utiliser une base de données sqlite pour pouvoir faire plus facilement des requêtes en php sur ma page html. Les problèmes ont alors commencé à arriver. J'ai fais plusieurs recherches pour pouvoir insérer une liste dans une base de données. Toutes ont abouties au même résultat. Un code python qui ressemble au suivant :

conn = sqlite3.connect('/root/Desktop/toto.db')
c = conn.cursor()
c.execute("INSERT INTO MAC_total (MAC_adress) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",(list_total))
conn.commit()

J'ai préalablement créer une base de données grâce à l'iinterface graphique "SQlite database browser" ou j'y ai créé une table "MAC_total" et une colonne "MAC_adress". Les 16 points d'interrogation correspondent bien aux 16 MAC adresses que contient la liste "list_total". J'ai ensuite eu plusieurs messages d'erreurs :

Value Error: parameters are of unsupported type

mais aussi

sqlite3.OperationalError: 16 values for 1 columns

Je me doute bien qu'il s'agit d'une erreur de débutant mais j'ai essayé encore d'autres variantes mais je n'ai pas réussis à insérer cette liste dans ma base de donnée. J'ai aussi regarder le code d'Hippolyte car il devait lui aussi insérer des données dans une base de données et c'est exactement la même structure de code.

2.2.7 Page web

Suite à l'incapacité de résoudre ce problème de base de données, il ne me restait plus de temps pour écrire ma page html mais elle aurait été de toute manière très simple avec un code php qui fait référence à ma base de données et le statuts des téléphones portables. Un simple print du tableau aurait suffit à déchiffrer les valeurs et nous aurions pu y voir qui se trouve à la maison mais aussi l'adresse MAC d'un éventuel intru.

3. Résultats

Je termine avec un code python qui fait ce que je lui demande et il ne comporte pas d'erreur. Il peut certainement être alléger mais je ne me suis pas attardé sur le stockage des variables et à la performance du code étant donné que mes données restent petites. Voici le code final :

from sets import Set 
import os 
import sqlite3 

robin_galaxy = 'B0:72:BF:C6:FC:B3'
zoe_galaxy = '04:D6:AA:OD:08:52'
abdul_galaxy ='04:D6:AA:62:DC:96'
carole_iphone = '48:4B:AA:D5:A0:07'

os.system("nmap -sP -n 192.168.1.* | grep MAC | cut -c 14-30 > SCAN_MAC")
os.system("grep MAC SCAN_BRUT | cut -c 14-30 > MAC_TOTAL")

mac_total = "/root/Desktop/MAC_TOTAL"
scan_mac = "/root/Desktop/SCAN_MAC"

total = open(mac_total)
scan = open(scan_mac)

list_total = Set (total.read().splitlines())
list_scan = Set (scan.read().splitlines())

intru = list_scan - list_total

#print (list_total)
print(" ")
#print (list_scan)
print(" ")

if intru == Set():
        print('pas intru')
else: 
        print(intru)


if robin_galaxy in list_scan:
	print ('rob home')
else:
	print ('rob not home')
if zoe_galaxy in list_scan:
	print ('zoe home')
else: 
	print ('zoe not home')
if abdul_galaxy in list_scan:
	print ('abdul home')
else:
	print ('abdul not home')
if carole_iphone in list_scan:
	print('carole home')
else:
	print('carole not home')


conn = sqlite3.connect('/root/Desktop/toto.db')
c = conn.cursor()
c.execute("INSERT INTO MAC_total (MAC_adress) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", (list_total))
conn.commit()

4. Discussion

Je me suis longuement intéressé aux différentes options de nmap, et j'ai lu énormément de document sur cette distribution. J'ai aussi eu la joie de découvrir le merveilleux système d'exploitation "Kali Linux" que j'ai finis par installer sur mon propre Raspberry. Cet OS m'a vraiment donné l'eau à la bouche et j'y ai consacré pas mal de temps, un peu trop peut-être... Je me suis probablement trop dispersé et j'y ai perdu beaucoup de temps mais c'est sans aucun regret car je n'ai peut-être pas réussi à finir mon projet dans le cadre scolaire mais ça m'a donné l'envie d'en faire encore plus. Je ne pense pas que ce projet soit très représentatif de ce que j'ai appris durant mes recherches et je pense que si nous devions être jugé sur la progression de nos compétences entre le début et la fin de notre projet, j'aurais sûrement plus que suffisamment atteint les exigences. Le bagage de connaissance que j'ai acquis, suffit largement à apaiser la frustration d'un projet non terminé. De plus, lorsque j'ai trouvé la commande "grep" je me suis intéressé un peu plus profondément aux autres commandes que Linux regorge. Ma curiosité ne m'a pas aidé à me fixer sur une tâche précise, plusieurs fois j'ai commencé à lire des cours qui n'était d'aucune utilité pour mon projet et toutes ces recherches prennent un temps inconsidérable.

5. Conclusion

Dans l'ensemble, je suis plutôt content du résultat auquel je suis arrivé. J'ai surmonté beaucoup d'obstacle qui me paraissait bien compliqué voir impossible au départ. Une bonne fragmentation du travail est la clé de la réussite de celui-ci. Mon projet manque certes d'une grosse partie, celle où je peux y accéder depuis l'extérieur sans avoir besoin d'exécuter le programme directement sur mon Raspberry. Je suis tout de même parvenu à mon but principal : voir si mon réseau se faisait squatter par d'autres appareils. Il ne reste plus qu'à trouver comment leur bloquer la connexion ou alors l'identifier complètement...

Références

  • http://apprendre-python.com/page-apprendre-listes-list-tableaux-tableaux-liste-array-python-cours-debutant
  • https://openclassrooms.com/courses/apprenez-a-programmer-en-python/les-dictionnaires-2
  • https://blog.netapsys.fr/nmap-commandes-utiles/
  • https://docs.python.org/2/library/sets.html
  • https://doc.ubuntu-fr.org/tutoriel/console_commandes_de_base#grep
  • https://openclassrooms.com/courses/reprenez-le-controle-a-l-aide-de-linux/extraire-trier-et-filtrer-des-donnees
  • https://stackoverflow.com/questions/1038160/data-structure-for-maintaining-tabular-data-in-memory
  • https://stackoverflow.com/questions/2092757/python-and-sqlite-insert-into-table
  • http://apprendre-python.com/page-database-data-base-donnees-query-sql-mysql-postgre-sqlite
  • https://stackoverflow.com/questions/43240617/python-sqlite3-insert-list
  • https://www.tutorialspoint.com/sqlite/sqlite_create_database.htm