Tcpdump (y su port a Windows, Windump) son programas cuya utilidad principal
es analizar el tráfico que circula por la red. Se apoya en la
librería de captura pcap, la cual presenta una interfaz uniforme y que esconde las peculiaridades
de cada sistema operativo a la hora de
capturar tramas de red. Para seguir el manual es necesario unos conocimientos
basicos del protocolo TCP/IP, remitiéndome al TCP/IP Illustrated,
Volumen 1 de Stevens, para quien esté interesado.
Aunque viene incluido con la mayoría de las distribuciones de Linux, sus fuentes
pueden encontrarse en www.tcpdump.org
El port completo para Windows, tanto de las librerias como del tcpdump puede
encontrarse en la web
de la Politécnica de Torino. Es un simple binario, que necesita tener
instalado el port
de las pcap para windows para funcionar.
Lo primero que debemos averiguar cuando estamos usando el tcpdump, es las
interfaces que queremos escuchar. Por defecto cuando se ejecuta sin parámetros, en los Linux se pone a escuchar en la eth0, mientras que en Windows hay que
especificarla la interfaz donde quiere escuchar.
Para averiguar la interfaces en cualquier Unix recurrimos al comando ifconfig -a el cual nos da una lista de las interfaces que tenemos, así como sus
parametros de configuración.
[terron@ux02 ~]$ /sbin/ifconfig -a
eth0 Link encap:Ethernet HWaddr addr
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:646760 errors:0 dropped:0 overruns:0 frame:0
TX packets:449673 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:100
Interrupt:5 Base address:0x2c20
eth1 Link encap:Ethernet HWaddr addr
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:1321583 errors:0 dropped:0 overruns:0 frame:0
TX packets:1778135 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:100
Interrupt:9 Base address:0x3000
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:3924 Metric:1
RX packets:39747 errors:0 dropped:0 overruns:0 frame:0
TX packets:39747 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
[terron@ux02 ~]$
(en el ejemplo anterior estan borradas las direcciones ip)
En el caso de Windows, podemos recurrir al propio windump, para que nos liste
las interfaces que tenemos. Para ello ejecutamos un Windump -D y nos
dara la información que buscamos:
C:\Documents and Settings\terron\download>windump -D
1.\Device\Packet_NdisWanIp (NdisWan Adapter)
2.\Device\Packet_{8435447C-6020-481F-A720-44D940909166} (Intel 8255x-based Integ
rated Fast Ethernet)
Usando los datos del ejemplo anterior, en el Linux si queremos escuchar
en la interfaz eth0, usaremos tcpdump -i eth0, mientras que en
el caso de Windows si queremos escuchar en la ethernet usaremos
windump -i \Device\Packet_{8435447C-6020-481F-A720-44D940909166}.
Cuando estamos leyendo la red, puede que no nos interese que el tcpdump intente
resolver los nombres de las maquinas (pueden que no estin dadas de alta en el
DNS, por motivos de seguridad, etc), para ello disponemos de la
opción -n.
Para establecer la longitud de los datos que captura tcpdump usamos -s
len, donde len es la longitud que nos interesa.
Por defecto el tcpdump sólo
captura los
primeros 68 bytes, lo cual es útil si lo único que se quiere
son las cabaceras
IP, TCP o UDP, pero que en caso de estar esnifando protocolos como el NFS
truncan los datos. En ese caso podemos ajustar la longitud de la captura a la
MTU del medio que estamos usando con esta opción. Por ejemplo para capturar
toda la trama ethernet podemos usar -s 1500.
En función de la cantidad de información que queramos a la hora de que el
tcpdump nos interprete, podemos usar -v,-vv,-vvv, aumentando el grado
de información con cada una de las opciones.
Si queremos imprimir el contenido del paquete, podemos usar la opción -x.
Si ademas queremos que nos imprima en ASCII el contenido de los paquetes podemos
usar -X. La longitud que imprime viene determinada por la opción -s o los 68 bytes que usa captura por defecto.
Podemos trabajar offline con el tcpdump. Si queremos grabar nuestra captura
para posteriormente leerla y analizarla usamos la opción -w file
donde file es el nombre del fichero donde queremos grabar la captura de
datos. Posteriormente podemos leer y analizar offline con -r file.
Además este tipo de ficheros de captura lo pueden leer otros
analizadores como por ejemplo Ethereal.
Lo primero que hay que decir es que la salida depende del protocolo que
estemos analizando. Para empezar comentar que todas las capturas del tcpdump
tienen como primer campo una marca de tiempo, que indica cuando ha sido
capturado el paquete.
Peticiones ARP/RARP
El protocolo ARP (address reslotion protocol), sobre ethernet está documentado en la
RFC 826. RARP puede encontrarse
en la RFC 1293.
Las peticiones arp aparecen de la siguiente manera:
En este caso, la máquina 192.168.1.1 pregunta por la dirección ethernet
192.168.1.2 (suponemos ambas máquinas en la misma subred). Como vemos
la 192.168.1.2 responde. En este caso, vemos los valores numéricos puesto
que he usado la opcin -n. En caso, las mayúsculas indican la máquina
por la cual se está preguntando, y la minúscula la máquina que hace la pregunta.
El protocolo TCP se define en la RFC 793
En principio src, dst y flags estan siempre presentes.
Los otros dependiendo del tipo de conexión TCP que se trate. El
significado de dichos parámetros es:
src: Dirección y puerto origen. En caso de no
especificar el parámetro -n se intenta resover el nombre
via DNS y el se busca el nombre del puerto vía (normalmente en
los Unix en /etc/services).
dst: Dirección y puerto destino, exactamente igual
que el caso anterior.
flags: Indica los flags de la cabecera TCP. Puede ser un
., cuyo significado es que no hay flags, o bien una
combinación de S (SYN), F (FIN), P (PUSH),
W (reducción de la ventana de congestión),
E (ECN eco).
dataseq: El námero de secuencia del primer
byte de datos en este segmento TCP. El formato es primero:ultimo(n),
que significa que desde a primero a ultimo
(sin incluir ultimo) hay
un total de n bytes de datos. Ojo cuando hay segmentos con
SYN, que también ocupa un numero del espacio
de secuencia.
ack: El número de asentimiento. Indica el número
siguiente de secuencia que se espera recibir. Ojo los SYN
también se asienten.
win: Tamaño de la ventana de recepción.
urgent: Existen datos urgentes.
options: Indica la existencia de opciones. En caso de que haya
van entre < y >.
En el siguiente ejemplo, (viene en la página de manual del tcpdump),
podemos ver:
rtsg.1023 > csam.login: S 768512:768512(0) win 4096
<mss 1024>
Esto simula una conexión originada por la máquina rtsg con
destino a csam, con el servicio rlogin.
El significado de las líneas anteriores es:
Inicio de conexion de rtsg -> csam SYN ISN 768512 ventana de 4096
SYN de csam -> rtsg ISN 947648 ventana de 4096 ACK del SYN anterior.
ACK del SYN mandado por csam. No hay flags
1 byte de datos de rtsg -> csam. Flag PUSH
activado.,
(los números de secuencia son relativos al ISN a menos que
especifiquemos la opción -S, en cuyo caso pone
los números de secuencia se imprimen de manera absoluta).
ACK del byte de datos anterior por parte de csam.
19 bytes de datos de rtsg a csam.
csam manda 1 byte de datos a rtsg, y manda el ACK de los
19 bytes enviados por rtsg. La ventana de recepcisn ha bajado en
19 bytes. Flag PUSH
En algunos casos, puede interpretar protocolos que vayan encapsulado en los
paquetes UDP, como NFS o DNS. El grado de detalle en la interpretación
de estos protocolos dependerá del grado de detalle (controlado con la
opción -v) que queramos darle.
Fragmentos de datagramas IP
Los datagramas fragmentados se indican con una expresión al lado
de los mismos entre paréntesis:
(frag id:size@offset+)
(frag id:size@offset)
id es el identificador de fragmento.
size tamaño del fragmento.
offset posició del fragmento en el datagrama original. Si existe
el + al final de offset significa que aún quedan
más fragmentos. En caso de ausencia, que es el último.
Los datos del protocolo del nivel superior, sólo se imprimen en el
primer fragmento.
Es lo mas importante que nos permite hacer el tcpdump, el uso de filtros.
Un filtro es una expresión que va detrás de las opciones
y que nos permite seleccionar los paquetes que estamos buscando. En ausencia
de ésta, el tcpdump volcará todo el tráfico que vea el
adaptador de red seleccionado.
La expresión que se usa para definir el filtro tiene una serie de
primitivas y tres posibles modificadores a las mismas. Esta expresión
sera verdadera o falsa y hara que se imprima o no el paquete de datos.
Los 3 modificadores posibles son:
tipo. Puede ser host, net o port.
indican respectivamente una maquina, por ejemplo host 192.168.1.1
, una red completa, por ejemplo net 192.168, o un puerto
concreto, por ejemplo port 22. Por defecto se asume el tipo
host.
dir. Especifica desde o hacia donde se va a mirar el flujo
de datos. Tenemos src o dst y podemos combinarlos con
or y and. Para el caso de de protocolos punto a punto
podemos sustituir por inbound o outbound.Por ejemplo
si queremos la dirección de destino 10.10.10.2 y la de origen
192.168.1.2, el filtro serma dst 10.10.10.2 and src 192.168.1.2
. Si se quiere que sea la dirección destino 192.168.1.1 o la
dirección origen 192.168.1.2, serma dst 192.168.1.1 or
src 192.168.1.2. Pueden seguirse combinando
con la ayuda de paréntesis o las palabras or y and. Si
no existe se supone src or dst. Por supuesto, esto se puede
combinar con los modificadores de tipo anteriores.
proto. En este caso es el protocolo que queremos capturar.
puede ser tcp,udp,ip,ether (en este caso
captura tramas a nivel de enlace,arp (peticiones arp),
rarp (petciones reverse-arp),fddi(para redes FDDI, pero
realmente el encapsulado es igual al ether). Hay otros niveles de enlace
para redes Decnet y lat, pero dado su escaso uso, me remito a la pagina
de manual del programa.
Siempre podemos combinar expresiones con ayuda de paréntesis.
Ojo con el tema de los paréntesis en los shell de Unix, porque son
metacaracteres interpretan.
A continuació se dan las primitivas que pueden usarse. Lo que aperece
entre [ y ] es opcional, y el | significa "o". El resto
se tiene que poner si queremos poner el filtro con el comportamiento.
[dst|src] host maquina. Cierto si la dirección destino
u origen del paquete es maquina lo cual puede ser una
dirección IPv4 (o IPv6 si se ha compilado soporte para el mismo),
o un nombre del DNS. Si queremos restringir a dirección destino
podemos restringir con dst. Para dirección origen
src.
Ejemplos:
Capturar el trafico cuya IP origen sea 192.168.1.1
Capturar todo el tráfico cuya dirección origen o
destino sea 192.168.1.2
tcpdump host 192.168.1.2 windump host 192.168.1.2
ether src|dst|host edir. Este filtro es cierto sm la
dirección origen (src), la destino (dst) o
el cualquiera de las dos(host) coincide con edir. Hacer
notar que src,dst o host es obligatorio
especificarlo.
Ejemplos:
Capturar el tráfico con destino a la dirección
ethernet 0:2:a5:ee:ec:10.
gateway maquina. Cierto en caso de que el paquete use maquina como router.
maquina debe estar definida en /etc/ethers y /etc/hosts.
Realmente los paquetes que cumplen con esa condición son aquellos que tienen como dirección ethernet destino maquina, pero ni la dirección IP destino u origen es maquina.
[dst|src] net red. Cierto en caso de que la red de la
dirección destino, origen o ambas sea red. El parametro red
puede ser una dirección numérica (por ejemplo 192.168.1.0)
o bien un nombre que se resuelve a dirección, en los Unix, con ayuda
del /etc/networks. Decir que también se admite el clásico
direccionamiento CIDR. Podemos especificar una mascara poniendo
red como net red mad mascara o bien usar /,
net red/bits. Hacer notar que el uso de net ... mask
no es compatible con direcciones IPv6. Si queremos hacer referencia
a la red destino usamos dst como prefijo. Para la red origen
usamos dst.
Ejemplos:
Capturar todo el tráfico cuya red destino sea 192.168.1.0.
tcpdump dst net 192.168.1.0 windump dst net 192.168.1.0
Capturar todo el tráfico cuya red origen sea
192.168.1.0/28
tcpdump src net 192.168.1.0 mask 255.255.255.240 tcpdump src net 192.168.1.0/28
Capturar todo el tráfico con origen o destino en la
10.0.0.0/24
tcpdump net 10.0.0.0/24 tcpdump net 10.0.0.0 mask 255.255.255.0
[dst|src] port puerto. Cierto en caso de que el puerto (ya sea udp o tcp) coincida con
puerto. Si no se especifica dst o src, será cierto tanto
puerto origen como destino. Si queremos restringir a destino usamos dst y a origen
usamos src.
El puerto es un valor numérico entre 0-65535 o bien un nombre que en Unix se resuelve a
través del /etc/services.
Ejemplos:
Capturar todo el tráfico con destino al puerto 23
tcpdump dst port 23
Capturar todo el tráfico con destino o origen puerto 80
tcpdump port 23
less longitud. Cierto en caso de que el tamaño del paquete sea
menor o igual longitud.
greater longitud. Cierto en caso de que el tamaño del paquete sea mayor o
igual que logitud.
ip proto protocolo. En este caso escucha el protocolo que se le indique.
El protocolo puede ser icmp, icmp6, igmp (internet group managent protocol),
igrp (interior gateway routing protocol), pim (protocol independent multicast),
ah (IP Authentication header), esp (encapsulating security payload),
udp o tcp. En caso de usar icmp, udp o tcp hay que
escapar el protocolo, poniendo un \, es decir, ip proto \icmp.
Ojo con ese caracter que también hay que escaparlo en los shells de Unix.
Por comodidad se disponen los alias tcp, udp e icmp que equivalen a
ip proto tcp or ip6 proto tcp, etc.
Ejemplos:
Capturar el todo los paquetes icmp
tcpdump ip proto \\ip
(en Unix hay que escapar el \).
Capturar todo el tráfico udp
tcpdump ip proto \\udp tcpdump udp
(el alias es más cómodo)
ip6 proto protocolo. Cierto si es un paquete de IPv6 con el protocolo
protocolo.
ip6 protochain protocolo. Es un número que en los Unix puede leerse
en /etc/protocols. En este caso lo que se busca es que dentro de los
diferentes cabeceras que puede tener un paquete IPv6 una de ellas sea
el protocolo especificado.
ip protochain protocolo. Igual que el caso anterior pero para IPv4.
ether broadcast. Cierto si la trama capturada va dirigida hacia
la dirección de difusión ethernet. La palabra ether
es opcional.
ip broadcast. Cierto si el paquete va dirigido a la dirección de
difusión de IP. Esta dirección se comprueba si es todo 0 o 1,
o bien se comprueba la dirección local de la subred.
ether multicast. Cierto si la trama va dirigida a una dirección multicast
ethernet.
ip multicast. Cierto si el paquete va dirigido a una dirección
multicast IP.
ip6 multicast. Cierto si el paquete va dirigido a una dirección
multicast IPv6.
ether proto protocolo. Cierto si el protocolo que contiene la
trama es de tipo protocolo Los protocolos son ip, ip6,
arp, rarp, atalk, aarp, decnet, sca,
lat, mopdlmoprc e iso. Además estos nombres
son identificadores que deben de ser escapados con \.
Sin embargo hay una serie de alias que hacen mas cómodo la
expresión en los filtros. Dichas expresiones son ip,ip6
,arp,rarp,aarp, decnet e iso, siendo
equivalentes a ether proto ip, ether proto ip6,
etc.
Ejemplos:
Capturar todo tráfico arp
tcpdump -n ether proto \\arp tcpdump -n arp
(el alias es más cómodo)
Capturar todo tráfico ip
tcpdump -n ether proto \\ip tcpdump -n ipi
vlan [vlanid]. Cierto si la trama capturada es un paquete 802.1Q VLAN.
Hacer notar de que esto cambia el resto de la interpretación del
paquete capturado, en especial los desplazamientos a partir de los cuales
empiezan a decodificar los protocolos, ya que se asume que estamos capturando
paquetes que viajan en tramas VLAN. Por último si esta presente el
parametro vlanid, sólo se mostraran aquellos paquetes que vayan
a la VLAN vlanid.
Combinando los filtros
Se pueden combinar las expresiones anteriores con los ayuda de los operadores
not, and y or (corresponden a la negación,
el y lógico y el o lógico, dando lugar a filtros
más complejos. Podemos usar también los equivalentes del lenguaje C:
!, && o ||.
Ejemplos:
Capturar todo el tráfico Web (TCP port 80)
tcpdump tcp and port 80
Capturar el todas las peticiones DNS
tcpdump udp and dst port 53
Capturar el tráfico al puerto telnet o ssh
tcpdump tcp and \(port 22 or port 23\)
(los "\" son para escapar en el shell de Unix)
Capturar todo el tráfico excepto el web
tcpdump tcp and not port 80
Filtros Avanzados
Para los realmente muy cafeteros, el tcpdump permite hacer filtros a mano, indicando que bytes de la trama queremos pillar y como los queremos interpretar.
Cuando queremos definir filtros de esta manera la expresión general es:
expr relop expr
Donde relop puede ser cualquiera de las operaciones de relación de
C: >,<, >=<=, = y !=.
expr es una expresión aritmética compuesta por una
serie de números
enteros, los operadores binarios de C, (+, -, *, /,
& y |), un operador de longitud, len, y una serie
de palabras reservadas que nos permiten el acceso a los diferentes paquetes
de datos (ether, fddi, tr, ip, arp,
rarp, tcp, udp, icmp e ip6).
Para acceder a los datos dentro de un paquete, usamos los modificadores
anteriores y una expresión entera. Opcionalmente podemos especificar el
tamaño de los datos que accedemos.
proto [expr : tam]
Asm por ejemplo, el primer byte de la trama ethernet será ether[0], la primera
palabra será ether[0:2]. El parámetro tam puede ser 1
(por defecto y no hace falta especificarlo), 2 o 4. Por ejemplo,
Una nota, al menos en la página de manual de la versión 3.6.2
hacen notar que
cuando se especifica tcp, udp u otro procolo de nivel superior
se hace referencia a IPv4. Esta limitación sin embargo no aparece en OpenBSD.
Otra nota a tener en cuenta: en caso de usar tcp[indice] o
udp[indice], implicitamente se aplica una regla para averiguar
si es un paquete fragmentado, es decir, usando la notacisn de estos filtros
ip[0:2] & 0x1fff = 0. udp[0] o tcp[0] se refieren al primer byte de la cabecera UDP o TCP.
La mayoría de la doc aquí contenida se ha obtenido de la pagina de manual del
tcpdump de una Redhat Linux y del OpenBSD. De hecho, la sección de filtrosl
procede en su totalidad de la página de manual del mismo, aunque he
cambiado algunos detalles a la hora de expresarlos.