Tcpdump es la mejor herramienta de línea de comandos en Linux y Unix para analizar e interceptar tráfico de red entrante y saliente de las redes a las que el equipo en el que se ejecuta está conectado. Son necesarios privilegios de superusuario en la mayoría de sistemas Unix para poder ejecutarlo, aunque es posible establecer la configuración de tal forma que pueda ser utilizado por usuarios sin privilegios de superuser. Para la captura de paquetes, tcpdump utiliza la librería libpcap.
Además de esnifar tráfico o capturar paquetes de red, tcpdump también puede leer el contenido de un fichero en el cual previamente se han volcado los paquetes de red. También puede escribir en salida estándar (por defecto) o a un fichero el tráfico capturado.
Vamos con lo interesante, que es el modo de utilizar la herramienta y los parámetros más básicos y comunes que se aplican para capturar paquetes.
Interfaz de red a capturar
Para capturar todo el tráfico de entrada y salida de una interfaz de red concreta (eth0, eth1…), se utiliza parámetro «-i» seguido del identificador de interfaz en el sistema operativo:
# tcpdump -i eth0 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes [...] ^C 3 packets captured 3 packets received by filter 0 packets dropped by kernel
Como podéis observar, al final de la ejecución, cuando cancelamos (CTRL + C) se muestran las estadísticas de paquetes capturados, recibidos por los filtros especificados y los filtrados por el kernel.
Para ver un listado de las interfaces disponibles para capturar tráfico con tcpdump, le pasamos el parámetro «-D»:
# tcpdump -D 1.eth0 2.ppp0 3.usbmon1 (USB bus number 1) 4.usbmon2 (USB bus number 2) 5.any (Pseudo-device that captures on all interfaces) 6.lo
Capturar tráfico y enviar a un fichero de texto
Por defecto el dump del tráfico es redirigido a salida estándar, podemos volcarlo a un fichero con el parámetro «-w» seguido del fichero:
# tcpdump -i eth0 -w trafico.log
Protocolo a capturar (TCP, UDP, ICMP, ARP…)
Además de especificar la interfaz de red por la que queremos capturar tráfico, también podemos especificar si el tráfico a capturar es TCP, UDP, ICMP, ARP…:
# tcpdump -i eth0 udp
# tcpdump -i eth0 tcp
# tcpdump -i eth0 icmp
Puerto a capturar
Podemos seguir acotando… ahora además del protocolo especificamos el puerto sobre el cual queremos capturar el tráfico, por ejemplo el puerto TCP 80 para capturar tráfico HTTP:
# tcpdump -i eth0 tcp port 80
O el tráfico DNS por el puerto UDP 53:
# tcpdump -i eth0 udp port 53
Host o IP de origen/destino
Especificamos todavía más, capturamos el tráfico TCP por el puerto 80, pero sólo visualizamos el tráfico originado desde la IP 192.168.1.100. Para ello usamos el parámetro «src«. Como estamos utilizando más de un parámetro, debemos comenzar a añadir condicionales (and|or). El siguiente ejemplo captura el tráfico que cumple las dos condiciones, puerto TCP 80 y origen IP 192.168.1.100:
# tcpdump -i eth0 tcp port 80 and src 192.168.1.100
Al igual que existe IP/host de origen, existe de destino, el parámetro es «dst«. En este ejemplo usamos el condicional «or» en lugar de «and», de modo que para que se capture tráfico, o viene por el puerto 80 TCP o tiene destino la IP 192.168.1.100 (sea cual sea el puerto y protocolo):
# tcpdump -i eth0 tcp port 80 and dst 192.168.1.100
Mostrar el contenido de los paquetes en formato ASCII
El parámetro «-A» volcará el contenido del paquete en formato ASCII:
# tcpdump -i eth0 -A tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes 13:41:57.767709 IP 192.168.1.100.58709 > 239.255.255.250.1900: UDP, length 97 E..}4....... o. 10.111.2.52.domain: 12422+ PTR? 250.255.255.239.in-addr.arpa. (46) E..J..@.@.S.o.> o.4...5.6=.0............250.255.255.239.in-addr.arpa..... 13:41:57.769498 IP 10.111.2.52.domain > www.test.com.33972: 12422 NXDomain 0/1/0 (103) E...1...?.15o.4o.>.5...o..0............250.255.255.239.inaddr.arpa................-. sns.dns.icann.org..noc.>x..-... ..... :..... [...]
Capturar paquetes en hexadecimal y ASCII
Con el parámetro -XX podemos visualizar el contenido del paquete en hexadecimal y ASCII:
# tcpdump -i eth0 -XX tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes 13:45:02.921314 ARP, Request who-has 10.111.1.201 tell 10.111.1.1, length 46 0x0000: ffff ffff ffff 000a e483 f608 0806 0001 ................ 0x0010: 0800 0604 0001 000a e483 f608 0a6f 0101 .............o.. 0x0020: 0000 0000 0000 0a6f 01c9 0000 0000 0000 .......o........ 0x0030: 0000 0000 0000 0000 0000 0000 ............ 13:45:02.922326 IP www.test.com.45829 > 10.111.2.52.domain: 34340+ PTR? 201.1.111.10.in-addr.arpa. (43) 0x0000: 000a e483 f608 f04d a2b0 f4f1 0800 4500 .......M......E. 0x0010: 0047 1724 4000 4011 0b33 0a6f 013e 0a6f .G.$@.@..3.o.>.o 0x0020: 0234 b305 0035 0033 c59d 8624 0100 0001 .4...5.3...$.... 0x0030: 0000 0000 0000 0332 3031 0131 0331 3131 .......201.1.111 0x0040: 0231 3007 696e 2d61 6464 7204 6172 7061 .10.in-addr.arpa 0x0050: 0000 0c00 01 .....
Capturar todo el tráfico excepto ciertas condiciones
Además de los condicionales «and|or» que comentaba antes, también podemos utilizar «not» para descartar cierto tráfico. Por ejemplo, vamos a capturar todo el tráfico a excepción del tráfico por protocolo ICMP:
# tcpdump -i eth0 not icmp
También podemos usar varias condiciones. Por ejemplo, capturar todo el tráfico a excepción del ICMP y el TCP:
# tcpdump -i eth0 not icmp and not tcp
Información extendida (verbose)
Hay dos niveles de verbose, «-v» y «-vv»:
# tcpdump -i eth0 -v
# tcpdump -i eth0 -vv
Múltiples condiciones
En el tema de condiciones podemos complicarnos todo lo que queramos… os recomiendo revisar la pagina man de tcpdump para ver más ejemplos y posibilidades:
$ man tcpdump
Por ejemplo, capturar todo el tráfico con destino 192.168.1.100 y por los puertos/servicio http o https):
# tcpdump 'dst 192.168.1.100 and (port http or https)'
Alguno más enrevesado, como este, sacado de la ayuda de tcpdump:
Capturar los paquetes de inicio y fin (SYN y FIN) de cada sesión TCP y que no involucre como destino a ninguna red local:
# tcpdump 'tcp[tcpflags] & (tcp-syn|tcp-fin) != 0 and not src and dst net localnet'
Leer captura de tráfico almacenada en un archivo
Para leer el contenido de un archivo utilizamos el parámetro «-r». El contenido del archivo ha sido generado previamente con el parámetro «-w».
# tcpdump -r archivo.log
Formato de salida
Es complicado explicar el formato de salida de tcpdump ya que es diferente según el protocolo que estemos capturando. Por ejemplo, el formato normal de una línea que captura protocolo tcp es el siguiente:
src > dst: flags data-seqno ack window urgent options
El de ARP:
arp who-has csam tell rtsg arp reply csam is-at CSAM
Sería muy extenso explicarlo, lo mejor es ir adquiriendo experiencia jugando con la herramienta e interpretar la salida con lógica, siempre os quedará la ayuda en man ;)