Table of Contents

sniffer réseau

TCPdump

TCPdump est un outil d'analyse réseau qui permet de sniffer (en mode promiscuité ou non) les paquets que reçoit une interface réseau de la machine. Une version pour Windows existe : Windump.

Son utilisation classique est la suivante :

tcpdump <paramètre(s)> <filtre(s)>

A la fin d'une capture, on a le retour suivant :

0 packets captured
130 packets received by filter
35 packets dropped by kernel

Pour connaitre la taille du buffer (taille par défaut et taille max) de réception d'une socket :

sysctl net.core.rmem_default
net.core.rmem_default = 110592
sysctl net.core.rmem_max
net.core.rmem_max = 131071

On peut l'augmenter ainsi (attention, cela peut avoir un impact sur la stabilité de la machine, le faire en connaissance de cause !) :

sysctl net.core.rmem_max=1013760
sysctl net.core.rmem_default=1013760

Paramètres

Filtres

Modificateurs

Analyse avancée des entêtes

On peut préciser à tcpdump d'analyser un bout d'entête spécifique ; la syntaxe est la suivante :

proto[x:y]

On analyse à partir de l'octet x et on lit y octets. Si :y n'est pas renseigné on ne considère que l'octet x.

C'est important de connaitre le format des entêtes du protocole analysé ; par exemple pour IPv4 :

0                   1                   2                   3   
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Version|  IHL  |Type of Service|          Total Length         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|         Identification        |Flags|      Fragment Offset    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|  Time to Live |    Protocol   |         Header Checksum       |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                       Source Address                          |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Destination Address                        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Options                    |    Padding    | <-- optional
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                            DATA ...                           |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

… ou TCP :

0                   1                   2                   3   
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|          Source Port          |       Destination Port        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                        Sequence Number                        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Acknowledgment Number                      |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|  Data |           |U|A|P|R|S|F|                               |
| Offset| Reserved  |R|C|S|S|Y|I|            Window             |
|       |           |G|K|H|T|N|N|                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|           Checksum            |         Urgent Pointer        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Options                    |    Padding    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                             data                              |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Divers

tcp-urg
tcp-ack
tcp-psh
tcp-rst
tcp-syn
tcp-fin

Exemple d'utilisation : capturer tous les paquets tcp SYN et FIN :

tcpdump 'tcp[tcpflags] & (tcp-syn|tcp-fin) != 0'
icmp-echoreply
icmp-routeradvert
icmp-tstampreply
icmp-unreach
icmp-routersolicit
icmp-ireq
icmp-sourcequench
icmp-timxceed
icmp-ireqreply
icmp-redirect
icmp-paramprob
icmp-maskreq
icmp-echo
icmp-tstamp
icmp-maskreply

Exemple : capturer les paquets icmp qui ne soient pas du PING (ni echo request ni echo reply).

tcpdump ’icmp[icmptype] != icmp-echo and icmp[icmptype] != icmp-echoreply’

Exemples d'utilisation

Pour être lisible, le maître mot dans une capture est de restreindre la sortie au maximum. La première chose est donc de n'écouter que sur une seule interface réseau. Pour lister les interfaces disponibles :

tcpdump -D
 1.eth0
 2.eth1
 3.any (Pseudo-device that captures on all interfaces)
 4.lo

Puis, pour ne capturer que les trames issues ou à destination de la machine 192.168.0.1 sur l'interface eth0 :

tcpdump -i eth0 host 192.168.0.1

D'autres exemples :

tcpdump -i eth0 not host toto
tcpdump -i eth0 host toto and net 192.168.0.0/24

2 équivalents qui permettent d'inspecter l'octet n° 9 (le 10ème octet, car tcpdump compte à partir de 0) de l'entête IP

tcpdump -i eth0 'ip[9] = 1'
tcpdump -i eth0 icmp

2 équivalents pour filtrer les jumbo frame (les paquets de taille supérieure à 1518 octet, le standard Ethernet) :

tcpdump -i eth1 'len > 1518'
tcpdump -i eth1 'ip[2:2] > 600'

Filtrer les trames Ethernet (-e) dont l'adresse MAC source est 00:11:11:00:11:22 :

tcpdump -e -nni eth0 ether src 00:11:11:00:11:22

NB : l'option -nn permet d'activer le format numérique pour la sortie, c'est-à-dire pas de résolution de port (service) ni d'IP (DNS).

Filtrer les paquets fragmentés

L'exemple suivant, tiré du Misc n° 32, permet de détecter les paquets fragmentés = ceux qui ont le bit MF (more fragment) à 1. Ce bit est situé dans le 3ème bit du 7ème octet de l'entête IP. On va récupérer ip[6] et lui appliquer le masque 0010 0000 (0x20 en hexa) afin de ne sélectionner que le bit qui nous intéresse :

tcmpdump 'ip[6] & 0x20' = 32

Le résultat de cette addition logique peut être soit 0 soit 32 : en effet le masque ajouté avec un “ET” logique permet d'annuler (passer à 0) tous les autres bits ; il ne restera que le 3eme bit en partant de la gauche de l'octet, qui correspond au 6eme en partant de la droite, soit 2^6 = 32). Comme on le constate ici, tcpdump travaille par octet.

Cependant cette méthode ne tient pas compte des derniers paquets fragmentés qui ont le bit MF = 0. En revanche ceux-ci possèdent un champ fragment offset non nul :

	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
	|Flags|      Fragment Offset    |
	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Bit 0: reserved, must be zero
Bit 1: (DF) 0 = May Fragment, 1 = Don't Fragment.
Bit 2: (MF) 0 = Last Fragment, 1 = More Fragments.

Une autre façon de faire est donc de chercher les paquets dont ces champs ne sont pas vide ET dont le bit DF (Don't Fragment) n'est pas égal à 1.

tcpdump -i eth1 '((ip[6:2] > 0) and (not ip[6] = 64))'

Paquet DF

Pour filtrer les paquets “non fragmentables” (ayant le bit DF = 1, cf entêtes IP) :

tcpdump -nnv 'ip[6] = 64'

En effet on regarde le 7e octet de l'entête IP (7e octet ⇒ le n°6 puisqu'on commence à 0) ; cet octet contient les champs suivants : (cf Filtrer les paquets fragmentés).

Donc, les paquets non fragmentables doivent avoir cet octet égal à “01000000” (binaire) càd 64 en décimal.

Port tcp < 1024

Cet exemple permet de sélectionner les paquets TCP ayant un port source < 1024 :

tcpdump 'tcp[0:2]' < 1024

Ici on débute à l'octet 0 de l'entête TCP et on lit 2 octets pour sélectionner le champ “src port”, que l'on peut comparer directement à 1024.

Filtrer les paquets TCP SYN

On veut filtrer uniquement les paquets SYN du protocole TCP, mais pas les SYN-ACK. On va donc sélectionner les paquet TCP ayant le flag “SYN” à 1 et pas le flag ACK. Ceci se voit dans l'entête TCP de chaque paquet. Il s'agit du 14ème octet de chaque paquet TCP ; et comme ils sont numérotés à partir de 0, on va regarder l'octet 13, structuré ainsi :

champ → CWR ECE URG ACK PSH RST SYN FIN
ce qu'on recherche x x x 0 x x 1 x

On ne fait attention qu'au flags ACK et SYN : on veut que le premier soit à 0 et le second à 1. Ceci se traduit par l'expression suivante (on utilise un masque binaire avec un ET logique sur l'octet 13 afin de ne sélectionner que ces 2 flags, et on vérifie la valeur de l'octet 13) :

<octet 13 de chaque paquet> ET <masque> = doit être égal à 00000010 (càd 2 en décimal)
tcp[13] ET 00010010 = 00000010

Soit, en décimal :

tcp[13] ET 18 = 2

Bref :

tcpdump -i eth1 -s 40 'tcp[13] & 18 == 2'

(l'option -s spécifie de ne capturer que les 40 premiers octets de chaque paquet : en effet on ne s'intéresse qu'aux entêtes des paquets.)

Filtrer les paquets TCP FIN

On procède de la même façon que pour les TCP SYNs, mais on filtre sur le bit FIN (le bit de poids faible du 13e octet) et on ne tient pas compte du flag ACK car il est (presque ?) toujours activé de toute façon.

champ → CWR ECE URG ACK PSH RST SYN FIN
ce qu'on recherche x x x x x x x 1

Ce qui nous donne :

tcpdump -i eth1 -s 40 'tcp[13] & 1 == 1'

Filtrer les messages ICMP

La balise “icmp” permet de filtrer tous les paquets ICMP, mais on peut filtrer des messages particulier, par exemple les ICMP redirect (type=5) :

tcpdump -nni eth0 icmp[0] == 5

Pour connaitre la liste exhaustive des différents messages ICMP, go Wikipedia fr