Un peu de Pratique


Un peu de Pratique:
Envoie/Réception de Paquets:

Scapy permet de forger vos propres paquets "ls" (pour voir la liste complète sous scapy), et nous allons voir dans cette partie
comment envoyer et comment recevoir des paquets.

Emission:
Envoyons un simple paquet TCP/IP vers google.fr sur le port 80.*
Listons tout d'abord les champs disponible pour les protocoles IP et TCP:

>>> 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      = ([])
>>> ls(TCP)
sport      : ShortEnumField       = (20)
dport      : ShortEnumField       = (80)
seq        : IntField             = (0)
ack        : IntField             = (0)
dataofs    : BitField             = (None)
reserved   : BitField             = (0)
flags      : FlagsField           = (2)
window     : ShortField           = (8192)
chksum     : XShortField          = (None)
urgptr     : ShortField           = (0)
options    : TCPOptionsField      = ({})



Pour notre simple exemple, nous utiliserons les champs dst et ttl pour le protocole IP et le champ dport pour le protocole TCP.
Pour envoyer ce paquets nous devons d'abord le créer en stockant les différentes informations dans une variable pour finalement l'envoyer:

>>> paquet = IP(dst="www.google.fr", ttl=15)/TCP(dport=80)
>>> send(paquet)
.
Sent 1 packets.



On peut également l'envoyer à l'infini avec l'option loop:

>>> paquet = IP(dst="www.google.fr", ttl=15)/TCP(dport=80)
>>> send(paquet, loop=1)
.....................................................................................^C
Sent 345 packets.



Cette exemple est très simple, mais il est largement suffisant pour comprendre comment crée un paquet de données, il y a néanmoins quelques variantes.
En effet nous avons utilisé la commande send() car nous somme en couche 3, néanmoins, pour un paquet de type ARP en couche 2, la commande à utiliser est sendp().

Emission & Reception:

Scapy nous propose aussi d'envoyer et de recevoir les réponses avec les commandes sr(),sr1() et srp(), srp1():

>>> paquet = IP(dst="www.google.fr", ttl=15)/TCP(dport=80)
>>> answer = sr(paquet)
Begin emission:
Finished to send 1 packets.
*
Received 1 packets, got 1 answers, remaining 0 packets



Reniflage:

Pleins de ressources (et nous voyons ici que les fonctionnalités de bases), Scapy offre la possibilité de renifler le trafic réseau via la commande sniff():
On peut préciser l'interface que l'on veut utiliser avec l'option iface.

>>> trafic = sniff(iface="eth0")
^C>>> trafic
<Sniffed: TCP:0 UDP:18 ICMP:0 Other:0>



Nous pouvons maintenant lister les paquets reçu (ici uniquement de l'UDP) avec la commande summary():

>>> trafic.summary()
Ether / IP / UDP 192.168.178.48:50422 > 37.187.40.232:1234 / Raw
Ether / IP / UDP 37.187.40.232:1234 > 192.168.178.48:50422 / Raw
Ether / IP / UDP 192.168.178.48:50422 > 37.187.40.232:1234 / Raw
Ether / IP / UDP 37.187.40.232:1234 > 192.168.178.48:50422 / Raw / Padding
Ether / IP / UDP 37.187.40.232:1234 > 192.168.178.48:50422 / Raw / Padding
Ether / IP / UDP 192.168.178.48:50422 > 37.187.40.232:1234 / Raw
Ether / IP / UDP 192.168.178.48:50422 > 37.187.40.232:1234 / Raw
Ether / IP / UDP 37.187.40.232:1234 > 192.168.178.48:50422 / Raw / Padding
Ether / IP / UDP 37.187.40.232:1234 > 192.168.178.48:50422 / Raw / Padding
Ether / IP / UDP 192.168.178.48:50422 > 37.187.40.232:1234 / Raw
Ether / IP / UDP 192.168.178.48:50422 > 37.187.40.232:1234 / Raw
Ether / IP / UDP 37.187.40.232:1234 > 192.168.178.48:50422 / Raw / Padding
Ether / IP / UDP 37.187.40.232:1234 > 192.168.178.48:50422 / Raw / Padding
Ether / IP / UDP 192.168.178.48:50422 > 37.187.40.232:1234 / Raw
Ether / IP / UDP 192.168.178.48:50422 > 37.187.40.232:1234 / Raw
Ether / IP / UDP 37.187.40.232:1234 > 192.168.178.48:50422 / Raw / Padding
Ether / IP / UDP 37.187.40.232:1234 > 192.168.178.48:50422 / Raw / Padding
Ether / IP / UDP 192.168.178.48:50422 > 37.187.40.232:1234 / Raw



Mais aussi les lister en les numérotant en utilisant la commande show():

>>> trafic.show()
0000 Ether / IP / UDP 192.168.178.48:50422 > 37.187.40.232:1234 / Raw
0001 Ether / IP / UDP 37.187.40.232:1234 > 192.168.178.48:50422 / Raw
0002 Ether / IP / UDP 192.168.178.48:50422 > 37.187.40.232:1234 / Raw
0003 Ether / IP / UDP 37.187.40.232:1234 > 192.168.178.48:50422 / Raw / Padding
0004 Ether / IP / UDP 37.187.40.232:1234 > 192.168.178.48:50422 / Raw / Padding
0005 Ether / IP / UDP 192.168.178.48:50422 > 37.187.40.232:1234 / Raw
0006 Ether / IP / UDP 192.168.178.48:50422 > 37.187.40.232:1234 / Raw
0007 Ether / IP / UDP 37.187.40.232:1234 > 192.168.178.48:50422 / Raw / Padding
0008 Ether / IP / UDP 37.187.40.232:1234 > 192.168.178.48:50422 / Raw / Padding
0009 Ether / IP / UDP 192.168.178.48:50422 > 37.187.40.232:1234 / Raw
0010 Ether / IP / UDP 192.168.178.48:50422 > 37.187.40.232:1234 / Raw
0011 Ether / IP / UDP 37.187.40.232:1234 > 192.168.178.48:50422 / Raw / Padding
0012 Ether / IP / UDP 37.187.40.232:1234 > 192.168.178.48:50422 / Raw / Padding
0013 Ether / IP / UDP 192.168.178.48:50422 > 37.187.40.232:1234 / Raw
0014 Ether / IP / UDP 192.168.178.48:50422 > 37.187.40.232:1234 / Raw
0015 Ether / IP / UDP 37.187.40.232:1234 > 192.168.178.48:50422 / Raw / Padding
0016 Ether / IP / UDP 37.187.40.232:1234 > 192.168.178.48:50422 / Raw / Padding
0017 Ether / IP / UDP 192.168.178.48:50422 > 37.187.40.232:1234 / Raw



Analyse de paquets

Profitons de cette capture réseau pour introduire quelques rudiments sur l'analyse des paquets reçu (rien de poussé, ce n'est qu'une introduction):
trafic est notre liste de paquet capturé.

Commande Description
trafic[n] Accés au paquet n
trafic[n].show() Affichage propre du paquet n
trafic[n][proto] Accés uniquement au protocol "proto" du paquet n (exemple: trafic[0][UDP])
trafic[n].[proto].champs Accés au champs du protocol "proto" du paquet n (exemple: trafic[0][IP].dst)
trafic[0].haslayer(proto) Retourne 1 si le protocol "proto" est présent dans le paquet n 0 sinon (exemple: trafic[0].haslayer(TCP))



Traitement de paquet à la volée:

Un titre bien bizarre, n'est-il pas? :)
la fonction sniff() de scapy, qui nous permet comme vous l'avez vu de reniffler le trafic réseau nous propose l'option prn.
Cette option nous permet de définir une fonction qui sera appliqué a chaque paquet sniffé.

Mais voyons plutôt ça, par un petit exemple, où nous définirons une fonction qui affichera les adresses IP Source:

# On définit la fonction, p est le paquet
>>> def affich_srcip(p):
# Si p possède une trame IP
...  if p.haslayer(IP):
# Alors on affiche le champs src de la trame IP de p
...   print p[IP].src
... 
>>> sniff(iface="eth0",prn=affich_srcip)
37.187.40.232
192.168.178.48
192.168.178.48
37.187.40.232
37.187.40.232
192.168.178.48
192.168.178.48
37.187.40.232
37.187.40.232
192.168.178.48
192.168.178.48
37.187.40.232
^C<Sniffed: TCP:0 UDP:12 ICMP:0 Other:2>