Tcpdump
Introduction à tcpdump
Par Tony
L'outil
tcpdump est un outil de capture et d'analyse réseau. Il permet d'avoir une analyse en direct du réseau ou d'enregistrer la capture dans un fichier afin de l'analyser pour plus tard. Il permet d'écrire des filtres afin de sélectionner les paquets à capturer/analyser.
Il est basé sur la libpcap pour la capture, ce qui permet à ses sauvegardes d'être compatible avec d'autres analyseurs réseaux, comme Wireshark (anciennement Ethereal). Cette bibliothèque étant multiplateforme, tcpdump est lui aussi porté sur la plupart des architectures.
C'est un outil indispensable à l'administration et au débugage d'applications réseaux.
Présentation d'une capture
# tcpdump -n -i ppp0
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ppp0, link-type LINUX_SLL (Linux cooked), capture size 96 bytes
01:04:28.531663 IP 71.197.145.153.46872 > 90.2.255.58.37727: . ack 816315239 win 65535 <nop,nop,timestamp 20729106 202488928>
01:04:28.539138 IP 90.2.255.58.37727 > 71.197.145.153.46872: . 9801:11201(1400) ack 0 win 2003 <nop,nop,timestamp 202489014 20729106>
01:04:28.569227 IP 81.242.185.212.17936 > 90.2.255.58.38835: . ack 1861880354 win 63552 <nop,nop,timestamp 522312 202488943,nop,nop,sack 1 {2801:4201}>
01:04:28.569286 IP 90.2.255.58.38835 > 81.242.185.212.17936: . 4201:5601(1400) ack 0 win 182 <nop,nop,timestamp 202489023 522312>
01:04:28.586301 IP 71.197.145.153.46872 > 90.2.255.58.37727: . ack 2801 win 65535 <nop,nop,timestamp 20729106 202488950>
01:04:28.586362 IP 90.2.255.58.37727 > 71.197.145.153.46872: . 11201:12601(1400) ack 0 win 2003 <nop,nop,timestamp 202489027 20729106>
01:04:28.609962 IP 71.197.145.153.46872 > 90.2.255.58.37727: . ack 5601 win 65535 <nop,nop,timestamp 20729107 202488958>
01:04:28.610020 IP 90.2.255.58.37727 > 71.197.145.153.46872: . 12601:14001(1400) ack 0 win 2003 <nop,nop,timestamp 202489033 20729107>
01:04:28.646915 IP 71.197.145.153.46872 > 90.2.255.58.37727: . ack 8401 win 65535 <nop,nop,timestamp 20729107 202488966>
01:04:28.646977 IP 90.2.255.58.37727 > 71.197.145.153.46872: . 14001:15401(1400) ack 0 win 2003 <nop,nop,timestamp 202489042 20729107>
01:04:28.647007 IP 90.2.255.58.37727 > 71.197.145.153.46872: . 15401:16801(1400) ack 0 win 2003 <nop,nop,timestamp 202489042 20729107>
11 packets captured
22 packets received by filter
0 packets dropped by kernel
Les options avec lesquelles ont été invoquées tcpdump ne sont pas importantes ici. Elles sont détaillées à la section suivante.
Détails champ à champ de la ligne bleue (attention, le format de sortie dépend du type de protocole analysé et des options passées) :
- l'heure
- le type de protocole (ici, IP)
- l'IP source.port_source > l'IP destination.port_destination
- les flags TCP : il peut y en avoir plusieurs pour un même paquet, on verra apparaître les lettres suivantes pour symboliser un drapeau levé :
- S (SYN)
- F (FIN)
- P (PUSH)
- R (RST)
- W (ECN CWR)
- E (ECN-Echo)
- ou juste un point comme ici quand on n'a pas de drapeaux
- ack numéro : le numéro de séquence que l'on attend de la part de l'autre interlocuteur à son prochain envoie de paquets
- win numéro : le numéro représente la taille de la fenêtre TCP
- <des options> : les options TCP portées par le paquet, ici, on n'a que le timestamp
Les trois dernières lignes de la capture représentent :
- 11 packets captured : c'est le nombre de paquet que tcpdump a reçu de l'OS et a traité
- 22 packets received by filter : c'est le nombre de paquets qui ont été capturés car ils correspondaient aux filtres, cela ne signifie pas qu'ils auront été traités par tcpdump
- 0 packets dropped by kernel : les paquets qui n'ont pas été capturés par l'OS car il n'y avait pas assez de place dans son buffer de réception.
Les options importantes
Voici une liste des options importantes avec leurs utilités:
- -S: permet à tcpdump de suivre les sessions TCP, ainsi il calculera des numéros de séquence relatif au premier numéro de séquence qu'il a reçu. Cette option a un contre-coup, elle fait consommer de la mémoire afin de sauvegarder les informations sur les sessions en cours, donc ne vous étonnez pas de voir la RAM prise par tcpdump grossir si cette option est activée.
- -p: dit à tcpdump de ne pas passer l'interface en mode "promiscous", alors celui-ci ne pourra capturer que les paquets qui sont adressé à la machine qui capture, il n'analysera pas les autres paquets qui peuvent passer sur le cable. Notez que cela peut permettre d'échapper aux outils de détection de sniffer (qui essayent de savoir si une machine du réseau possède une interface en mode "promiscous" par diverses techniques), mais cela fait de par la même occasion perdre une partie de l'intérêt du sniffing.
- -n: tcpdump ne convertira pas les adresses et les numéros de ports en leurs noms. Pour les numéros de ports, en général, ce n'est pas bien grave, cela ne prend pas beaucoup de temps (c'est en local), mais pour les adresses, la recherche inverse de DNS peut-être un peu longue, elle peut alors ralentir TPCdump.
- -i nom_interface : permet de choisir l'interface d'écoute. Par défaut, tcpdump écoute la première interface qu'il trouve. Si vous souhaitez écouter toutes vos interfaces à la fois, vous pouvez spécifier "any" à la place d'un nom d'interface, cela aura pour effet d'écouter TOUTES vos interfaces. (sous GNU/Linux "ifconfig -a" vous affiche toutes les interfaces réseaux de votre machine)
- -w lefichier.pcap : enregistre toute la capture dans le fichier fichier.pcap. Cela permet de réanalyser le trafic plus tard. Le format PCAP étant reconnu par Wireshark, cela permet de donner le fichier à analyser à Wireshark pour une analyse plus fine des champs.
- -r lefichier.pcap : le complémentaire de l'option précédente, qui permet de relire un fichier d'une session précédente. Peut notamment être utilisé sur une machine qui n'a pas le réseau ou autre pour une analyse post-mortem.
- -s taille_de_la_capture : la taille de la fenêtre de capture. C'est la taille maximale que pourra faire un paquet capturé, au-delà de cette taille, la fin du paquet sera tronquée. Il peut être parfois intéressant de capturer les paquets complets, dans ce cas, il est possible de spécifier comme taille de capture 0 et tcpdump capturera alors l'intégralité du paquet quelque soit sa taille.
- -v : permet d'afficher encore plus d'informations sur les paquets, il y a trois niveaux de verbosité. Le nombre de 'v' correspond au niveau de verbosité.
- -X : affiche les paquets en hexadécimal et en ASCII. Assez utile pour analyser les protocoles basés sur le texte (HTTP, POP3, etc).
Les règles utiles
tcpdump dispose d'un filtre puissant des paquets nommés BPF (abréviation de BSD packet filter). Cette section ne détaillera pas en profondeur toutes les possibilités des filtres, mais se chargera de détailler les exemples qui se trouvent dans le manuel. Vous êtes donc invité à lire le manuel si vous désirez plus de précisions (de plus ces règles, sont celles données en exemple dans le manuel).
Une règle simple qui ne permet d'écouter qu'un hôte précis :
tcpdump host le_nom_de_lhote
Une règle un peu plus complexe qui écoute une hôté précis et son port :
tcpdump host le_nom_de_lhote port le_port
Écouter tout le trafic entre l'hôte 1 et l'hôte 2 ou 3 (les antislashs devant les parenthèses servent à ne pas faire interpréter ses dernières par un shell) :
tcpdump host hote1 and \( hote2 or hote3 \)
Tous les paquets IP entre l'hôte 1 et le reste du réseau, sauf l'hôte 2 :
tcpdump ip host hote1 and not hote2
Pour afficher les paquets SYN et le paquets FIN de chaque session TCP d'un hôte qui n'est pas sur notre réseau :
tcpdump 'tcp[tcpflags] & (tcp-syn|tcp-fin) != 0 and not src and dst net ladresse_du_reseau_local'
Pour afficher tous les paquets HTTP sur IPv4 qui viennent ou arrivent sur le port 80 et qui ne contiennent que des données (pas de SYN, pas de FIN, pas de paquet ne contenant qu'un ACK):
tcpdump 'tcp port 80 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)'
Quelques exemples de capture
Une capture d'une session HTTP entre un client et son serveur
On veut ici écouter le trafic entre tous les serveurs HTTP et tous leurs clients sur l'interface réseau eth0, on ne veut ici que 10 paquets qui vérifient cette règle.
#tcpdump -vv -i eth0 -X port http -c 10 15:29:46.668822 IP (tos 0x0, ttl 64, id 10981, offset 0, flags [DF], proto: TCP (6), length: 608) 192.168.1.3.60963 > 192.168.1.100.http : P 1:557(556) ack 1 win 46 <nop,nop,timestamp 2537037 1662948> 0x0000: 4500 0260 2ae5 4000 4006 89fb c0a8 0103 E..`*.@.@....... 0x0010: c0a8 0164 ee23 0050 55ef 9cb0 4dbd 2dde ...d.#.PU...M.-. 0x0020: 8018 002e 860a 0000 0101 080a 0026 b64d .............&.M 0x0030: 0019 5fe4 4745 5420 2f6d 6564 692f 2048 .._.GET./medi/.H 0x0040: 5454 502f 312e 310d 0a48 6f73 743a 2031 TTP/1.1..Host:.1 0x0050: 3932 92
On note ici l'intérêt d'afficher en hexadécimal et en ASCII le paquet car comme le protocole HTTP est un protocole texte, on peut y voir des informations intéressantes. On voit clairement ici que le client fait une GET sur le serveur (on savait déjà que c'était le client qui envoyait des informations au serveur sur ce paquet, mais sans l'affichage en mode ASCII, on aurait eu plus de mal à définir l'action exacte).
Introspection d'une capture d'une session SSH
Ici, on inspecte une session ssh lancée en local (ssh localhost).
# tcpdump -vv -i lo -XX port ssh tcpdump: listening on lo, link-type EN10MB (Ethernet), capture size 96 bytes 15:27:21.166503 IP (tos 0x0, ttl 64, id 31969, offset 0, flags [DF], proto: TCP (6), length: 60) localhost.43630 > localhost.ssh: S, cksum 0x19bd (correct), 1276248378:1276248378(0) win 32792 <mss 16396,sackOK,timestamp 2391515 0,nop,wscale 7> 0x0000: 0000 0000 0000 0000 0000 0000 0800 4500 ..............E. 0x0010: 003c 7ce1 4000 4006 bfd8 7f00 0001 7f00 .<|.@.@......... 0x0020: 0001 aa6e 0016 4c12 013a 0000 0000 a002 ...n..L..:...... 0x0030: 8018 19bd 0000 0204 400c 0402 080a 0024 ........@......$ 0x0040: 7ddb 0000 0000 0103 0307 }......... 15:27:21.172752 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto: TCP (6), length: 60) localhost.ssh > localhost.43630: S, cksum 0x52d7 (correct), 1282931829:1282931829(0) ack 1276248379 win 32768 <mss 16396,sackOK,timestamp 2391515 2391515,nop,wscale 7> 0x0000: 0000 0000 0000 0000 0000 0000 0800 4500 ..............E. 0x0010: 003c 0000 4000 4006 3cba 7f00 0001 7f00 .<..@.@.<....... 0x0020: 0001 0016 aa6e 4c77 fc75 4c12 013b a012 .....nLw.uL..;.. 0x0030: 8000 52d7 0000 0204 400c 0402 080a 0024 ..R.....@......$ 0x0040: 7ddb 0024 7ddb 0103 0307 }..$}..... 15:27:21.172868 IP (tos 0x0, ttl 64, id 31970, offset 0, flags [DF], proto: TCP (6), length: 52) localhost.43630 > localhost.ssh: ., cksum 0x3afa (correct), 1:1(0) ack 1 win 257 <nop,nop,timestamp 2391516 2391515> 0x0000: 0000 0000 0000 0000 0000 0000 0800 4500 ..............E. 0x0010: 0034 7ce2 4000 4006 bfdf 7f00 0001 7f00 .4|.@.@......... 0x0020: 0001 aa6e 0016 4c12 013b 4c77 fc76 8010 ...n..L..;Lw.v.. 0x0030: 0101 3afa 0000 0101 080a 0024 7ddc 0024 ..:........$}..$ 0x0040: 7ddb }. 15:27:21.182235 IP (tos 0x0, ttl 64, id 33194, offset 0, flags [DF], proto: TCP (6), length: 72) localhost.ssh > localhost.43630: P, cksum 0xfe3c (incorrect (-> 0x8529), 1:21(20) ack 1 win 256 <nop,nop,timestamp 2391531 2391516> 0x0000: 0000 0000 0000 0000 0000 0000 0800 4500 ..............E. 0x0010: 0048 81aa 4000 4006 bb03 7f00 0001 7f00 .H..@.@......... 0x0020: 0001 0016 aa6e 4c77 fc76 4c12 013b 8018 .....nLw.vL..;.. 0x0030: 0100 fe3c 0000 0101 080a 0024 7deb 0024 ...<.......$}..$ 0x0040: 7ddc 5353 482d 322e 302d 4f70 656e 5353 }.SSH-2.0-OpenSS 0x0050: 485f 342e 330a H_4.3. 15:27:21.184787 IP (tos 0x0, ttl 64, id 31971, offset 0, flags [DF], proto: TCP (6), length: 52) localhost.43630 > localhost.ssh: ., cksum 0x3ac4 (correct), 1:1(0) ack 21 win 257 <nop,nop,timestamp 2391534 2391531> 0x0000: 0000 0000 0000 0000 0000 0000 0800 4500 ..............E. 0x0010: 0034 7ce3 4000 4006 bfde 7f00 0001 7f00 .4|.@.@......... 0x0020: 0001 aa6e 0016 4c12 013b 4c77 fc8a 8010 ...n..L..;Lw.... 0x0030: 0101 3ac4 0000 0101 080a 0024 7dee 0024 ..:........$}..$ 0x0040: 7deb
Ici, on a très peu d'informations. Tout le contraire d'un protocole texte, car en plus, celui-ci est chiffré. Les seuls informations visibles à l'oeil sont que l'on écoute une session TCP qui se passe sur le port SSH par défaut et que le client se connecte sur un serveur OpenSSH en version 4.3 (la version du protocole SSH est 2.0 par contre).
Je n'arrive pas à capturer
Voici quelques indices pour vous aider à trouver le problème dans un cas général :
- Vous n'écoutez pas la bonne interface réseau, bête, mais ça peut arriver, surtout si vous ne précisez pas à tcpdump l'interface réseau à écouter alors que vous en avez plusieurs ;
- Vous êtes sur un switch, celui-ci n'est sensé diriger que votre trafic sur le réseau, donc si vous avez une machine qui agit comme une sonde (c'est à dire sans adresse IP, qui se contente d'écouter) il se peut que le switch n'ait pas de paquets pour vous. Certains switchs d'assez haut niveau ont des options de configurations afin de mettre certains ports en recopie de tout le trafic (afin justement de pouvoir l'analyser). Il existe certaines techniques pour faire passer un switch en hub (c'est à dire répéter les paquets sur tous les ports) mais comme ceci constitue une forme d'attaque, cela ne sera pas développé ici (de plus, les nouveaux switchs sont de moins en moins vulnérables à ces attaques) ;
- Vous n'avez pas mis votre interface réseau en mode "promiscous". Le mode "promiscous" est le mode où la carte peut lire tous les paquets du réseau, même ceux qui ne lui sont pas destiné (avec une adresse MAC différente de la sienne par exemple pour une carte Ethernet). Normalement, tcpdump passe automatiquement les interfaces en mode "promiscous", si ce n'est pas le cas chez vous, c'est probablement qu'il n'a pas réussi, dans ce cas c'est que votre carte réseau ne supporte pas le mode "promiscous".
Je ne capture que mon trafic
Si c'est le cas, comme explicité plus haut, vous êtes surement dans une des deux configurations suivantes:
- Vous n'êtes pas en mode "promiscous", à moins que vous ayez expressément spécifié à tcpdump de ne pas s'y mettre, c'est sûrement un problème de carte réseau ;
- Vous êtes sur un switch.
Je ne capture rien à part de l'ARP
Il est fortement probable que vous soyez alors sur un switch que ne vous recopie pas tous les paquets sur votre interface. Vous recevez alors les paquets ARP de l'annonce de nouvelles machines ou autre (en fait, il suffit que l'adresse MAC soit celle de broadcast). Cela doit vous conforter dans l'idée d'être sur un switch si vous ne recevez que ces paquets.
J'ai toujours quelques (voire un nombre important de) paquets qui sont "dropped by kernel"
Bon, en fait, je ne sais pas si c'est un problème connu ou non, mais quand il y a un trafic trop important de paquets, il arrive que la machine n'arrive pas à traiter assez rapidement les paquets et finisse par les "dropper" (rejeter). Vous pouvez faire gagner du temps CPU en ne faisant pas traiter les paquets en live et en écrivant dans un fichier, ou vous pouvez vous attaquer au corps du problème. Le problème vient de la taille de la socket de récéption qui en général est trop petite. Voici chez moi, la taille de la socket d'écoute par défaut et la taille maximale :
#sysctl net.core.rmem_default net.core.rmem_default = 506880 #sysctl net.core.rmem_max net.core.rmem_max = 506880
C'est parfois un peu trop petit pour un trafic important, pour régler ce problème, il suffit d'augmenter la taille de la socket, on peut faire comme il suit:
# sysctl net.core.rmem_max=1013760 net.core.rmem_max = 1013760 # sysctl net.core.rmem_default=1013760 net.core.rmem_default = 1013760
Ici, je me suis contenté de doubler ces valeurs. Vous pouvez bien entendu encore les augmenter. Mais sachez que cette méthode va allouer un buffer de la taille que vous fixerez pour chaque socket d'écoute. Donc sur une machine qui n'est pas dédiée à l'écoute, vous ne pourrez pas trop monter cette valeur (la machine risque d'avoir beaucoup de socket d'ouverte, donc un besoin d'allouer beaucoup de mémoire).
Il existe un patch non officiel pour la libpcap (sur laquelle se base tcpdump) pour pouvoir changer la taille de la socket d'écoute (ce qui reviendrait ici à modifier net.core.rmem_max pour l'augmenter et modifier la socket de la libpcap afin d'augmenter sa taille, mais ne pas augmenter cette taille pour tous les programmes).
Liens utiles
Les liens suivants sont en anglais, ils pointent pour la plupart vers certaines parties du site officiel :
- http://www.tcpdump.org/faq.html : les questions fréquemment posées, les problèmes les plus rencontrés.
@ Retour à la rubrique Réseau et sécurité
Copyright
© 2007, 2010 Tony Cheneau
Vous avez l'autorisation de copier, distribuer et/ou modifier ce document suivant les termes de la GNU Free Documentation License, Version 1.2 ou n'importe quelle version ultérieure publiée par la Free Software Foundation; sans section invariante, sans page de garde, sans entête et sans page finale. |