Installation de scapy sur Ubuntu
sudo apt-get install python-scapy
Obtenir de l'aide sur les commandes scapy
Pour connaitre la liste des commandes scapy
>>> lsc() arpcachepoison : Poison target's cache with (your MAC,victim's IP) couple arping : Send ARP who-has requests to determine which hosts are up bind_layers : Bind 2 layers on some specific fields' values corrupt_bits : Flip a given percentage or number of bits from a string corrupt_bytes : Corrupt a given percentage or number of bytes from a string defrag : defrag(plist) -> ([not fragmented], [defragmented], defragment : defrag(plist) -> plist defragmented as much as possible dyndns_add : Send a DNS add message to a nameserver for "name" to have a new "rdata" dyndns_del : Send a DNS delete message to a nameserver for "name" etherleak : Exploit Etherleak flaw fragment : Fragment a big IP datagram fuzz : Transform a layer into a fuzzy layer by replacing some default values by random objects getmacbyip : Return MAC address corresponding to a given IP address hexdiff : Show differences between 2 binary strings hexdump : -- hexedit : -- is_promisc : Try to guess if target is in Promisc mode. The target is provided by its ip. linehexdump : -- ls : List available layers, or infos on a given layer promiscping : Send ARP who-has requests to determine which hosts are in promiscuous mode rdpcap : Read a pcap file and return a packet list send : Send packets at layer 3 sendp : Send packets at layer 2 sendpfast : Send packets at layer 2 using tcpreplay for performance sniff : Sniff packets split_layers : Split 2 layers previously bound sr : Send and receive packets at layer 3 sr1 : Send packets at layer 3 and return only the first answer srbt : send and receive using a bluetooth socket srbt1 : send and receive 1 packet using a bluetooth socket srflood : Flood and receive packets at layer 3 srloop : Send a packet at layer 3 in loop and print the answer each time srp : Send and receive packets at layer 2 srp1 : Send and receive packets at layer 2 and return only the first answer srpflood : Flood and receive packets at layer 2 srploop : Send a packet at layer 2 in loop and print the answer each time traceroute : Instant TCP traceroute tshark : Sniff packets and print them calling pkt.show(), a bit like text wireshark wireshark : Run wireshark on a list of packets wrpcap : Write a list of packets to a pcap file >>>
Voir tous les objets que Scapy peut manipuler
ls() ARP : ARP ... IP : IP ...
=> Il existe donc un objet IP dont le contenu peut être connu via ls(IP)
>>> ls(IP) version : BitField = (4) ihl : BitField = (None) tos : XByteField = (0) len : ShortField = (None) id : ShortField = (1) flags : FlagsField = (0) frag : BitField = (0) ttl : ByteField = (64) proto : ByteEnumField = (0) chksum : XShortField = (None) src : Emph = (None) dst : Emph = ('127.0.0.1') options : PacketListField = ([]) >>>
Aide sur la commande send qui permet d'envoyer un paquet forgé à partir du niveau 3 (couche IP). Ceci veut dire que le niveau 2 (la couche ethernet) a été renseigné par scapy automatiquement :
thierry@PC1:~/Bureau/data/testScapy$ scapy
Welcome to Scapy (2.2.0)
>>> help(send)
Help on function send in module scapy.sendrecv:
send(x, inter=0, loop=0, count=None, verbose=None, realtime=None, *args, **kargs)
Send packets at layer 3
send(packets, [inter=0], [loop=0], [verbose=conf.verb]) -> None
Aide sur la commande sendp qui permet d'envoyer un paquet forgé à partir du niveau 2 (couche Ethernet):
thierry@PC1:~$ scapy INFO: Can't import python gnuplot wrapper . Won't be able to plot. INFO: Can't import PyX. Won't be able to use psdump() or pdfdump(). WARNING: No route found for IPv6 destination :: (no default route?) Welcome to Scapy (2.2.0) >>> help(sendp) Help on function sendp in module scapy.sendrecv: sendp(x, inter=0, loop=0, iface=None, iface_hint=None, count=None, verbose=None, realtime=None, *args, **kargs) Send packets at layer 2 sendp(packets, [inter=0], [loop=0], [verbose=conf.verb]) -> None
Création d'un paquet
On voit ci-dessous les valeutrs par défaut.
De plus, certaines valeurs sont recalculées, comme l'IP source suite à la définition de l'IP destination :
>>> a=IP() >>> a.ttl 64 >>> a.src '127.0.0.1' >>> a.dst='192.168.1.2' >>> a.src '192.168.1.10' >>>
Création d'un paquet ping vers www.google.fr
Trois méthodes :
- soit on crée le paquet à partir du niveau Ethernet en précisant que celui-ci contient un paquet IP à destination www.google.fr, lui même contenant un paquet ICMP echo-request, et envoie via srp
- soit on crée le paquet à partir du niveau IP en précisant que la destination est www.google.fr, puis en précisant que ce paquet IP contient une charge un paquet ICMP echo-request, et envoi via sr,
- soit on crée le paquet avec la méthode ICMP().
Cas de la construction de la trame à partir du niveau Ethernet. La fonction pour envoyer un tel paquet est alors srp.
#!/usr/bin/python
from scapy.all import *
# creation du paquet IP a destination de www.google.fr, ce paquet IP contenant un ICMP
pck=Ether()/IP(dst='www.google.fr')/ICMP()
# Affichage de ce paquet : affiche son contenu Ethernet, IP et ICMP
print "--- pck.show():"
pck.show()
L'exécution de ce script donne :
WARNING: No route found for IPv6 destination :: (no default route?) --- pck.show(): ###[ Ethernet ]### dst = 94:fe:f4:ac:d0:51 src = 00:24:21:b5:e6:46 type = 0x800 ###[ IP ]### version = 4 ihl = None tos = 0x0 len = None id = 1 flags = frag = 0 ttl = 64 proto = icmp chksum = None src = 192.168.1.2 dst = Net('www.google.fr') \options \ ###[ ICMP ]### type = echo-request code = 0 chksum = None id = 0x0 seq = 0x0
Explications :
Scapy signale qu'il ne peut joindre www.google.fr via IPv6 étant donné que ma box ne supporte pas IPv6.
Scapy a complété automatiquement la couche 2 pour ce qui concerne l'adresse MAC de l'émetteur et l'adresse MAC du destinataire :
adresse MAC de l'émetteur : l'adresse MAC de mon PC
adresse MAC du destinataire : l'adresse MAC de ma box côté LAN.
A présent on envoie ce paquet en utilisant rep,norep=srp(pck). rep contient les paquet émis avec la réponse. norep contient les paquets qui n'auraient pas obtenu de réponse.
Compléter donc le script ainsi :
#envoi du paquet construit a partir du niveau IP, send permet l'envoi du paquet mais ne permet pas de recuperer la reponse a ce paquet
print "--- envoi du paquet sans lire la reponse"
sendp(pck)
print "--- envoi du paquet avec lecture de la reponse via la commande srp"
rep,norep=srp(pck)
print "--- Affichage de la reponse, uniquement la partie ICMP pour la destination " + str(pck.dst)
rep[0][1][ICMP].show()
Ce qui donne:
--- envoi du paquet sans lire la reponse . Sent 1 packets. --- envoi du paquet avec lecture de la reponse via la commande srp Begin emission: Finished to send 1 packets. * Received 1 packets, got 1 answers, remaining 0 packets --- Affichage de la reponse, uniquement la partie ICMP pour la destination 94:fe:f4:ac:d0:51 ###[ ICMP ]### type = echo-reply code = 0 chksum = 0xffff id = 0x0 seq = 0x0 ###[ Padding ]### load = '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
Cas de la construction de la trame à partir du niveau IP comme montré ci-dessous. La fonction pour envoyer un tel paquet est alors sr.
#!/usr/bin/python
from scapy.all import *
# creation du paquet IP a destination de www.google.fr, ce paquet IP contenant un ICMP
pck=IP(dst='www.google.fr')/ICMP()/"Hello"
# Affichage de ce paquet : affiche son contenu IP et son contenu ICMP
print "--- pck.show():"
pck.show()
# Affichage de ce paquet mais uniquement sa partie ICMP
print "--- pck[ICMP].show():"
pck[ICMP].show()
#envoi du paquet construit a partir du niveau IP, send permet l'envoi du paquet mais ne permet pas de recuperer la reponse a ce paquet
print "--- envoi du paquet sans lire la reponse"
send(pck)
print "--- envoi du paquet avec lecture de la reponse via la commande sr"
rep,norep=sr(pck)
print "--- Affichage de la reponse, uniquement la partie ICMP pour la destination " + str(pck.dst)
rep[0][1][ICMP].show()
Ce qui donne:
WARNING: No route found for IPv6 destination :: (no default route?) --- pck.show(): ###[ IP ]### version = 4 ihl = None tos = 0x0 len = None id = 1 flags = frag = 0 ttl = 64 proto = icmp chksum = None src = 192.168.1.2 dst = Net('www.google.fr') \options \ ###[ ICMP ]### type = echo-request code = 0 chksum = None id = 0x0 seq = 0x0 ###[ Raw ]### load = 'Hello' --- pck[ICMP].show(): ###[ ICMP ]### type = echo-request code = 0 chksum = None id = 0x0 seq = 0x0 ###[ Raw ]### load = 'Hello' --- envoi du paquet sans lire la reponse . Sent 1 packets. --- envoi du paquet avec lecture de la reponse via la commande sr Begin emission: .Finished to send 1 packets. * Received 2 packets, got 1 answers, remaining 0 packets --- Affichage de la reponse, uniquement la partie ICMP pour la destination Net('www.google.fr') ###[ ICMP ]### type = echo-reply code = 0 chksum = 0xdc2d id = 0x0 seq = 0x0 ###[ Raw ]### load = 'Hello' ###[ Padding ]### load = '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
Bibliographie
http://fr.openclassrooms.com/informatique/cours/manipulez-les-paquets-reseau-avec-scapy