python, Pcapy, Impacket et un petit sniffer

by david

Bon, alors je pars du principe que les modèles OSI – TCP/IP n’ont plus de secret pour vous .

Pour notre petit sniffer il nous faut , comme vous l’avez lu, 2 modules : pcapy et Impacket .
pcapy sert à capturer les pokémons paquets alors que Impacket décapsule/encapsule .

Pour commencer, il faut récupérer les interfaces sur lesquelles on peut écouter .
La fonction findalldevs() est faite pour ça.
On va créer la fonction mesInterfaces()

def mesInterfaces():
        try:
                interfaces =  pcapy.findalldevs()
                interfaces.remove(‘any’)
                interfaces.remove(‘lo’)
        except pcapy.PcapError, e:
        #si on a pas les droits, par exemple
                interfaces = None
        return interfaces

Ensuite, il nous faut créer monReader , qui va lire les paquets.
On va donc créer notre classe EcouteMamanEstPresDeToi qui le contient.

class EcouteMamanEstPresDeToi(Thread):

        def __init__(self,monInterface,maxBits,promiscuite,timeOut,onSniffe):
                Thread.__init__(self)
                self.monInterface = monInterface
                self.maxBits = maxBits
                self.promiscuite = promiscuite
                self.timeOut = timeOut
                self.onSniffe = onSniffe
                self.monReader = pcapy.open_live(self.monInterface,
                                            self.maxBits,
                                            self.promiscuite,
                                            self.timeOut)

pcapy.open_live prend plusieurs arguments:
self.monInterface  = l’interface que l’on veut écouter.
self.maxBits = la taille maximale d’un paquet
self.promiscuite =  0 ou 1, afin de permettre à la carte d’accepter tous les paquets
self.timeOut = va accumuler pendant t ms les paquets, puis les analyser

Ensuite, ce serait bien de savoir dans quel sous réseau on se trouve .
On va ajouter dans notre classe, deux méthodes : reseau() et masque() .

        def reseau(self):
                return self.monReader.getnet()
               
        def masque(self):
                return self.monReader.getmask()

Notre reader contient les méthodes getnet() et getmask() qui renvoient l’adresse réseau et le masque .

Maintenant, il nous faut les IP des paquets .
On va donc rajouter 2 méthodes à notre classe :

        def ip_source(self,paquet):
                return paquet.get_ip_src()
             
        def ip_dest(self,paquet):
                return paquet.get_ip_dst()

paquet désigne la couche 3 : le protocole IP .

Il faut aussi, qu’on sache quel est le protocole  de couche 4 du paquet.
Pour ce faire, on va ajouter une méthode : couche4(paquet) .

def couche4(self,segment):
                dicoCouche4 = { 6:’TCP’, 17:’UDP’ }
                try :
                        return dicoCouche4[segment.protocol]
                except KeyError, e :
                        return None

 

segment désigne la couche 4 .
dicoCouche4 est un dictionnaire contenant quelques protocoles de couche 4 et leurs numéros associés.

C’est presque terminé, on a plus qu’à capturer les paquets et lancer les méthodes, le tout dans la méthode run() .

        def run(self):
             
                try :
                                ethernet = Ethernet().decode( self.monReader.next()[1] )
                                ip = ethernet.child()
                                print( « IP source :  » + str(self.ip_source( ip ) ) )
                                print( « IP destination :  » + str(self.ip_dest( ip ) ) )
                                couche_4 = ip.child()
                                print( « Protocole de couche 4 :  » + str( self.couche4( couche_4 ) ) )
                                couche_superieure = couche_4.child()
                                print( couche_superieure.get_buffer_as_string()  )
                except:
                                pass

 

self.monReader.next() va prendre le prochain paquet, et retourne une liste de 2 éléments : le header ( grâce auquel on aura la taille du paquet, le timestamp,…. ) et le paquet, qui nous intéresse .
On met un try/except vu que l’on désencapsule en partant du principe que la trame sera de type Ethernet : Ethernet().decode() .
child() renvoie la couche supérieure .
Les couches 5,6,7 contiennent les données, donc get_buffer_as_string() les renvoie .

Voilà la code en entier :

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

import pcapy
from impacket.ImpactDecoder import EthDecoder as Ethernet
from threading import Thread
import time

def mesInterfaces():
        try:
                interfaces =  pcapy.findalldevs()
                interfaces.remove(‘any’)
                interfaces.remove(‘lo’)
        except pcapy.PcapError, e:
                interfaces = None
        return interfaces

class EcouteMamanEstPresDeToi(Thread):

        def __init__(self,monInterface,maxBits,promiscuite,timeOut,onSniffe):
                Thread.__init__(self)
                self.monInterface = monInterface
                self.maxBits = maxBits
                self.promiscuite = promiscuite
                self.timeOut = timeOut
                self.onSniffe = onSniffe
                self.monReader = pcapy.open_live(self.monInterface,
                                            self.maxBits,
                                            self.promiscuite,
                                            self.timeOut)
                print(self.monInterface +  » :  » + self.reseau() +  » :  » + self.masque() )
               
        def run(self):
             
                while self.onSniffe:
                        try :
                                ethernet = Ethernet().decode( self.monReader.next()[1] )
                                ip = ethernet.child()
                                print( « IP source :  » + str(self.ip_source( ip ) ) )
                                print( « IP destination :  » + str(self.ip_dest( ip ) ) )
                                couche_4 = ip.child()
                                print( « Protocole de couche 4 :  » + str( self.couche4( couche_4 ) ) )
                                couche_superieure = couche_4.child()
                                print( couche_superieure.get_buffer_as_string()  )
                        except:
                                pass                                       
                                     
       
       
        def ip_source(self,paquet):
                return paquet.get_ip_src()
             
        def ip_dest(self,paquet):
                return paquet.get_ip_dst()
              

        def reseau(self):
                return self.monReader.getnet()
               
        def masque(self):
                return self.monReader.getmask()   
       
        def couche4(self,segment):
                dicoCouche4 = { 6:’TCP’, 17:’UDP’ }
                try :
                        return dicoCouche4[segment.protocol]
                except KeyError, e :
                        return None
       
                   
       
if __name__ == ‘__main__’:
        for element in mesInterfaces() :
                sniffSniff = EcouteMamanEstPresDeToi(element,1024,0,100,True)
                sniffSniff.start()

 

Voilà, l’article est terminé.
Il y aura peut-être une suite : le GUI de notre sniffer .

One Comment to “python, Pcapy, Impacket et un petit sniffer”

  1. Bonjour, je voulais tout d’abord te féliciter pour ton site/blog qui est tout simplement très instructif.

    Je suis élève-ingénieur actuellement en poste en tant que manager applicatif. Comprendre les failles m’est essentiel.

    Tout est explicite est bien formulé. J’ai une petite question qui regroupe un peu tout test tuto « impacket ».

    Comment reconstruire un email a partir d’un sniffer?

    Je fais un pen-test mais la sécurité n’est pas mon point fort. Pour l’instant je sniffe et j’arp-poisoning. Mais j’aimerai sniffer sur le réseau et reconstituer un mail se baladant avant un serveur exchange et ainsi pouvoir déterminer au mieux la cible.

    Si tu as des pistes de reflexion avec impacket, je suis preneur.

    Cordialement,
    Seb aka ‘sena’

Leave a Reply