Contribuez à SecuObs en envoyant des bitcoins ou des dogecoins.
Nouveaux articles (fr): 1pwnthhW21zdnQ5WucjmnF3pk9puT5fDF
Amélioration du site: 1hckU85orcGCm8A9hk67391LCy4ECGJca

Contribute to SecuObs by sending bitcoins or dogecoins.



[Trames et paquets de données avec Scapy – Partie 6] Manipulations de paquets et de trames

Par Rédaction, secuobs.com
Le 01/10/2007


Résumé : Scapy est avant tout un utilitaire permettant de forger, recevoir et émettre des paquets et des trames de données sur un réseau. On retrouve dans cette partie les nombreuses fonctions disponibles à cet effet à travers différents exemples comme la réalisation d'un ping ICMP ou d'un scan de port.



On affiche maintenant les spécificités du protocole IP à l'aide de la commande ls() :

>>> 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 : IPoptionsField = ('')



On affiche également les spécificités du protocole ICMP toujours avec la commande ls() :

>>> ls(ICMP)
type : ByteEnumField = (8)
code : ByteField = (0)
chksum : XShortField = (None)
id : XShortField = (0)
seq : XShortField = (0)



On effectue un ping en destination de la machine dont l'adresse ip est équivalente à 192.168.0.2 ; dans un premier temps on visualise le paquet ICMP correspondant à ce ping :

>>> IP(dst='192.168.0.2')/ICMP()
>



On affiche la documentation de la fonction sr1() à l'aide la fonction lsc() :

>>> lsc(sr1)
Send packets at layer 3 and return only the first answer
nofilter: put 1 to avoid use of bpf filters
retry: if positive, how many times to resend unanswered packets
if negative, how many times to retry when no more packets are answered
timeout: how much time to wait after the last packet has been sent
verbose: set verbosity level
multi: whether to accept multiple answers for the same stimulus
filter: provide a BPF filter
iface: listen answers only on the given interface



On envoie cette fois le même paquet ICMP et on accepte de ne recevoir qu'un seul paquet en réponse à l'aide de la commande sr1() :

>>> sr1(IP(dst='192.168.0.1')/ICMP())
Begin emission:
.Finished to send 1 packets.
*
Received 2 packets, got 1 answers, remaining 0 packets
>



Le ping est bien effectif et il est semblable aux résultats de la commande système ping :

root@casper:~# ping -c 1 192.168.0.1
PING 192.168.0.1 (192.168.0.1) 56(84) bytes of data.
64 bytes from 192.168.0.1: icmp_seq=1 ttl=128 time=1.40 ms

--- 192.168.0.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 1.409/1.409/1.409/0.000 ms



On constate avec la fonction sr1() que l'on ne reçoit bien et qu'on n'enregistre dans les résultats qu'un seul paquet en réponse. Cette même fonction peut également servir à réaliser un scan de port ; on envoie un paquet TCP/IP vers www.secuobs.com à destination du port 80 avec le flags TCP Syn activé qui indique qu'on demande à établir une connexion non préalable :

>>> sr1(IP(dst="www.secuobs.com")/TCP(dport=80, flags="S"))
Begin emission:
Finished to send 1 packets.
*
Received 1 packets, got 1 answers, remaining 0 packets
>



On constate ici que l'on a reçu un paquet en réponse, on peut en conclure que le port 80 (www) est ouvert sur le serveur dont l'adresse IP est affectée au FQDN "www.secuobs.com" ; on effectue un deuxième essai sur le port 22 (SSH) :

>>> sr1(IP(dst="www.secuobs.com")/TCP(dport=22, flags="S"))
Begin emission:
.Finished to send 1 packets.
*
Received 2 packets, got 1 answers, remaining 0 packets
>



On reçoit également une réponse le port 22 est ouvert ; on réalise un dernier essai sur le port 53 (DNS) :

>>> sr1(IP(dst="www.secuobs.com")/TCP(dport=53, flags="S"))
Begin emission:
Finished to send 1 packets.
..............................
Received 30 packets, got 0 answers, remaining 1 packets



On en conclut que le port 53 n'est pas ouvert sur ce serveur, cela ne veut pas forcément dire qu'un serveur DNS ne tourne pas sur ce port, on peut juste en conclure que des rêgles de filtrage sont présentes afin d'empêcher les connexions extérieures vers ce port 53.


On affiche maintenant, à l'aide de la commande lsc(), les détails des options de la fonction sr() qui permet quant à elle de recevoir et de stocker plus d'un paquet en réponse à ceux préalablement envoyés :

>>> lsc(sr)
Send and receive packets at layer 3
nofilter: put 1 to avoid use of bpf filters
retry: if positive, how many times to resend unanswered packets
if negative, how many times to retry when no more packets are answered
timeout: how much time to wait after the last packet has been sent
verbose: set verbosity level
multi: whether to accept multiple answers for the same stimulus
filter: provide a BPF filter
iface: listen answers only on the given interface



On affiche les détails de la fonction send() à l'aide de la commande lsc() :

>>> lsc(send)
Send packets at layer 3
send(packets, [inter=0], [loop=0], [verbose=conf.verb]) -> None



On peut par ailleurs utiliser la fonction srloop de scapy afin d'exécuter une boucle sur l'envoi d'un paquets de données (ici de l'ICMP à destination de la machine dont l'adresse IP est égale à 192.168.0.2) :

>>> srloop(IP(dst='192.168.0.2')/ICMP())
RECV 1: IP / ICMP 192.168.0.1 > 192.168.0.2 echo-reply 0
RECV 1: IP / ICMP 192.168.0.1 > 192.168.0.2 echo-reply 0
RECV 1: IP / ICMP 192.168.0.1 > 192.168.0.2 echo-reply 0
RECV 1: IP / ICMP 192.168.0.1 > 192.168.0.2 echo-reply 0
RECV 1: IP / ICMP 192.168.0.1 > 192.168.0.2 echo-reply 0
RECV 1: IP / ICMP 192.168.0.1 > 192.168.0.2 echo-reply 0
RECV 1: IP / ICMP 192.168.0.1 > 192.168.0.2 echo-reply 0
RECV 1: IP / ICMP 192.168.0.1 > 192.168.0.2 echo-reply 0
RECV 1: IP / ICMP 192.168.0.1 > 192.168.0.2 echo-reply 0

Sent 9 packets, received 9 packets. 100.0% hits.
(, )



Ctrl C pour arrêter le srloop, ici on a envoyé et reçu 9 paquets ; on peut également affecter à srloop() un numéro d'envoi limité avec le paramètre count, ici 10 paquets :

>>> srloop(IP(dst='192.168.0.2')/ICMP(),count=10)
RECV 1: IP / ICMP 192.168.0.1 > 192.168.0.2 echo-reply 0
RECV 1: IP / ICMP 192.168.0.1 > 192.168.0.2 echo-reply 0
RECV 1: IP / ICMP 192.168.0.1 > 192.168.0.2 echo-reply 0
RECV 1: IP / ICMP 192.168.0.1 > 192.168.0.2 echo-reply 0
RECV 1: IP / ICMP 192.168.0.1 > 192.168.0.2 echo-reply 0
RECV 1: IP / ICMP 192.168.0.1 > 192.168.0.2 echo-reply 0
RECV 1: IP / ICMP 192.168.0.1 > 192.168.0.2 echo-reply 0
RECV 1: IP / ICMP 192.168.0.1 > 192.168.0.2 echo-reply 0
RECV 1: IP / ICMP 192.168.0.1 > 192.168.0.2 echo-reply 0
RECV 1: IP / ICMP 192.168.0.1 > 192.168.0.2 echo-reply 0

Sent 10 packets, received 10 packets. 100.0% hits.
(, )



Les fonctions sr, sr1, send et srloop envoient et/ou recoivent des paquets au niveau réseau soit la couche 3 du modèle OSI soit celle présente juste avant (émission) ou après (réception) le niveau correspondant à liaison de donnée qui se trouve en seconde position dans ce modèle à 7 couches.

La couche liaison de données se situe donc juste avant (émission) ou après (réception) le niveau correspondant à la couche physique du modèle OSI.

L'équivalent de ces fonctions du niveau réseau pour le niveau liaison de données dans Scapy sont les fonctions srp, srp1, srploop et sendp qui forgent, recoivent et/ou envoient des trames de données et non plus seulement des paquets de données sur le réseau ; à noter qu'au niveau de la couche physique du modèle OSI on parle en octet et non plus en paquet ou en trames de données.

On affiche la documentation de srp() :

>>> lsc(srp)
Send and receive packets at layer 2
nofilter: put 1 to avoid use of bpf filters
retry: if positive, how many times to resend unanswered packets
if negative, how many times to retry when no more packets are answered
timeout: how much time to wait after the last packet has been sent
verbose: set verbosity level
multi: whether to accept multiple answers for the same stimulus
filter: provide a BPF filter
iface: work only on the given interface



Soit la trame suivante :

>>> Ether()/IP(dst="www.secuobs.com")/TCP(dport=[80,443])/"GET / HTTP/1.0 \n\n"
Ether()/IP(dst="www.secuobs.com")/TCP(dport=[80,443])/"GET / HTTP/1.0 \n\n"
>>>



On affecte cette trame à la variable sn :

>>> sn=Ether()/IP(dst="www.secuobs.com")/TCP(dport=[80,443])/"GET / HTTP/1.0 \n\n"

>>> sn
>>>



A l'aide de la fonction srp on envoie la trame contenu dans la variable sn :

>>> srp(sn)
Begin emission:
.Finished to send 2 packets.
**
Received 3 packets, got 2 answers, remaining 0 packets
(, )



On aurait également pû affecter certaines valeurs à l'envoi de la trame comme le nombre de fois où elles doivent être réémises après une réponse négative et cela grâce au paramètre retry (ici 3 fois), l'intervalle de temps entre l'envoi de deux trames avec inter (ici 1) ou la durée limite (ici 2) à attendre après l'envoi de la dernière trame avec timeout (l'ensemble de ces paramètres étant également disponibles pour l'envoi de paquets via la fonction sr()) :

>>> srp(Ether()/IP(dst="www.secuobs.com")/TCP(dport=[80,443])/"GET / HTTP/1.0 \n\n",inter=1,retry=-3,timeout=2)
Begin emission:
...Finished to send 2 packets.
*..Begin emission:
..Finished to send 1 packets.
*
Received 9 packets, got 2 answers, remaining 0 packets
(, )



Autres ressources dans ce dossier :

[Trames et paquets de données avec Scapy – Partie 1] Présentation – lien

[Trames et paquets de données avec Scapy – Partie 2] Installation et configuration – lien

[Trames et paquets de données avec Scapy – Partie 3] Utilisation basique – lien

[Trames et paquets de données avec Scapy – Partie 4] Captures de données – lien

[Trames et paquets de données avec Scapy – Partie 5] Traceroute et visualisation 2D/3D – lien

[Trames et paquets de données avec Scapy – Partie 7] Orientation et représentation objet – lien

[Trames et paquets de données avec Scapy – Partie 8] Compléments et webographie – lien