Bonjour, je vous partage comme il l'a souhaité le tuto de jokoast
Un grand merci à lui !!!
TUTORIEL : Utiliser PyShark sous Python3.x (MacOSx) afin de sniffer en live les paquets de Dofus
Sommaire:
1 - Prérequis et installation de PyShark
2 - Introduction
3 - Mise en place de l'écoute et récupération des paquets
4 - Récupération des données depuis le paquet
5 - Allons plus loin
6 - Bonus
1 - Prérequis et installation de PyShark
Cliquez pour révéler
Cliquez pour masquer
Dans un premier temps il vous faut Python3.x, pip3.x et WireShark d'installés.
Pour Python et Pip je ne vous apprends rien, vous êtes là vous avez très sûrement cet interpréteur magnifique qu'est Python et son installateur de package, Pip.
Pour WireShark, je vous invite à l'installer depuis ce lien.
Une fois installé, je vous conseille de redémarrer afin de bien finaliser l'installation.
Une fois cela fait, installez PyShark via Pip:
pip3 install pyshark
2 - Introduction
Cliquez pour révéler
Cliquez pour masquer
Dans un premier temps nous allons binder PyShark (et par conséquent le processus WireShark) sur l'interface de notre choix.
Lancez cette commande afin de connaître les interfaces réseaux disponibles:
networksetup -listallhardwareports
Vous allez avoir un output dans ce genre là:
Hardware Port: Wi-Fi
Device: en0
Ethernet Address: d7:02:65:7c:1e:14
Hardware Port: Bluetooth PAN
Device: en1
Ethernet Address: N/A
Hardware Port: Thunderbolt 1
Device: en2
Ethernet Address: bb:e8:c3:25:2b:12
Retenez le "Device" correspondant à votre interface, c'est sur celle là que nous allons écouter.
Ouvrez un fichier .py de votre choix et copiez/collez ce code:
import pyshark
capture = pyshark.LiveCapture(interface='en1') # On bind le module WireShark sur l'interface WiFi (pour moi)
capture.sniff(timeout=20) # On sniffe l'interface pendant 20 secondes
print(capture) # On imprime le type de l'objet (ou sa méthode str)
Vous devriez avoir une sortie de ce genre :
<LiveCapture (11 packets)>
3 - Mise en place de l'écoute et récupération des paquets
Cliquez pour révéler
Cliquez pour masquer
En accord avec la partie II) Analyse du tutoriel de Labo, nous cherchons à écouter que les paquets en provenance ou au départ de Dofus et ayant une longueur de plus de 66 octets (Bytes) pour éviter d'attraper les paquets propres au maintien de la connection TCP.
Pour cela nous mettons en place un bpf_filter dans la ligne permettant de se préparer à la capture en temps réel.
Retestez le code précédent en modifiant la ligne précédente et en ayant Dofus coupé.
capture = pyshark.LiveCapture(interface='en1',bpf_filter='tcp port 5555 and len > 66')
Vous devriez n'avoir capturé aucun paquet TCP ayant pour port 5555 et une longueur supérieure à 66.
4 - Récupération des données depuis le paquet
Cliquez pour révéler
Cliquez pour masquer
Les packets construits par pyshark répondent à la même structure que celle de Wireshark, donc c'est un oignon bien chiant qu'il faut décortiquer pour comprendre sa structure.
La documentation de PyShark n'explique pas comment accéder aux données hors couche IP/ETH/TCP, la seule chose qui vous est expliquée est comment récupéré l'IP Source / Destinataire du packet.
A force de test, pour récupérer les données brutes (parce qu'il y en aura forcement puisque les paquets sans données sont filtrés) il suffit de faire ça:
print("[DEBUG] {} paquets reçus".format( len(capture) ) )
for packet in capture:
print(packet.data.data)
A partir de là vous devriez avoir le nombre de paquets reçus et de l'hexa affiché sur votre terminal (pour chaque paquet reçu).
5 - Allons plus loin
Cliquez pour révéler
Cliquez pour masquer
Avec PyShark nous pouvons aussi sniffer en continu (ou déterminer un nombre de paquets à attraper - permettant de faciliter les tests de traitement).
# Version continu
for packet in capture.sniff_continuously():
print(packet.data.data)
# Version avec le paramètre nombre de paquets
for packet in capture.sniff_continuously(packet_count=10):
print(packet.data.data)
Vous pouvez déterminer si c'est un paquet reçu ou un paquet émis en comparant l'ip source. (selon la configuration de votre fichier hosts)
import socket
# [...]
for packet in capture.sniff_continuously(packet_count=10):
if packet.ip.src == socket.gethostbyname(socket.gethostname()):
print("[DEBUG] Paquet Dofus Envoyé")
else:
print("[DEBUG] Paquet Dofus Reçu")
print(packet.data.data)
Il faut aussi savoir que les données reçus depuis PyShark sont des chaînes de caractères formatés pour représenter les octets (00:00:00:00), il faut donc les traiter afin d'avoir une chaîne incrémentable.
raw_data = ''.join(paquet.data.data.split(':'))
print(raw_data)
Avec ça vous devriez maintenant être capable de catcher proprement les paquets et prévoir des handlers pour traiter chaque paquet selon son idmessage ;).
6 - Bonus
Parce que ça manque de couleur dans le terminal afin de répérer les erreurs, et autres warning, debug et autres, je partage avec vous une petite librairie faite main utilisant les codes ANSII des couleurs du Terminal.
Cliquez pour révéler
Cliquez pour masquer
class Colored():
def __init__(self, print_bool=True):
self.have_to_print = print_bool
self.green = "\033[1;32m"
self.red = "\033[1;31m"
self.yellow = "\033[1;33m"
self.blue = "\033[1;34m"
self.purple = "\033[1;35m"
self.cyan = "\033[1;36m"
self.end = "\033[0;0m"
def PrintOn(self):
self.have_to_print = True
def PrintOff(self):
self.have_to_print = False
def OK(self, string):
OK = "[" + self.green + "OK" + self.end + "] "
if self.have_to_print:
print(OK + string)
return OK + string
def ERROR(self, string):
ERROR = "[" + self.red + "KO" + self.end + "] "
if self.have_to_print:
print(ERROR + string)
return ERROR + string
def WARNING(self, string):
WARNING = "[" + self.yellow + "WARNING" + self.end + "] "
if self.have_to_print:
print(WARNING + string)
return WARNING + string
def NOTICE(self, string):
NOTICE = "[" + self.blue + "NOTICE" + self.end + "] "
if self.have_to_print:
print(NOTICE + string)
return NOTICE + string
def DEBUG(self, string):
DEBUG = "[" + self.purple + "DEBUG" + self.end + "] "
if self.have_to_print:
print(DEBUG + string)
return DEBUG + string
def KO(self, string):
KO = "[" + self.red + "KO" + self.end + "] "
if self.have_to_print:
print(KO + string)
return KO + string
Et je vous reposte ici le code correspondant au tutoriel avec un exemple d'utilisation de la petite librairie du dessus.
import pyshark
import socket
# Seulement si vous collez la librairie Colored au dessus, sinon utilisez les import
# colored = Colored()
capture = pyshark.LiveCapture(interface='en1',bpf_filter='tcp port 5555 and len > 66')
colored.OK("Interface bindée sur %s" % socket.gethostbyname(socket.gethostname()))
for packet in capture.sniff_continuously():
if packet.ip.src == socket.gethostbyname(socket.gethostname()):
colored.OK("Paquet Dofus Envoyé")
else:
colored.OK("Paquet Dofus Reçu")
print(''.join(packet.data.data.split(":")))
print("")