Skip to content

Charge ICMP : Stéganographie avec le ping

Il y a quelque temps sur un site de challenge, je suis tombé sur un défi un peu spécial qui mêlait la stéganographie et le protocole ICMP. J’ai trouvé le concept intéressant et ai voulu étudier cela d’un peu plus près.

Stéganographie et cryptographie

Il est tout d’abord important de différencier la cryptographie et la stéganographie. En réalité, ces deux concepts sont plus complémentaires qu’autre chose.

La cryptographie va avoir pour but de rendre incompréhensible, voire illisible, le contenu d’un message donné. Pour faire simple, le message pourra être lu et relu, personne ne comprendra ce qu’il signifie.

La stéganographie a pour but de faire en sorte de cacher le message dans un autre objet, une image, un texte, un paquet réseau … Le but de la stéganographie est en fait de faire passer une information dans un objet qui n’est pas censé la contenir. Comme si l’on cachait un message écrit derrière un tableau. Tout le monde regardera le devant du tableau, seules la ou les personnes sachant qu’il y a quelque chose derrière regarderont derrière. Un exemple un peu simpliste, mais j’espère que vous aurez compris le principe 😉

Il est donc possible d’utiliser ces deux concepts de façon complémentaire. Nous allonschiffrer notre message puis le cacher dans une image par exemple, dans le cas où nous avons une mauvaise stéganographie et que le message est trouvé, nous aurons alors une sécurité supplémentaire puisqu’il sera chiffré. En effet, il peut être risqué de ne compter que sur la stéganographie pour cacher un message ou d’être sûr à 100% que notre chiffrement est incassable.

Cacher des informations dans des transmissions ICMP

Le principe de la charge ICMP est donc d’effectuer de la stéganographie via le protocole ICMP, un protocole qui semble au premier abord inoffensif. Quoi de plus anodin qu’un ping ?

Le principe est simple, un ping est constitué de 8 octets :

  • 1 octet pour le type
  • 1 pour le code
  • 2 pour le checksum
  • 2 pour l’identifiant
  • 2 pour le numéro de séquence

Les deux derniers éléments ne servant que pour les echo request et reply. Cependant, à la fin de chaque paquet ICMP, on peut retrouver une espace « data » de 32 octets. Le voici sur une analyse Wireshark :

icmp-charge-02Assez étonnant, il contient « abcdefgh… ». On peut donc penser qu’il est loin d’être vital.

Il se trouve que cette partie du ping est facilement modifiable, avec une option prévue à cet effet dans la commande ping sous Linux. On peut alors mettre n’importe quelles données, au format hexadécimal, à l’intérieur. Hors tout peut être converti en hexadécimal.

Par exemple :

Bonjour je suis Mickael !

Peut être encodé en hexadécimal et donnera alors :

426f6e6a6f7572206a652073756973204d69636b61656c202120

L’option permettant de remplir le « champ » data dans un paquet ICMP echo-request est « -p » .

Script Python

Pour aller plus loin dans mon étude de ce concept, j’ai écrit deux scripts permettant d’automatiser cet échange, voici leur fonctionnement :

icmp-charge

Voici le principe, nous avons d’un côté l’envoi, de l’autre côté la réception, chacun ayant un script distinct. Le poste qui envoie passe en paramètre de son script le message qu’il souhaite transmettre et l’IP du destinataire. Le script en question chiffre, découpe et envoie le message au travers des paquets ICMP echo-request. De son côté, le destinataire va avoir deux moyens de lire les paquets. Soit il prévoit une période d’écoute dans le script, qui analyse les paquets qui arrivent, repère les ICMP echo-request et essaie de lire un message à l’intérieur. Soit il lit un fichier PCAP, qui sont des enregistrements réseaux. Le script du destinataire va ensuite déchiffrer le message et l’afficher au destinataire.

Leur utilisation peut être améliorée, mais pour les curieux, je le poste ici la partie utile du code Python :

# Chiffrement du message en ROT13 et encode en hexa
 Encrypt_msg = message.encode('ROT13').encode('hex')
# Déterminer le nombre de ping à envoyer
 nb_ping = len(Encrypt_msg)/32
if len(Encrypt_msg) % 32 >= 1:
 nb_ping = nb_ping +1
send_ping = 0
 i = 0
 y = 32
# Envoie des PING avec les informations cachées dans le champ DATA
 while send_ping < nb_ping:
 msgToSend = Encrypt_msg[i:y]
 msg = "ping -c 1 -p "+msgToSend+" "+optList["Target"]
 print msg
 os.system(msg)
 send_ping = send_ping + 1
 i = i + 32
 y = y + 32

Ici nous avons le script d’envoi. Pour le décrire rapidement, il prend en réception soit un texte en clair (option -t), soit un fichier (option -f).

Le contenu de ce qui est mis en entrée est ensuite chiffré en ROT13 (un chiffrement TRÈS light, qui est juste utilisé pour l’exemple), j’encode le tout en hexadécimal par la suite. Pour finir, je détermine combien de place va prendre mon message, sachant que je ne peux envoyer que des messages de 32 octets de long. Je vais donc envoyer mon message par section de 32 octets.

Côté réception, je propose deux modes. Le premier consiste en l’écoute de l’interface réseau pendant 10 secondes (durée qui peut être réduite ou allongée facilement via la modification du paramètre…), le second mode est la lecture d’un fichier PCAP, celui-ci devra contenir des ICMP echo-request envoyés avec le script d’envoi pour être exploité, sinon il ne renverra rien. Voici le code dans le cas où l’on effectue une écoute du réseau pendant 10 secondes :

sniff_content = sniff(timeout=10)
for pkt in sniff_content:
        if pkt.type == 2048:
                if pkt[ICMP].type == 8:
                        print pkt.load[16:32].decode('ROT13')

Une fois que l’écoute réseau est faite (durant 10 secondes à l’aide de scapy), on effectue différents tris qui permettent de repérer les paquets ICMP, puis les paquets ICMP de type echo-requests, puis de ne sortir que la partie utile du paquet, le message hexadécimal mis dans la partie « data« , que l’on « déchiffre ».
Je rappelle que dans un cadre plus sérieux, il faudrait utiliser un système de chiffrement bien plus robuste que le ROT13, je l’ai utilisé uniquement à des fins de tests dans notre cas.

Qu’est ce que cela nous apprend ?

En soi, il n’y a rien de révolutionnaire dans ce que je présente ici, la simple utilisation d’un protocole réseau pour faire passer des données n’est que de la logique, ceci étant le concept même du réseau et des protocoles. Ce qui est intéressant ici, c’est d’utiliser un protocole (l’ICMP) pour une fonction qu’il n’a pas prévu de faire : envoyer et recevoir des données texte. Le ping n’étant habituellement qu’un protocole de signal.

On peut alors imaginer utiliser ce protocole pour faire passer des données, car il paraît anodin. Il sera de fait moins « surveillé » qu’un protocole comme l’HTTP ou le DNS.

Bien que cet article traite de l’ICMP, le principe même de la stéganographie peut être utilisé dans bien des contextes. Le fait étant toujours de dissimuler une information dans une autre qui paraîtra inoffensive.

Partager :
Published inArticles

4 Comments

  1. La technique est intéressante, mais ceci dit, j’ai vu plusieurs fois des réseaux qui « étouffaient » l’ICMP voire le bloquaient carrément. Donc ce n’est pas nécessairement un bon moyen pour « cacher » de l’information. J’adore le détournement malgré tout 😀
    Aussi, même si ça doit entrainer plus de paquets (toujours ce dilemme entre charge et invisibilité), il faut bien garder la taille « standard » de 32 octets, ce qui permet de moins se faire repérer avec ces paquets. Car oui, on peut tester du ping avec des paquets plus gros, mais ça pourra se voir plus facilement/rapidement en cas d’analyse.
    À relire l’article il y a quand même une sacrée contrainte, notamment sur le récepteur du message. Et capturer du trafic en permanence n’est pas nécessairement facile à faire (surtout à stocker, que ce soit en mémoire ou sur disque).

  2. Ogma_Sec

    Hello,
    Merci pour ton commentaire. Oui effectivement, l’utilisation de cette méthode est assez contraignante, je n’ai pas cherché à pousser plus loin la facilité d’écoute du récepteur. Peut être avec un service qui tourne en fond analysant les trames ou seulement les pings ?
    Le blocage du ping est une contrainte importante également, bien qu’il soit souvent bloqué en entrée et peu en sortie. Ainsi, on peut envisager par exemple un malware qui aurait pour fonctionnement d’extraire les données qu’il récupère via cette méthode, le ping étant peu bloqué en sortie.. Néanmoins dans cet exemple précis je pense qu’il existe des méthodes bien plus efficaces. 😉

  3. rinkler

    Yo, toujours pas trouver le flag dans les charges ICMP sur root-me ? Et tu oses créer un article avec un chiffrement comme ROT13 alors que si tu avais réussi ce challenge tu pourrais … *censuré valide d’abord l’épreuve*
    L’utilisation de ICMP pour un malware est assez complexe lorsqu’il est avec des privilèges utilisateurs. L’interface de la socket RAW donc créer des paquets ICMP demande généralement l’accès administrateur. Ainsi les malwares qui arrive à faire des escalades privilèges peut utiliser cette technique. Donc son usage est restreint par cette capacité.

    • Ogma_Sec

      Et non, toujours pas réussi le challenge root-me. D’ailleurs dans ce challenge, la difficulté est plus de casser le chiffrement que de trouver l’endroit où le message est caché. Ce que je souhaite montrer ici n’est pas la solution à ce challenge. Je ne site d’ailleurs nul part le site ou ce challenge ce trouve. Je trouvais juste intéressant la façon dont on peut utiliser l’ICMP.
      Le principe du challenge n’est pas forcément de le réussir mais d’apprendre des choses, ce que je fait ici. D’ailleurs ce challenge possède une solution toute faite si on sait utiliser Google correctement.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *