Blue Flower

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