lunes, 4 de marzo de 2013

tcpdump para tontos

Hace un tiempo trajimos un articulo introductorio sobre una de las herramientas mas socorridas a la hora de resolver problemas relacionados con la red, tcpdump. Ustedes ya conocen las razones y usos de los sniffers de paquetes así que no nos vamos a extender sobre eso. Aquel articulo era un introductorio, este que encontré hace un par de días va un poco mas allá y ofrece varios ejemplos de uso muy claros.
Las páginas del manual son el recurso superior casi siempre, de manera que vayan allá si quieren profundizar como Dios manda, pero por algo deben empezar, así que ahí les va. Este es el autor del original y si no necesitan la traducción tiene varios trabajos publicados en su blog que valen la pena (ha desarrollado para el kernel de Linux entre otras cosas). Pues eso, es lunes de redes :) .... provecho!.
 
Introducción 
En este artículo me gustaría hablar de una de las herramientas más útiles de mi caja de herramientas de red que es tcpdump. Por desgracia, dominar completamente esta herramienta no es una tarea fácil. Sin embargo, para las tareas que hacemos regularmente es relativamente sencilla y puede llegar a ser un buen trampolín para pasar a temas más complejos.
Uso de tcpdump
tcpdump es un sniffer de paquetes. Es capaz de capturar el tráfico que pasa a través de una máquina. Funciona a nivel de paquetes, lo que significa que captura los paquetes reales que entran o salen de su equipo. Puede guardar los paquetes en un archivo. Puede guardar paquetes completos o sólo los encabezados. Más tarde se puede "jugar" con el archivo grabado y aplicar diferentes filtros en los paquetes, diciéndole a tcpdump que ignore los paquetes en los que no estamos interesados.

Bajo el capó, tcpdump entiende los protocolos y los nombres de host. La herramienta hará todo lo posible para ver qué host envía cada paquete y le informará su nombre en lugar de la dirección IP.

Es una herramienta excepcionalmente útil para depurar lo que pueda causar un problema relacionado con la red. Además, es una excelente herramienta para aprender cosas nuevas.

Invocando tcpdump.
Invocar tcpdump es fácil. Lo primero que hay que recordar es que usted debe estar conectado como root o estar definido en el sudoer de la maquina en que la ejecuta - sudoer define las personas que tiene derecho a obtener derechos de administrador en el ordenador durante un período corto de tiempo con el comando sudo.

Ejecutar tcpdump sin argumentos hace que empiece a capturar paquetes en la primera interfaz de red (descontando el loopback) e imprima una breve descripción de cada paquete a la salida. Esto puede causar un poco de dolor de cabeza en caso de que usted esté conectado a la máquina de manera remota. Si está conectado vía SSH o telnet (rlogin?), ejecutar el tcpdump producirá una línea de texto para cada paquete entrante o saliente. Esta línea de texto hará que el demonio SSH envíe un paquete con esta línea, lo que a su vez provocará que tcpdump produzca otra línea de texto. Y esto no se detendrá hasta que ud haga algo al respecto.

Filtrado simple
Así que lo primero que vamos a aprender acerca de tcpdump es la forma de filtrar los paquetes SSH y telnet. Vamos a estudiar los fundamentos del filtrado en tcpdump mas adelante en esta guía, por ahora sólo recuerde esta sintaxis.

# tcpdump not port 22

"not port 22" es una especificación de filtro que le indica a tcpdump que filtre los paquetes con el puerto IP 22 de destino u origen. Como ustedes saben el puerto 22 es el puerto SSH. Básicamente, cuando le dices algo así a tcpdump, hará caso omiso de todos los paquetes SSH - exactamente lo que necesitamos.

Telnet por otra parte, utiliza el puerto 23. Así que si usted está conectando vía telnet, lo puede filtrar con:

# tcpdump not port 23

Claro y simple!

Lectura de la salida de tcpdump
Por defecto tcpdump produce una línea de texto por cada paquete que intercepta. Cada línea comienza con una marca de tiempo. Le indica precisamente el tiempo de llegada del paquete.

A continuación viene el nombre del protocolo. Desafortunadamente, tcpdump entiende un número muy limitado de protocolos. No te va a decir la diferencia entre los paquetes que pertenecen a HTTP y por ejemplo, los que pertenecen a un flujo FTP. En su lugar, simplemente marcará los paquetes como paquetes IP. Si tiene un conocimiento limitado de TCP. Por ejemplo, identifica los paquetes de sincronización TCP como SYN, ACK, FIN y otros. Esta información se imprime después de las direcciones IP de origen y destino (si es un paquete IP).

Las direcciones de origen y destino siguen al nombre del protocolo. Para los paquetes IP, estas son las direcciones IP. Para otros protocolos, tcpdump no imprime los identificadores a menos que se le pida explícitamente (vea la opción "-e" mas adelante).

Por último, tcpdump imprime alguna información sobre el paquete. Por ejemplo, imprime un número de secuencia TCP, banderas, comandos ARP / ICMP, etc

He aquí un ejemplo típico de la salida de tcpdump.

17:50:03.089893 IP 69.61.72.101.www > 212.150.66.73.48777: P 1366488174:1366488582 (408) ACK 2337505545 1491222906 win 7240

Este paquete es parte de un flujo de datos HTTP. Usted puede ver el significado de todos y cada uno de los campo en la descripción del paquete en la página del manual de tcpdump.

He aquí otro ejemplo

17:50:00.718266 arp who-has 69.61.72.185 tell 69.61.72.1

Estos son paquetes ARP. Estos son un poco mas claros de entender que los paquetes TCP. De nuevo, para ver el significado exacto de cada campo en la descripción del paquete vea la página del manual de tcpdump.

Invocación, continuación.
Ahora, que ya sabe cómo invocar tcpdump incluso cuando se conecta al ordenador través de alguna red, veamos que opciones de comando tenemos disponibles.

Elección de una interfaz
Vamos a empezar con una simple. Cómo capturar los paquetes que entran o salen de determinada interfaz de red. La opción -i hace exactamente eso.

# tcpdump -i eth1

El comando mostrado causará que tcpdump capture los paquetes en la interfaz de red eth1. O bien, considerando nuestra experiencia con SSH / Telnet:

# tcpdump -i eth1 not port 22

Por último, la opción del nombre de la interfaz puede ser definido como "any", para especificarle a tcpdump que escuche por todas las interfaces.

# tcpdump -i any not port 22

Desactivación de la resolución de nombres.
Al depurar problemas de red, podemos tener problemas con la forma en que tcpdump funciona por defecto. El problema es que tcpdump tratará de resolver cada dirección IP que encuentra. Es decir, cuando ve un paquete IP le pregunta al servidor DNS cual es el nombre del equipo a quien corresponde esa dirección IP. Esto funciona sin problemas la mayor parte del tiempo. Sin embargo, hay dos problemas.

En primer lugar, se ralentiza la interceptación de paquetes. Esto no es un problema cuando se trata de pocos paquetes, pero cuando hay miles y decenas de miles se introduce un retardo en el proceso. El retardo puede variar, dependiendo del tráfico.

Otro problema, mucho más grave se produce cuando no hay ningún servidor DNS disponible o cuando el servidor DNS no está funcionando correctamente. Si este es el caso, tcpdump pasa unos segundos tratando de averiguar dos nombres de host para cada paquete IP. Esto en la práctica detiene la intercepción del tráfico.

Afortunadamente hay una manera de evitar esto. Hay una opción que hace que tcpdump deje de intentar resolver los nombres, y es la opción "-n".

# tcpdump -n

Y aquí están algunas variaciones de cómo puede utilizar esta opción junto con las opciones que hemos aprendido ya.

# tcpdump -n -i eth1 
# tcpdump -ni eth1 not port 22

Limitar el número de paquetes a interceptar
Aquí hay algunas otras opciones útiles. A veces, la cantidad de tráfico que entra y sale de su ordenador es muy alta, y ud solo necesita ver unos cuantos paquetes. A menudo querrá ver quien genera el tráfico, pero cuando intente capturar cualquier cosa con tcpdump este capturará tantos paquetes que no podrá entender casi nada. Aquí es cuando resulta útil la opción "-c".

Esta opción le dice a tcpdump que limite el número de paquetes a interceptar. Deberá especificar el número de paquetes que desea ver. tcpdump capturará la cantidad especificada de paquetes y saldrá. Aquí un ejemplo.

# tcpdump -c 10

O con las opciones que vimos antes.

# tcpdump -ni eth1 -c 10 not port 22

Esto limitará la cantidad de paquetes que captura tcpdump a 10. Una vez recibidos 10 paquetes, tcpdump se cerrará.

Guardando los datos capturados
Una de las características más útiles de tcpdump es que permite capturar los paquetes entrantes y salientes en un archivo y luego utilizar este archivo mas adelante. Por cierto, podrá reproducir este archivo, no sólo con tcpdump, sino también con WireShark (antes Ethereal), el analizador de paquetes gráfico.

Usted puede hacer esto con la opción "-w". A continuación defina el nombre del archivo que guardará los paquetes. De esta manera:

# tcpdump -w file.cap

Incluyendo las opciones que ya hemos visto

# tcpdump -ni eth1 -w file.cap not port 22

Cambiando de tamaño de los paquetes en el archivo de captura
Por defecto, cuando se capturan paquetes hacia un archivo, tcpdump guardará sólo 68 bytes de los datos de cada paquete. El resto de la información será desechada.

Una de las cosas que hago a menudo cuando capturo el tráfico hacia un archivo, es cambiar el tamaño de los paquetes guardados. La cosa es que el espacio en disco necesario para guardar esta información es muy barato y además disponible la mayor parte del tiempo. Gastar unos pocos megabytes de su espacio en disco en una captura no es demasiado doloroso. Por otro lado, perder parte valiosa de los paquetes puede ser crítico.

Por lo tanto, lo que suelo hacer cuando capturo hacia un archivo es ejecutar tcpdump con la opción "-s". Esta opción le dice a tcpdump cuántos bytes guardar de cada paquete. Si especifica 0 como la longitud de la instantánea de un paquete le dirá a tcpdump que salve el paquete entero. He aquí cómo funciona:

# tcpdump -w file.cap -s0

Y en combinación con las opciones que ya hemos visto:

# tcpdump -ni eth1 -w file.cap -s 0 -c 1000 not port 22

Obviamente, usted puede guardar tantos datos como desee. El valor "1000" (bytes) especificará esto por usted. Debemos tener en cuenta que hay marcos (frames en el original ndt) llamados "jumbo frames" que puede ser tan grandes como 8Kb.

Leyendo archivos capturados.
Ahora, cuando hemos capturado algo de tráfico en un archivo, nos gustaría reproducirlo mas adelante. La opción "-r" le indicará a tcpdump que lea los datos de un archivo, en lugar de capturar paquetes desde las interfaces. Así es como funciona.

# tcpdump -r file.cap

Con un archivo de captura, podremos analizar fácilmente los paquetes y entender lo que hay dentro. tcpdump presenta varias opciones que nos ayudarán en esta tarea. Veamos algunos de ellos.

Buscando dentro de los paquetes.
Hay varias opciones que permiten a uno ver más información sobre el paquete. Hay un problema, sin embargo. tcpdump en general no le está dando demasiada información acerca de los paquetes. No comprende diferentes protocolos. Si desea ver el contenido del paquete, es mejor utilizar herramientas como Wireshark (nota). Wireshark si entiende los protocolos, los analiza y te permite ver diferentes campos, no sólo en la cabecera TCP, sino en las cabeceras de los protocolos de capa 7.

tcpdump es una herramienta de línea de comandos y como la mayoría de las herramientas de línea de comandos, su capacidad para presentar la información es algo limitada. Sin embargo, todavía tiene algunas opciones que controlan la forma en que son presentados los paquetes.

Viendo cabecera Ethernet para cada paquete.
La opción -e, hace que tcpdump nos presente las cabeceras Ethernet (protocolo de nivel de enlace) de cada paquete impreso. Veamos un ejemplo.

# tcpdump -n -e not port 22

Controlando las marcas de tiempo.
Hay cuatro opciones que controlan la manera en que tcpdump imprime las marcas de tiempo. En primer lugar, existe la opción "-t". Hace que tcpdump no imprima marcas de tiempo. Luego viene "-tt". Esta opción causa que tcpdump imprima la marca de tiempo como el número de segundos desde el 1 de enero 1970 y una fracción de un segundo. "-ttt" imprime el delta entre esta línea y la linea previa. Por último, "-tttt" causa que tcpdump imprima la fecha y hora en su formato normal precedido por fecha.

El control de nivel de detalle.
La opción "-v" hace que tcpdump imprima más información sobre cada paquete. Con "-vv" tcpdump imprime aún más información. Como habréis podido adivinar, "-vvv" produce aún más información. Por último "-vvvv" producirá un mensaje de error diciendo que no hay tal opción

Imprimiendo al contenido del paquete.
La opción "-x" hará que tcpdump imprima cada paquete en formato hexadecimal. El número de bytes que se van a imprimir sigue siendo aún un misterio. De esta manera, imprimirá los primeros 82 bytes del paquete, excluyendo la cabecera ethernet. Puede controlar el número de bytes impresos con la opción "-s".

En caso de que también quiera ver la cabecera ethernet, utilice la opción -xx. Esto hará que tcpdump imprima 14 bytes adicionales para la cabecera ethernet.

De manera análoga -X y -XX imprimirán el contenido del paquete en formato hexadecimal y ASCII. La última hará que tcpdump incluya el encabezado ethernet en copia impresa.

Filtrado de paquetes
Ya hemos visto un filtro simple. Causa que tcpdump ignore los paquetes SSH, lo que nos permite ejecutar tcpdump a través de un acceso remoto. Ahora vamos a tratar de entender el lenguaje que usa tcpdump para evaluar las expresiones de filtro.

Selección de paquetes.
Debemos entender que nuestro filtro de tcpdump se aplica a cada paquete entrante y saliente. Si coincide con el filtro, tcpdump reconoce el paquete y en función las opciones del comando o bien lo guarda en un archivo o lo mostrará en pantalla. De lo contrario, tcpdump ignorará el paquete y solo lo tendrá en cuenta para calcular el numero total de paquetes recibidos, descartados y filtrados que muestra al final de la operación.

Para demostrar esto, volvamos a la expresión "no port 22". tcpdump ignora los paquetes con origen o destino al puerto 22. Cuando tal paquete llega, tcpdump le aplica el filtro y puesto que el resultado es falso, descartará el paquete.

Más calificadores.
Por lo tanto, de lo que hemos visto hasta ahora, podemos concluir que tcpdump comprende la palabra "port" y la expresión "not" como un no. En realidad, la negación de expresiones es parte de una compleja sintaxis de expresiones y hablaremos de expresiones complejas un poco más adelante. Mientras tanto, veamos unos cuantos calificativos de paquetes que podemos utilizar en expresiones tcpdump.

Hemos visto que el calificador "port" especifica especifica un número de puerto, sea de origen o de destino. En caso de que desee especificar sólo el puerto de origen o de destino podemos utilizar las expresiones "src port" o "dst port". Por ejemplo, utilizando la expresión siguiente se pueden ver todos los paquetes HTTP salientes.

# tcpdump -n dst port 80

También podemos especificar rangos de puertos. los calificadores "portrange", "src portrange" y "dst portrange" hacen exactamente esto. Por ejemplo, veamos un comando que captura todos los paquetes telnet y SSH.

# tcpdump -n portrange 22-23

Especificación de direcciones.
Utilizando los calificadores "dst host", "src host" se pueden especificar direcciones IP de origen o destino. Por ejemplo:

# tcpdump src host alexandersandler.net

Imprimirá todos los paquetes procedentes de computadora alexandersandler.net.

También puede especificar direcciones Ethernet. Lo puede hacer con los calificadores de hosts "ether src", "ether dst" y "ether". Cada uno debe ir seguido por la dirección MAC de la fuente, destino o ambos del host en cuestión.

También se pueden especificar redes. Los calificadores "net", "src net" y "dst net" hacen exactamente esto. Su sintaxis sin embargo es ligeramente más compleja que la de un solo host. Esto es debido a que se debe especificar la máscara de red.

Se pueden utilizar dos formas básicas de especificación de la red. Usar la máscara directamente o usar la notación CIDR. Éstos son algunos ejemplos.

# tcpdump src net 67.207.148.0 mask 255.255.255.0

O lo mismo usando notación CIDR.

# tcpdump src net 67.207.148.0/24

Nótese la palabra máscara que hace el trabajo de especificar la red en el primer ejemplo. El segundo ejemplo es mucho más corto.

Otros calificadores
Hay varios calificadores útiles que no entran en ninguna de las categorías que hemos cubierto hasta ahora.

Por ejemplo, puede especificar que usted está interesado en los paquetes con una longitud específica. El calificador "length" hace esto. Los calificadores "less" y "greater" le indican a tcpdump que usted está interesado en paquetes cuya longitud es menor o mayor que el valor especificado.

He aquí un ejemplo que muestra su uso.

# tcpdump -ni eth1 greater 1000

Capturará sólo los paquetes cuyo tamaño es mayor que 1000 bytes.

Expresiones de filtrado complejas.
Como ya hemos visto podemos construir expresiones de filtrado más complejas usando el idioma de filtros de tcpdump. En realidad, tcpdump permite expresiones de filtrado extraordinariamente complejas.

Hemos visto la expresión "not port 22". Aplicando esta expresión en determinados paquetes producirá un "true" válido para los paquetes que no tienen su origen o destino en el puerto 22. O en dos palabras, "no" niega la expresión.

Además de la negación de expresiones, podemos construir expresiones más complejas combinando dos expresión más pequeñas en una mayor utilizando las palabras clave "and" y "or". Además, podemos utilizar paréntesis para agrupar varias expresiones.

Por ejemplo, veamos un filtro que causa que tcpdump capture los paquetes más grandes que 100 bytes provenientes de google.com o desde microsoft.com.

# tcpdump -XX greater 100 and \(src host google.com or src host microsoft.com\)

Los operadores "and" y "or" tienen igual precedencia en el idioma de filtros de tcpdump y se evalúan de izquierda a derecha. Esto significa que sin corchetes, tcpdump capturaría los paquetes de cualquier tamaño provenientes de microsoft.com. Con corchetes, tcpdump primero se asegura de que todos los paquetes son mayores de 100 bytes y sólo entonces verifica su origen.

Observe el símbolo de diagonal invertida ("\") antes de los paréntesis. En este caso necesitamos usarlos para "escapar" de los paréntesis debido al intérprete de comandos (la shell). La shell en Unix tiene una comprensión especial del uso de los paréntesis. Por lo tanto tenemos que decirle que no los interprete y se los pase a tcpdump como vienen. Las dos diagonales invertidas hacen exactamente esto.

Hablando de prioridades, tenemos que tener en cuenta que en el lenguaje de filtros de las expresiones de tcpdump NOT tiene mayor precedencia que AND y que OR. La página del manual de tcpdump tiene un muy buen ejemplo y hace hincapié en el significado de esto.

not host vs and host ace

y

not (host vs or host ace)

Son dos expresiones diferentes. Debido a que NOT tiene mayor prioridad que AND y OR, el filtro del primer ejemplo captura los paquetes no desde /o hacia vs, sino hacia/o desde ace. El segundo filtro de ejemplo por otra parte capturará los paquetes que no entran / o salen de vs y los que no entran / o salen de ace. Es decir, el primero captura los paquetes desde ace hacia cualquier otra máquina (pero no para vs). Sin embargo, el segundo ejemplo no capturará este paquete.

Repetición de los calificadores
Para concluir este artículo, me gustaría decirte una cosa más que puede llegar a ser muy útil al escribir expresiones de filtros complejas para tcpdump.

Eche un vistazo a el siguiente ejemplo.

# tcpdump -XX greater 100 and \(src host google.com or microsoft.com \)

Ya vimos este ejemplo, con una pequeña excepción. En el otro ejemplo incluimos un calificador "src host" antes de microsoft.com y ahora lo omitimos. La cosa es que si queremos utilizar el mismo calificador dos veces seguidas, no es necesario especificarlo dos veces. En su lugar, sólo escribimos los parámetro del calificador y tcpdump sabrá qué hacer. Esto hace el lenguaje de expresiones de filtros de tcpdump mucho más fácil de entender y mucho más legible.

Epílogo
Espero que hayas encontrado este artículo útil. En caso de tener alguna duda, sugerencia o si desea compartir su agradecimiento al autor no dude en escribirme a alexander.sandler@gmail.com

Nota del traductor : Wireshark está disponible en el centro de software de Ubuntu y en Freebsd debajo de /usr/ports/net/wireshark, para Windows solo vayan al sitio oficial y descárgen en instalador. Regresar