Kali-linux distribution GNU/Linux spécialisée dans l'audit et le pentest.
Kali-linux.fr Communauté française de kali-linux
tuto manipulation de paquets scapy python kali linux

Scapy, le grand gourou

“And IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII WILL ALWAYS LOVE Y….” Oh mince vous êtes la ?!?! CPU lance vite le programme tuto.exe !!!

Bonjour/Bonsoir à tous !

Aujourd’hui dans ce tuto on va s’attaquer à une librairie python bien pratique et très connue il s’agit de … Pygam…Scapy ! Attachez vos ceintures c’est parti !

“Hey mais c’est quoi scapy !? et d’ailleurs c’est quoi python !? ça vit en Amazonie ?”

Tu as raison je vais un peu vite ! alors voilà ! :

Python est un langage de programmation interprété, en somme cela veut dire que c’est un programme qui se charge de traduire les instructions python en programme machine de manière séquentielle (enfin pas dans tout les cas).

Scapy est une libraire du langage python qui permet de manipuler facilement des objets ou des structures permettant de faire du réseau au sens large du terme : connexions TCP, Sockets etc.. Pour ceux qui sont à un stade un peu plus avancé dans la programmation Scapy n’est pas vraiment une librairie mais un framework complet écrit en python. Pour plus d’informations je vous renvoie à la page Wikipédia de celui ci :

https://fr.wikipedia.org/wiki/Scapy

Ce tuto est destiné aux gens qui savent au moins se servir un peu de python et de linux et qui ont déjà des bases en réseaux, je parlerai très peu de python en lui même mais bel et bien de la librairie Scapy et de ses possibilités. Scapy étant une librairie assez conséquente il me sera impossible d’en montrer toutes les utilisations possibles mais j’espère vous donner les bases et l’envie d’aller plus loin !

I) Les bases

Bon ben pour commencer va falloir forcément installer Scapy !

“Woooow bravo on s’en serait pas douté ! Quoi d’autre Captain ? ”

Oui oui je sais… Mais en fait il existe plusieurs façon d’installer Scapy !

“Quelle surprise ! “

Et oui ! Donc ici je vais vous montrer comment installer la version de Scapy la plus “basique”, la plus légère, ce sera amplement suffisant pour vous le faire découvrir.

Il est évidemment nécessaire d’avoir python d’installé….

Pour installer Scapy sous vôtre linux préféré c’est très simple :

pip install scapy

Si vous êtes sous kali comme moi, Scapy est normalement déjà installé, le cas contraire il faudra utiliser pip comme ci-dessus.

Une fois installé on lance Scapy via un terminal en tapant…… :

scapy


Nous voici maintenant sur l’interpréteur de Scapy !

Comme je vous le disais Scapy comporte beaucoup de choses, bien trop pour pouvoir couvrir tout dans un tuto, néanmoins en utilisant les commandes suivantes sous l’interpréteur de Scapy vous aurez une bonne idée de tout ce qu’il est possible de faire avec :

ls();

Cette commande va vous permettre entre autre d’afficher les protocoles disponibles d’utilisation avec Scapy, il y en a plus de 150 mais en voici un extrait..

lsc();

La commande suivante permet quant à elle d’afficher la liste des fonctions que vous pourrez utiliser :

Encore une fois, il y a une multitude de choix…..

“Avec tout ça on est un peu perdu… On fait quoi du coup…?”

Oui en effet vous avez raison une fois de plus ! Passons à la suite.

Pour en finir avec les bases nous allons simplement faire un ping avec Scapy ! Pour ce faire l’idée va être la suivante :

A-Nous allons fabriquer un paquet

B-Nous allons l’envoyer

Simple non ? Je vous conseille dans un premier temps de lire ceci ou du moins d’y jeter un oeil : https://www.frameip.com/entete-icmp/

Cela pourra vous servir pour la suite.

“Comment on fait ça alors ?!!!”

Voilà comment :

A) Fabrication du paquet

mon_paquet= ICMP()

Ici nous créons un paquet ICMP, pour l’instant il est vide, comme nous pouvons le voir :

mon_paquet.show()

Ici on remarque que le paquet ICMP est par défaut en mode echo-request ce qui nous arrange. Comme vous avez tous fait un peu de réseau je pense que vous remarquez que pour l’instant rien ne nous permet de faire un ping, en effet un paquet ICMP ne contient pas de champ IP, vu que c’est le paquet IP qui contient ce champ. Nous allons donc devoir ajouter une entête IP au paquet ICMP en l’encapsulant :

 mon_paquet = Ether() / IP(dst='192.168.1.1') / ICMP()


Le paquet est maintenant créé, regardons ce qui se trouve dedans :

mon_paquet.show()

Ici vous l’aurez compris on va ping une adresse qui correspond chez moi à ma box mais vous pouvez changer l’IP bien entendu.

Comme vous le remarquez certainement ici, certains champs sont automatiquement remplis par Scapy comme par exemple le champ ‘src’ de l’entête IP, mais il est évident que nous pourrions remplir ces champs nous même.

B) Envoi du paquet

Pour envoyer le paquet il suffit de faire :

sendp(mon_paquet)

“Heu ouais ok et c’est tout ? on fait quoi maintenant ? Je sens que ce tuto tourne en rond…..”


Ne vous inquiétez pas je vous assure que le paquet est bien envoyé ! Mais il nous manque juste un petit truc…. De quoi recevoir le paquet qui nous reviens, pour ce faire nous allons demander à Scapy de stocker les informations de retour de la fonction ‘srp’ dans deux paquets différents, en effet la fonction ‘srp’ renvoie 2 objets distincts :

-les paquets émis et les réponses de ces paquets

-les paquets n’ayant aucune réponses

Pour faire d’une pierre deux coups nous procédons de la manière suivante :

rep_positive,rep_negative = srp(mon_paquet)


Tout semble bien se passer, consultons le contenu des réponses :

rep_positive
rep_negative

Nous remarquons qu’ici une réponse ICMP est arrivée, et qu’à priori aucune erreur n’est survenue, consultons maintenant les détails de l’entête ICMP :

rep_positive.show()

Nous avons donc bien reçu une réponse ICMP !

Mais en fait il est possible d’avoir plus de détails, en effet ‘rep_positive’ est une liste (je vous rappelle que nous sommes dans un framework basé sur Python !) et cette liste contient des couples de paquets, dans notre cas la liste ne contient que 2 paquets :

rep_positive[0]

Le résultat étant un tuples on l’affiche de cette manière :

rep_positive[0][0].show()

cela correspond au paquet envoyé, pour afficher le paquet reçu de la même manière on peut utiliser :

rep_positive[0][1].show()



Bravo les amis vous avez fait un ping !

“Ouais mais sinon on pouvait juste faire un ping avec notre terminal on aurais gagné 8 jours non ?”

Certes jeune padawan, mais Scapy comme tu l’a vu te permets de construire les paquets pas à pas et de pouvoir modifier tout les champs, ce qui sera difficile voir impossible avec juste une commande ping et c’est franchement très pratique dans certains cas 😉


II) Voici Otis, mon scribe… Heu mon script

Comme nous l’avons vu dans la partie précédente, il est possible d’utiliser Scapy sous forme d’un interpréteur python mais comme je vous l’avais dis plus tôt, Scapy peut servir également de librairie, ce qui signifie que nous pouvons écrire un script python qui embarque toutes les fonctionnalités de Scapy.

Reprenons le ping que nous avons fait précédemment et transformons le en script, ce qui nous donnera :


#!/usr/bin/env python
# -*- encoding: utf-8 -*-
from scapy.all import *

#ICMP PING#

host="IP à scanner"  #L'ip que l'on va scanner...
rep, rep_neg = sr(IP(dst=host)/ICMP()) #voir détails plus bas
rep.summary(lambda (s, r): r.sprintf("%IP.src% te dit coucou"))  #affiche le resultat



Le code est très simple à comprendre normalement ! mais pour ceux qui se demandent ce qu’est donc la fonction sr(…) voici ce que nous dis Scapy :

Pour faire simple, la fonction permet d’envoyer ou de recevoir un paquet en couche 3, et c’est exactement ce que l’on veut ici ça tombe bien !

Pour lancer le script c’est comme pour lancer un script python normal :

python mon_script.py

Voici un petit retour de ce qu’affiche le script chez moi :

“Wow trop bien et qu’es ce que je fais si je veux faire un ping sur plusieurs machines du même réseau à la fois ? Il faut que je donne plusieurs hosts à chaque fois ?”

Et bien oui et non ! Oui car au fond la requête sera envoyer une fois à chaque adresse et non car il n’y a pas besoin de remettre les adresses une par une ce serait bien trop ennuyeux ! une méthode magique existe, la voici !


#!/usr/bin/env python
# -*- encoding: utf-8 -*-
from scapy.all import *

#ICMP PING#

host="Range d'IP"  #l'intervalle d'IP à scanner
rep, rep_neg = sr(IP(dst=host)/ICMP()) #voir détails plus bas
rep.summary(lambda (s, r): r.sprintf("%IP.src% te dit coucou"))  #affiche le resultat

La range d’IP comme dans le code ci dessus sera présenté sous cette forme par exemple, pour scanner les machines allant de 10.0.2.0 à 10.0.2.15 on écrira :

host="10.0.2.0-15"  #l'intervalle d'IP à scanner


“Splendide !”

Encore mieux ! il est possible de donner directement un réseau et le CIDR associé en faisant ceci :

rep, rep_neg = sr(IP(dst="IP/CIDR")/ICMP())

Ce qui donne par exemple :

rep, rep_neg = sr(IP(dst="10.0.0.0/8")/ICMP())


On peut même également donner une liste d’adresse :

rep, rep_neg = sr(IP(dst=["1.2.3.4", "2.3.4.5", "5.6.7.8"])/ICMP()) 

III) Les dents de la mer…

Pour finir ce petit tuto je vais vous montrer comment on peut facilement enregistrer grâce à Scapy des échanges au format .PCAP pour ensuite les lire avec Wireshark ou même les rejouer avec tcpreplay !

“MAIS ! depuis quand tu es aussi fort toi !!?”

Hahaha je suis imprévisible ! Pour éviter que ce tuto soit aussi long que la Muraille de Chine nous allons prendre un exemple très simple :

#!/usr/bin/env python
# -*- encoding: utf-8 -*-
from scapy.all import *

host="IP à scanner"  #L'ip que l'on va scanner...
rep, rep_neg = sr(IP(dst=host)/ICMP()) 
wrpcap("tartine.pcap", rep) #ecriture du contenu de rep dans le fichier

Ici nous créons donc un fichier au format PCAP nommé “tartine”, ce fichier contiendra tout les échanges stockés dans ‘rep’.

Par exemple dans mon cas si je ping les machines allant de 10.0.2.2 à 10.0.2.4 le contenu du paquet sera :

IV) Le mot de la fin

Comme nous l’avons vu dans ce tuto, Scapy permet de faire beaucoup de choses, de l’arp spoofing, passant par le ping, jusqu’aux requêtes DNS et même le fuzzing.

Scapy peut sembler un peu difficile au premier abord mais il permet de manipuler les paquets avec une précision chirurgicale ce qui en fait un outils puissant et utile dans pleins de circonstances !

Pour ce tuto je me suis concentré sur les requêtes ICMP mais il est bien évident que toutes les formes de requêtes, du moins la plupart sont possible avec Scapy.

Merci à tous d’avoir suivis ce tuto et j’espère vous revoir très vite !

“Ouais bah pas nous !”

Mouhahahahahaha je reviendraiiiiiiiiiiiiiiiiiiii……….

ZeR0-@bSoLu

PS: pour ceux qui le souhaitent voici une petit cheat sheet très pratique :

https://github.com/rewardone/OSCPRepo/blob/master/CheetSheets/Networking/ScapyCheatSheet_v0.2.pdf




4 thoughts on “Scapy, le grand gourou”
  1. Encore une découverte qui va faire mal <3

    Je ne connaissais pas Scapy !! Merci ZeR0-Di3u-AbSoLu.

    Question qui peut paraître con mais étant donné que chaque information que nous allons échanger/envoyer/recevoir avec un quelconque serveur sera sous forme de paquets, est il envisageable de découper un script (reverse shell à tout hasard), et l'envoyer sous forme de paquets avec Scapy ?

    (Je découvre ce soft donc je pose peut être une question débile encore une fois)

    Petit tips : Le lien vers le sheet est hs mais je l'ai retrouvé sur Github :

    https://github.com/rewardone/OSCPRepo/blob/master/CheetSheets/Networking/ScapyCheatSheet_v0.2.pdf
    )

    1. Merci beaucoup pour ton retour, j’ai mis le lien à jour grâce à ton aide 🙂
      Pour répondre à ta question, oui cela est possible si tu programmes tout simplement ce script avec scapy 🙂

  2. Bonjour,

    Très bon tutoriel, en revanche je me suis un peu étranglé arrivé à la phrase “ICMP ne contient pas de champ IP, vu que c’est la trame Ethernet qui contient ce champ”. La trame Ethernet ne contient pas ce champ, c’est le paquet IP qui la contient, d’ailleurs, l’exemple le montre bien avec l’appel à IP() et les 2 encapsulations (Ethernet puis IP)

    1. Merci pour la remarque ,
      Je suis bien conscient que c’est le paquet IP qui détient cette information, néanmoins je ne voulais pas rentrer trop dans les détails et je comptais sur le fait que ce n’était pas dans l’absolu le point important du sujet.
      Je vais modifier cela car ta remarque me fait rendre compte que en effet cela peut porter à confusion.

Leave a Comment

Time limit is exhausted. Please reload CAPTCHA.