Bienvenidos a un nuevo post en ByteMind. En el caso de hoy estaremos analizando tráfico con tcpdump, una herramienta de línea de comandos con la finalidad de analizar el tráfico que circula por nuestra red.
Tcpdump permite al usuario la posibilidad de capturar y mostrar en tiempo real los paquetes enviados y recibidos por la red a la cual esté conectado, permitiendo además poder filtrar el tipo de tráfico a analizar.
Tcpdump funciona en la gran mayoría de distribuciones unix mediante el uso de la librería libpcap, e incluso existe una adaptación de la misma para windows bajo el nombre de Windump, la cual se apoya mediante la librería winpcap
Índice
Cómo funciona
Tcpdump, al igual que en la gran mayoría de herramientas, existe a disposición del usuario una ayuda simple del mismo y el manual con la información al respecto, dejo también un enlace a la página oficial en el siguiente link.
El comando tendrá la siguiente sintaxis:
1 |
$ tcpdump [options] |
Y se puede ver la ayuda del mismo con el siguiente comando:
1 2 3 4 5 6 7 8 9 |
$ tcpdump --help Usage: tcpdump [-aAbdDefhHIJKlLnNOpqStuUvxX#] [ -B size ] [ -c count ] [ -C file_size ] [ -E algo:secret ] [ -F file ] [ -G seconds ] [ -i interface ] [ -j tstamptype ] [ -M secret ] [ --number ] [ -Q in|out|inout ] [ -r file ] [ -s snaplen ] [ --time-stamp-precision precision ] [ --immediate-mode ] [ -T type ] [ --version ] [ -V file ] [ -w file ] [ -W filecount ] [ -y datalinktype ] [ -z postrotate-command ] [ -Z user ] [ expression ] |
O el manual completo del mismo con:
1 |
$ man tcpdump |
También permite el uso de operadores para concatenar diferentes filtros:
- AND -> and o &&
- OR -> or o ||
- EXCEPT -> not o !
Explicada la sintaxis y opciones disponibles, vamos a verlo en funcionamiento con una serie de ejemplos muy útiles a la hora de analizar el tráfico de red.
Capturar paquetes desde una interfaz concreta
Si ejecutamos tcpdump sin especificar ninguna opción, por defecto, capturará todo el tráfico que pase por cualquier interfaz de red a través de la cual estemos conectados, podemos limitar esta captura a una interfaz en concreto con la opción -i:
1 |
$ tcpdump -i eth0 |
En caso de querer capturar tráfico de cualquiera de ellas podemos especificarlo con la opción any:
1 |
$ tcpdump -i any |
Capturar n número de paquetes
Es posible especificar cuantos paquetes se quieren obtener a la hora de realizar una captura de paquetes, para ello se utiliza la opción -c
1 2 3 4 5 6 7 8 9 10 11 |
$ tcpdump -i lo -c 5 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes 12:47:08.751521 IP localhost.33380 > localhost.zabbix-agent: Flags [S], seq 359103935, win 43690, options [mss 65495,sackOK,TS val 1718706 ecr 0,nop,wscale 7], length 0 12:47:08.751547 IP localhost.zabbix-agent > localhost.33380: Flags [S.], seq 808607597, ack 359103936, win 43690, options [mss 65495,sackOK,TS val 1718706 ecr 1718706,nop,wscale 7], length 0 12:47:08.751566 IP localhost.33380 > localhost.zabbix-agent: Flags [.], ack 1, win 342, options [nop,nop,TS val 1718706 ecr 1718706], length 0 12:47:08.751707 IP localhost.33380 > localhost.zabbix-agent: Flags [P.], seq 1:32, ack 1, win 342, options [nop,nop,TS val 1718706 ecr 1718706], length 31 12:47:08.751721 IP localhost.zabbix-agent > localhost.33380: Flags [.], ack 32, win 342, options [nop,nop,TS val 1718706 ecr 1718706], length 0 5 packets captured 20 packets received by filter 0 packets dropped by kernel |
El anterior comando capturar sólo los 5 primeros paquetes que pasen a través de la interfaz eth0.
Mostrar los paquetes capturados en ASCII
Con la opción -A es posible especificar a tcpdump que lo que nos interesa es ver los paquetes capturados en formato ascii, quedando el comando de la siguiente manera:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
$ tcpdump -i lo -A tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes 12:48:42.099220 IP localhost.8089 > localhost.56966: Flags [P.], seq 454385591:454385628, ack 1120298145, win 368, options [nop,nop,TS val 1812053 ecr 1811053], length 37 E..Yv.@.@................._.B.d....p.M..... ...U...m.... ....=......`..1....[.7.....:.p.X 12:48:42.099243 IP localhost.56966 > localhost.8089: Flags [.], ack 37, win 1432, options [nop,nop,TS val 1812053 ecr 1812053], length 0 E..4+,@.@...............B.d..._......(..... ...U...U 12:48:42.103865 IP6 localhost.38938 > localhost.postgres: Flags [P.], seq 2612544936:2612545365, ack 810596084, win 3826, options [nop,nop,TS val 1812058 ecr 1807054], length 429 `......@...................................8..E.0P............. ...Z....Q....select h.hostid,h.host,h.name,t.httptestid,t.name,t.agent,t.authentication,t.http_user,t.http_password,t.http_proxy,t.retries,t.ssl_cert_file,t.ssl_key_file,t.ssl_key_password,t.verify_peer,t.verify_host,t.delay from httptest t,hosts h where t.hostid=h.hostid and t.nextcheck<=1566902922 and mod(t.httptestid,1)=0 and t.status=0 and h.proxy_hostid is null and h.status=0 and (h.maintenance_status=0 or h.maintenance_type=0). 3 packets captured 6 packets received by filter 0 packets dropped by kernel |
Mostrar los paquetes capturados en HEX y ASCII
En algunas ocasiones es posible que el usuario prefiera ver los paquetes en formato hexadecimal y ascii, para ello tcpdump tiene una opción específica que mostraría ambos formatos. Esta opción sería la -X, como en el siguiente comando de ejemplo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
$ tcpdump -i lo -X tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes 12:49:14.973833 IP6 localhost.37883 > localhost.37883: UDP, length 88 0x0000: 0000 0000 0000 0000 0000 0000 86dd 6000 ..............`. 0x0010: 0000 0060 1140 0000 0000 0000 0000 0000 ...`.@.......... 0x0020: 0000 0000 0001 0000 0000 0000 0000 0000 ................ 0x0030: 0000 0000 0001 93fb 93fb 0060 0073 0b00 ...........`.s.. 0x0040: 0000 5800 0000 0000 0000 0000 0000 0000 ..X............. 0x0050: 0000 0000 0000 0100 0000 0000 0000 0000 ................ 0x0060: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 0x0070: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 0x0080: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 0x0090: 0000 0000 0000 ...... 12:49:15.017972 IP6 localhost.38936 > localhost.postgres: Flags [P.], seq 1837056155:1837056376, ack 635064344, win 6146, options [nop,nop,TS val 1844972 ecr 1843966], length 221 0x0000: 0000 0000 0000 0000 0000 0000 86dd 6000 ..............`. 0x0010: 0000 00fd 0640 0000 0000 0000 0000 0000 .....@.......... 0x0020: 0000 0000 0001 0000 0000 0000 0000 0000 ................ 0x0030: 0000 0000 0001 9818 1538 6d7f 409b 25da .........8m.@.%. 0x0040: 5018 8018 1802 0105 0000 0101 080a 001c P............... 0x0050: 26ec 001c 22fe 5100 0000 dc73 656c 6563 &...".Q....selec 0x0060: 7420 612e 616c 6572 7469 642c 612e 6d65 t.a.alertid,a.me 0x0070: 6469 6174 7970 6569 642c 612e 7365 6e64 diatypeid,a.send 0x0080: 746f 2c61 2e73 7562 6a65 6374 2c61 2e6d to,a.subject,a.m 0x0090: 6573 7361 6765 2c61 2e73 7461 7475 732c essage,a.status, 0x00a0: 612e 7265 7472 6965 732c 652e 736f 7572 a.retries,e.sour 0x00b0: 6365 2c65 2e6f 626a 6563 742c 652e 6f62 ce,e.object,e.ob 0x00c0: 6a65 6374 6964 2066 726f 6d20 616c 6572 jectid.from.aler 0x00d0: 7473 2061 206c 6566 7420 6a6f 696e 2065 ts.a.left.join.e 0x00e0: 7665 6e74 7320 6520 6f6e 2061 2e65 7665 vents.e.on.a.eve 0x00f0: 6e74 6964 3d65 2e65 7665 6e74 6964 2077 ntid=e.eventid.w 0x0100: 6865 7265 2061 6c65 7274 7479 7065 3d30 here.alerttype=0 0x0110: 2061 6e64 2061 2e73 7461 7475 733d 3320 .and.a.status=3. 0x0120: 6f72 6465 7220 6279 2061 2e61 6c65 7274 order.by.a.alert 0x0130: 6964 00 id. 12:49:15.018410 IP6 localhost.37883 > localhost.37883: UDP, length 248 0x0000: 0000 0000 0000 0000 0000 0000 86dd 6000 ..............`. 0x0010: 0000 0100 1140 0000 0000 0000 0000 0000 .....@.......... 0x0020: 0000 0000 0001 0000 0000 0000 0000 0000 ................ 0x0030: 0000 0000 0001 93fb 93fb 0100 0113 0200 ................ 0x0040: 0000 f800 0000 d44b 0000 0200 0000 0100 .......K........ 0x0050: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 0x0060: 0000 0000 0000 6950 0000 0000 0000 0100 ......iP........ 0x0070: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 0x0080: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 0x0090: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 0x00a0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 0x00b0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 0x00c0: 0000 0000 0000 0000 0000 0000 0000 0f50 ...............P 0x00d0: 0000 0803 0000 0100 0000 0000 0000 0000 ................ 0x00e0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 0x00f0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 0x0100: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 0x0110: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 0x0120: 0000 0000 0000 0100 0000 0000 0000 0100 ................ 0x0130: 0000 0000 0000 ...... 3 packets captured 10 packets received by filter 0 packets dropped by kernel |
Guardar el resultado de una captura en un fichero
Tcpdump da también la posibilidad de guardar los paquetes capturados en un fichero para analizarlo más detenidamente más tarde. Para ello se utilizaría la opción -w como en el siguiente ejemplo:
1 2 3 4 5 |
$ tcpdump -i lo -w firstcapture.pcap tcpdump: listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes ^C247 packets captured 494 packets received by filter 0 packets dropped by kernel |
Como formato de salida se utiliza la extensión .pcap porque es entendida por la gran mayoría de herramientas de análisis de paquetes.
Lectura de paquetes desde un fichero .pcap
De la misma forma que es posible guardar los paquetes capturados, es posible leerlos del fichero .pcap generado. Para ello usaremos la opción -r como en el siguiente ejemplo:
1 |
$ tcpdump -r firstcapture.pcap |
Mostrar la ip de los paquetes capturados
Tcpdump por defecto muestra los paquetes con la dirección DNS del mismo, pero no muestra información de su IP. Para evitar esto y ver información acerca de la IP se encuentra disponible la opción -n como en el siguiente ejemplo:
1 2 3 4 5 6 7 8 9 |
$ tcpdump -i lo -n tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes 12:51:50.355457 IP6 ::1.38958 > ::1.postgres: Flags [P.], seq 936783230:936783242, ack 1250811896, win 459, options [nop,nop,TS val 2000310 ecr 1998280], length 12 12:51:50.355561 IP6 ::1.postgres > ::1.38958: Flags [P.], seq 1:18, ack 12, win 1112, options [nop,nop,TS val 2000310 ecr 2000310], length 17 12:51:50.355580 IP6 ::1.38958 > ::1.postgres: Flags [.], ack 18, win 459, options [nop,nop,TS val 2000310 ecr 2000310], length 0 3 packets captured 12 packets received by filter 0 packets dropped by kernel |
Mostrar los paquetes modificando el formato de fecha
Es posible modificar el timestamp mostrado en cada paquete con un formato más legible con la opción -tttt como en el siguiente ejemplo:
1 2 3 4 5 6 7 8 9 |
$ tcpdump -i lo -tttt tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes 2019-08-27 12:54:18.339880 IP6 localhost.38936 > localhost.postgres: Flags [P.], seq 1837123977:1837124198, ack 635151860, win 6146, options [nop,nop,TS val 2148294 ecr 2147292], length 221 2019-08-27 12:54:18.340737 IP6 localhost.37883 > localhost.37883: UDP, length 248 2019-08-27 12:54:18.340780 IP6 localhost.postgres > localhost.38936: Flags [P.], seq 1:289, ack 221, win 3080, options [nop,nop,TS val 2148295 ecr 2148294], length 288 3 packets captured 8 packets received by filter 0 packets dropped by kernel |
Mostrar paquetes con un tamaño superior o inferior a n bytes
Tcpdump también ofrece la posibilidad de capturar sólo el tráfico que tenga un tamaño mínimo especificado. Para ello se puede especificar un tamaño mínimo, un tamaño máximo o ambos.
Para especificar un tamaño mínimo se utiliza el filtro less:
1 2 3 4 5 6 7 8 9 |
$ tcpdump -i lo less 1024 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes 12:59:29.195243 IP localhost.8089 > localhost.56966: Flags [P.], seq 454409493:454409530, ack 1120298145, win 368, options [nop,nop,TS val 2459149 ecr 2458149], length 37 12:59:29.195283 IP localhost.56966 > localhost.8089: Flags [.], ack 37, win 1432, options [nop,nop,TS val 2459149 ecr 2459149], length 0 12:59:29.613357 IP6 localhost.38936 > localhost.postgres: Flags [P.], seq 1837193567:1837193788, ack 635241680, win 6146, options [nop,nop,TS val 2459567 ecr 2458557], length 221 3 packets captured 12 packets received by filter 0 packets dropped by kernel |
Para especificar un tamaño máximo se utiliza el filtro greater:
1 2 3 4 5 6 7 8 |
$ tcpdump -i lo greater 1024 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes 12:56:28.909254 IP localhost.8191 > localhost.47156: Flags [P.], seq 1344585881:1344588292, ack 3500004162, win 3635, options [nop,nop,TS val 2278863 ecr 2278863], length 2411 ^C 1 packet captured 2 packets received by filter 0 packets dropped by kerne |
O es posible el uso de ambos para especificar una franja concreta de tamaño:
1 2 3 4 5 6 7 8 9 |
$ tcpdump -i lo less 1024 && greater 2048 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes 13:01:12.095676 IP6 localhost.38936 > localhost.postgres: Flags [P.], seq 1837216541:1837216762, ack 635271272, win 6146, options [nop,nop,TS val 2562050 ecr 2561048], length 221 13:01:12.096968 IP6 localhost.37883 > localhost.37883: UDP, length 248 13:01:12.097045 IP6 localhost.postgres > localhost.38936: Flags [P.], seq 1:289, ack 221, win 3080, options [nop,nop,TS val 2562051 ecr 2562050], length 288 3 packets captured 8 packets received by filter 0 packets dropped by kernel |
En el ejemplo anterior especificamos que los paquetes deben de tener un tamaño mínimo de 1024 bytes y un tamaño máximo de 2048 bytes, como ya mencionamos es posible utilizar operadores para concatenar diferentes filtros.
Capturar paquetes de un protocolo específico
También es posible capturar el tráfico sólo de aquellos protocolos especificados como podría ser icmp, arp, tcp, udp…
Para ello simplemente hay que especificar dicho protocolo como en el siguiente ejemplo:
1 2 3 4 5 6 7 8 9 10 11 12 |
$ tcpdump -i lo tcp tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes 13:12:39.739806 IP localhost.8089 > localhost.56966: Flags [P.], seq 454438686:454438723, ack 1120298145, win 368, options [nop,nop,TS val 3249694 ecr 3248694], length 37 13:12:39.739850 IP localhost.56966 > localhost.8089: Flags [.], ack 37, win 1432, options [nop,nop,TS val 3249694 ecr 3249694], length 0 13:12:40.185001 IP6 localhost.38936 > localhost.postgres: Flags [P.], seq 1837370302:1837370523, ack 635469740, win 6146, options [nop,nop,TS val 3250139 ecr 3249125], length 221 13:12:40.186797 IP6 localhost.postgres > localhost.38936: Flags [P.], seq 1:289, ack 221, win 3080, options [nop,nop,TS val 3250141 ecr 3250139], length 288 13:12:40.186849 IP6 localhost.38936 > localhost.postgres: Flags [.], ack 289, win 6146, options [nop,nop,TS val 3250141 ecr 3250141], length 0 ^C 5 packets captured 10 packets received by filter 0 packets dropped by kernel |
En el anterior ejemplo capturamos todo el tráfico de la interface de loopback a través del protocolo tcp.
Mostrar paquetes de un puerto específico
Esto puede ayudar mucho a la hora de detectar un fallo en un puerto o si nos interesa conocer que está corriendo en un puerto determinado. Para ello simplemente hay que especificar el filtro port junto con el puerto que queremos analizar:
1 |
$ tcpdump -i any port 22 |
Filtrar tráfico por ip o red
Mediante el uso del filtro host es posible especificar una ip o hostname específico como en el siguiente ejemplo:
1 |
$ tcpdump -i eth0 host 10.0.0.1 |
En caso de querer escanear una red se usaría el filtro net, por ejemplo:
1 |
$ tcpdump -i eth0 net 10.0.0.0/24 |
Filtrar tráfico por origen y destino
Para filtrar el tráfico por su origen o destino es tan sencillo como especificar el mismo mediante los filtros src o dst como en el siguiente ejemplo:
1 2 3 4 |
# origen $ tcpdump src 10.0.0.1 # destino $ tcpdump dst 10.0.0.2 |
También es posible utilizar estos filtros para especificar un puerto, un host o una red específicas de origen y/o destino. Por ejemplo:
1 |
$ tcpdump -i eth0 src host 10.0.0.1 and src port 21 and dst host 10.0.0.2 and dst port 21 |
Modo verbose
Como en la gran mayoría de herramientas, existe un modo debug el cual nos de más información acerca de lo que estamos realizando. En el caso de tcpdump podemos especificar el nivel de debug que deseamos con la opción -v a -vvv según cuanta información se quiere obtener.
1 2 3 |
$ tcpdump -i eth0 -v $ tcpdump -i eth0 -vv $ tcpdump -i eth0 -vvv |
Filtrar por flags TCP
También es posible filtrar por paquetes con un flag TCP específico.
Flag TCP RST
1 2 |
$ tcpdump 'tcp[13] & 4!=0' $ tcpdump 'tcp[tcpflags] == tcp-rst' |
Flag TCP SYN y RST
1 |
$ tcpdump 'tcp[13] = 6' |
Flag TCP SYN
1 2 |
$ tcpdump 'tcp[13] & 2!=0' $ tcpdump 'tcp[tcpflags] == tcp-syn' |
Flag TCP SYN y ACK
1 |
$ <span class="firstc">tcpdump <span class="fourthc">'tcp[13]</span><span class="thirdc">=18</span>'</span> |
Flag TCP ACK
1 2 |
$ tcpdump 'tcp[13] & 16!=0' $ tcpdump 'tcp[tcpflags] == tcp-ack' |
Flag TCP URG
1 2 |
$ tcpdump 'tcp[13] & 32!=0' $ tcpdump 'tcp[tcpflags] == tcp-urg' |
Flag TCP PSH
1 2 |
$ tcpdump 'tcp[13] & 8!=0' $ tcpdump 'tcp[tcpflags] == tcp-psh' |
Flag TCP FIN
1 2 |
$ tcpdump 'tcp[13] & 1!=0' $ tcpdump 'tcp[tcpflags] == tcp-fin' |
Filtrar por cabeceras HTTP
También es posible entre otras cosas filtrar por diferentes datos de una cabecera http.
Filtrar por user-agent
1 |
$ tcpdump -vvAl | grep 'User-Agent:' |
Filtrar por tipo de petición
1 2 3 4 5 6 |
$ tcpdump -vvAl | grep 'GET' $ tcpdump -vvAl | grep 'POST' $ tcpdump -vvAl | grep 'PUT' $ tcpdump -vvAl | grep 'DELETE' $ tcpdump -vvAl | grep 'HEAD' $ tcpdump -vvAl | grep 'OPTIONS' |
Filtrar por cabecera
1 |
$ tcpdump -vvAl | grep 'Host:' |
Filtrar por cookie
1 |
$ tcpdump -vvAl | grep 'Set-Cookie|Cookie:' |
Búsqueda de conexiones ssh
En este caso no se especifica el puerto de la conexión ssh ya que se identifica la misma mediante el banner.
1 |
$ tcpdump 'tcp[(tcp[12]>>2):4] = 0x5353482D' |
Búsqueda de tráfico ftp
Es posible utilizar un nombre ya predefinido o por un puerto específico.
1 |
$ tcpdump -vvA port ftp or ftp-data or 21 |
Búsqueda de contraseñas en plano
Esta consulta la dejo como extra ya que puede ayudar a identificar posibles problemas de seguridad al enviarse credenciales de acceso en texto plano.
1 |
$ tcpdump port http or port ftp or port smtp or port imap or port pop3 or port telnet -lA | egrep -i -B5 'pass=|pwd=|log=|login=|user=|username=|pw=|passw=|passwd= |password=|pass:|user:|username:|password:|login:|pass |user ' |
Esto es todo por el momento. Espero que les sea de utilidad y ya saben cualquier aporte, duda o comentario es bienvenido.