Índice del tutorial
- Qué es Wireshark
- Instalar y permisos
- La interfaz por dentro
- Los tres paneles
- Encapsulación y capas
- Captura vs. visualización
- Lenguaje de filtros
- Ethernet
- ARP
- IPv4
- IPv6
- ICMP
- TCP
- UDP
- DNS
- DHCP
- HTTP
- HTTPS y TLS
- Follow Stream
- Statistics
- Expert Information
- Coloring rules
- Columnas propias
- Perfiles
- Descifrar TLS propio
- tshark
- PCAP y su custodia
- Análisis defensivo
- Línea base
- Escaneo de puertos
- Beaconing
- DNS sospechoso
- ARP anómalo
- Exfiltración
- HTTP sospechoso
- Credenciales en claro
- Resets y pérdidas
- Flujo de análisis
- Informe de incidente
- 12 laboratorios
- Desafíos
- Errores comunes
- Chuleta de filtros
Guía práctica · CachyOS · wlan0 — «Wireshark en 9 capturas»
Nueve ejercicios en orden, cada uno construido sobre el anterior. Abres Wireshark, ejecutas el comando, miras lo que aparece. Al final sabes leer una conversación de red entera.
Esa era la promesa de la primera versión y sigue en pie: los nueve ejercicios están todos aquí. Alrededor han crecido cuatro partes más, hasta cubrir el camino completo —qué es un paquete, cómo se lee cada protocolo, cómo se maneja Wireshark de verdad y cómo se usa todo eso para investigar tráfico sospechoso—. Puedes leerlo de principio a fin como un curso, o entrar por el índice a la sección que necesites.
Fundamentos
Qué es un paquete, qué hace Wireshark con él y cómo se mueve uno por el programa.
Qué es Wireshark y qué no es
Antes de instalar nada, conviene saber qué esperas de la herramienta.
Wireshark es un analizador de protocolos de red. Hace dos cosas, y es útil separarlas desde el principio porque son independientes:
- 1 · Capturar
- Le pide al sistema operativo una copia de cada trama que entra o sale por una
interfaz de red, y la guarda. Esta parte es privilegiada y en Linux la hace un
binario aparte,
dumpcap. - 2 · Analizar
- Coge esos bytes y los disecciona: reconoce que los primeros catorce son una cabecera Ethernet, que dentro hay IP, dentro TCP, dentro HTTP, y te lo presenta con nombres. Esta parte no necesita permisos: puedes analizar un fichero guardado sin capturar nada.
Un sniffer es cualquier programa que hace lo primero. Wireshark es un sniffer, pero su valor está en lo segundo: conoce más de tres mil protocolos y sabe desmontarlos campo a campo.
Lo que Wireshark no hace
Esto ahorra malentendidos, y algunos son frecuentes:
- No bloquea, no modifica, no inyecta. Es un microscopio, no un cortafuegos. Si algo va mal en tu red, Wireshark te dice qué está pasando, pero arreglarlo es otra herramienta.
- No descifra tráfico ajeno. Sin las claves, HTTPS es ruido. Más adelante descifrarás tráfico tuyo porque tu propio navegador te presta sus claves; no hay forma de conseguir las de nadie más.
- No detecta ataques por su cuenta. No es un IDS. Marca anomalías de protocolo, y eres tú quien decide si significan algo.
- No ve lo que no pasa por tu interfaz. Esta es la limitación que más sorprende y merece su propio apartado.
Trama, paquete y qué ve realmente tu tarjeta
Los términos se usan indistintamente en conversación, pero designan cosas distintas y Wireshark los distingue en el árbol:
| Nombre | Capa | Qué incluye |
|---|---|---|
| Trama (frame) | Enlace | Todo lo que viaja por el cable o el aire, cabecera Ethernet incluida. Es la unidad que Wireshark numera y cronometra. |
| Paquete (packet) | Red | La cabecera IP y su contenido, sin la envoltura Ethernet. |
| Segmento | Transporte | La unidad de TCP. En UDP se llama datagrama. |
Por eso el campo frame.len mide la trama completa y ip.len
solo el paquete IP: son números distintos y la diferencia son los 14 bytes de Ethernet.
Tráfico propio, tráfico ajeno y modo promiscuo
Una tarjeta de red normal descarta las tramas que no van dirigidas a su MAC. En modo promiscuo deja de descartarlas y entrega todo lo que oye. Suena potente, pero en una red moderna oye menos de lo que parece:
- En una red con switch (todas las cableadas de hoy), el switch envía cada trama solo al puerto de su destinatario. En modo promiscuo verás tu propio tráfico, el broadcast y el multicast — no las conversaciones de tus vecinos.
- En wifi hace falta además el modo monitor, que es otra cosa: captura tramas 802.11 en bruto del aire. Muchos controladores no lo soportan y al activarlo pierdes la conexión.
- Para ver tráfico de terceros de forma legítima se usa un port mirroring / SPAN configurado en el switch, o un TAP físico. Es una decisión de infraestructura, no una casilla de Wireshark.
Las cuatro limitaciones de cualquier captura
Tenlas presentes antes de sacar conclusiones de una investigación:
- Punto de observación. Solo ves lo que pasa por donde capturas. Un mismo incidente se ve distinto desde el portátil, desde el router o desde el servidor.
- Ventana temporal. Una captura de dos minutos no dice nada sobre un patrón que se repite cada hora.
- Cifrado. Ves con quién se habla y cuánto, casi nunca qué se dice.
- Pérdida. Si el equipo va justo de CPU o disco,
dumpcapdescarta tramas. El diálogo Statistics → Capture File Properties te dice cuántas se perdieron; si el número no es cero, tu captura está incompleta.
Instalar y entender los permisos
Dos paquetes y un grupo de usuario. Y una lección de diseño seguro.
Wireshark en Arch viene partido en dos: wireshark-cli trae el motor de
captura y las herramientas de terminal, wireshark-qt añade la interfaz
gráfica. Instalando el segundo entra el primero como dependencia.
$ sudo pacman -S wireshark-qtCapturar paquetes es una operación privilegiada: le estás pidiendo al kernel que te
entregue tramas en crudo de la tarjeta de red. Ejecutar toda la GUI como root sería una
mala idea (es un programa enorme que parsea datos hostiles de la red), así que Wireshark
aísla esa parte en un binario diminuto, dumpcap, y da acceso solo a los
miembros del grupo wireshark.
$ sudo usermod -aG wireshark $USERVerifica que todo está en su sitio:
$ tshark --version | head -1
$ getcap /usr/bin/dumpcap
/usr/bin/dumpcap cap_net_admin,cap_net_raw=epEsas dos capabilities son exactamente los permisos mínimos:
cap_net_raw para leer tramas crudas y cap_net_admin para poner
la interfaz en modo promiscuo. Nada más.
Leer la salida de getcap, letra a letra
Las capabilities de Linux trocean el poder de root en permisos sueltos, para
poder dar uno sin dar todos. La salida tiene forma nombre=letras y cada
letra es un conjunto:
| Letra | Conjunto | Significado |
|---|---|---|
| e | effective | Activa en cuanto arranca el proceso, sin que el programa tenga que pedirla. |
| p | permitted | El proceso tiene derecho a usarla. |
| i | inheritable | Se transmite a procesos hijos que también la tengan marcada. |
Así que cap_net_admin,cap_net_raw=ep se lee: «este binario puede leer
tramas crudas y administrar la interfaz, y esos permisos están activos desde el
arranque». Si tu salida incluye además cap_dac_override o termina en
=eip, tu distribución ha sido algo más generosa; es habitual y no es un
problema, pero ahora sabes leerlo.
Comprueba también quién puede ejecutarlo:
$ ls -l /usr/bin/dumpcap
-rwxr-xr-- 1 root wireshark ... /usr/bin/dumpcapEl último tramo de permisos es ---: quien no sea root ni miembro del
grupo wireshark ni siquiera puede ejecutarlo. Ese es el mecanismo completo.
Identificar la interfaz correcta
Capturar en la interfaz equivocada es el error número uno de quien empieza: la captura sale vacía y parece que Wireshark no funciona. Averigua primero cuál usas de verdad.
$ ip addrBusca la interfaz que tenga una dirección inet de tu red y la marca
state UP. En este equipo es wlan0 con 10.2.3.170/24.
El /24 te dice además que tu red local va de 10.2.3.1 a
10.2.3.254: cualquier IP fuera de ese rango sale por el router.
$ ip linkMuestra lo mismo sin las direcciones IP, pero incluye la MAC (link/ether)
y el estado físico del enlace. Es donde verías la marca PROMISC si una
interfaz estuviera en modo promiscuo.
$ ip route | head -1
default via 10.2.3.1 dev wlan0Tu gateway. Apúntalo: aparecerá constantemente, porque todo lo que sale de tu red lleva su MAC como destino en la capa 2.
Y la lista tal y como la ve Wireshark:
$ tshark -D
1. wlan0
2. any
3. lo (Loopback)
4. enp8s0
5. docker0 (Docker Bridge)Tres de esas merecen un comentario: lo es el tráfico que tu equipo se
manda a sí mismo (útil para depurar un servidor local, invisible desde fuera);
any es una pseudointerfaz que agrega todas a la vez, cómoda para no fallar
al elegir pero sin cabecera Ethernet real; y docker0 solo tiene tráfico si
hay contenedores corriendo. Si tshark -D no lista ninguna interfaz real, el
grupo todavía no está activo: vuelve al aviso de arriba.
La interfaz por dentro
Un recorrido por el programa antes de empezar a capturar.
La pantalla de inicio
Al abrir Wireshark no hay ninguna captura: hay una lista de interfaces con una sparkline al lado de cada una. Esa gráfica en miniatura es tráfico en vivo, y es la forma más rápida de acertar con la interfaz: la que se mueve es la que está en uso. Doble clic sobre ella empieza a capturar.
Debajo de la lista hay un campo etiquetado «…using this filter»: ahí va el capture filter, no el de visualización. Es una distinción que confunde a todo el mundo al principio y tiene su propia sección más abajo.
La barra de herramientas
De izquierda a derecha, los controles que vas a usar de verdad:
| Control | Qué hace |
|---|---|
| Aleta azul | Iniciar captura en la interfaz seleccionada. |
| Cuadrado rojo | Detener. La captura sigue en memoria y se puede analizar y guardar. |
| Flecha circular | Reiniciar: descarta lo capturado y vuelve a empezar. |
| Lupa | Buscar dentro de los paquetes (Ctrl+F), por cadena, hex o filtro. |
| Flechas ← → | Ir al paquete anterior/siguiente del historial de navegación. |
| Regla / reloj | Poner el tiempo a cero desde el paquete seleccionado. Imprescindible para medir intervalos. |
| Colores | Activa o desactiva las reglas de coloreado. |
La barra de estado
La franja de abajo se ignora y no debería. De izquierda a derecha lleva:
- Un círculo de color con el nivel máximo de Expert Information de la captura. Rojo es «error». Pulsarlo abre el diálogo directamente.
- El fichero de captura y su tamaño.
- Packets (capturados), Displayed (los que pasan el filtro actual, con su porcentaje) y Dropped. Vigila ese último número.
- El perfil activo, a la derecha. Pulsar ahí cambia de perfil.
Preferences: lo que merece la pena tocar
En Edit → Preferences, tres ajustes cambian el día a día:
- Appearance → Layout. Coloca los tres paneles. En pantallas anchas, poner Packet Details y Packet Bytes uno al lado del otro gana mucho espacio vertical.
- Appearance → Columns. Las columnas de la lista; tiene sección propia más abajo.
- Protocols. Un ajuste por disector. Aquí desactivarás los números de secuencia relativos de TCP y configurarás el descifrado de TLS.
Name Resolution: cómodo y peligroso a la vez
En View → Name Resolution puedes pedir que Wireshark traduzca lo que ve. Hay tres tipos y no son equivalentes:
| Tipo | Convierte | Cuidado |
|---|---|---|
| Physical | MAC → fabricante (b8:1e:a4 → el OUI del fabricante) | Ninguno: es una tabla local. |
| Transport | Puerto → servicio (443 → https) | Es una convención, no un hecho: un servicio puede usar cualquier puerto. |
| Network | IP → nombre de dominio | Genera consultas DNS desde tu equipo. |
Los tres paneles
Siempre son los mismos tres, siempre significan lo mismo.
- Arriba · Packet List
- Una línea por paquete. No. orden de captura · Time segundos desde que empezaste · Source y Destination · Protocol el más alto que Wireshark supo reconocer · Length bytes totales · Info el resumen legible. Los colores vienen de reglas configurables: negro sobre rojo casi siempre significa problema.
- Medio · Packet Details
- El paquete seleccionado, desmontado en el árbol de capas de arriba. Cada rama se despliega. Aquí es donde se aprende: despliega TCP y verás los puertos, el número de secuencia, los flags, la ventana. Clic derecho sobre cualquier campo → Apply as Filter construye el filtro por ti.
- Abajo · Packet Bytes
- Los bytes reales en hexadecimal y ASCII. Al pinchar un campo del árbol, se resaltan sus bytes aquí. Es la prueba de que el árbol no se inventa nada: cada nombre bonito corresponde a una posición concreta.
Para empezar una captura: doble clic en wlan0 en la pantalla de inicio.
La sparkline al lado de cada interfaz muestra actividad — así sabes cuál está viva antes
de elegir. Para parar, el cuadrado rojo. Para descartar y volver a empezar, la escoba.
El puente entre el panel del medio y el de abajo
Esta correspondencia es el mejor ejercicio conceptual de todo Wireshark, porque demuestra que los nombres bonitos del árbol son solo una lectura de bytes concretos. Selecciona un paquete y mira dónde cae cada campo:
Time to Live
en el árbol, Wireshark resalta el byte marcado: 40 hexadecimal = 64.
- Ethernet: MAC destino, MAC origen, EtherType
- IPv4: versión, longitud, TTL, protocolo, IP origen y destino
- ICMP: tipo, código, identificador
Compruébalo tú: pincha Time to Live y verás un solo byte resaltado abajo;
pincha Source Address y se resaltan cuatro; pincha la rama
Internet Protocol Version 4 entera y se resaltan los veinte de la cabecera.
El panel de bytes es la verdad; el árbol es su traducción.
El menú View → Time Display Format cambia lo que significa la columna Time: segundos desde el inicio de la captura (por defecto), hora del día, o delta respecto al paquete anterior. El delta es el que usarás para medir periodicidad.
Encapsulación: el modelo mental
Un paquete es una cebolla. Wireshark la pela.
Cuando tu navegador pide una página, ese dato no viaja solo: cada capa de la pila de red lo envuelve con su propia cabecera antes de pasarlo abajo. Lo que sale por la antena wifi es este bloque de bytes:
- MAC origen y destino — el salto físico
- IP origen y destino — la ruta global
- Puertos, secuencia, flags — la conversación
- El contenido
Cada capa solo sabe de la siguiente. Ethernet entrega la trama al router de al lado; IP sabe llevarla hasta el otro extremo del mundo; TCP se encarga de que llegue completa y en orden; HTTP es el idioma que hablan los dos programas. Wireshark hace una cosa: coge esos bytes y te los desmonta capa por capa, con nombres.
Y algo que conviene tener claro desde el principio: Wireshark no toca nada. No bloquea, no modifica, no inyecta. Es un microscopio, no un cortafuegos. Si algo va mal en tu red, Wireshark te dice qué está pasando, pero arreglarlo es otra herramienta.
Dónde encaja cada protocolo
El modelo OSI tiene siete capas y el de TCP/IP cuatro. Wireshark no dibuja ninguno de los dos: dibuja lo que hay realmente en la trama. Esta tabla traduce entre ambos mundos y te dice qué escribir en la barra de filtros para quedarte con cada nivel:
| OSI | TCP/IP | Protocolos | Filtro |
|---|---|---|---|
| 7–5 Aplicación | Aplicación | HTTP, DNS, DHCP, TLS | http · dns · dhcp · tls |
| 4 Transporte | Transporte | TCP, UDP | tcp · udp |
| 3 Red | Internet | IPv4, IPv6, ICMP | ip · ipv6 · icmp |
| 2 Enlace | Acceso a red | Ethernet, ARP | eth · arp |
| 1 Física | Acceso a red | Cable, radio | No se captura |
Dos detalles que rompen la simetría del dibujo y conviene saber: ARP no tiene
cabecera IP —vive entre la capa 2 y la 3, y por eso no se puede filtrar por
ip.addr—; y TLS no es una capa OSI, sino una envoltura que
se coloca entre TCP y la aplicación, que es exactamente como Wireshark lo muestra en el
árbol.
Filtros: la distinción que hay que interiorizar
Hay dos tipos de filtro y no se parecen en nada.
Este es el punto donde más gente se atasca. Wireshark tiene dos sistemas de filtrado distintos, con sintaxis distintas, en momentos distintos.
Capture filter — antes de capturar
Se escribe en la pantalla de inicio, debajo de la lista de interfaces. Decide qué
paquetes se guardan y cuáles se tiran a la basura sin mirarlos. Usa sintaxis BPF, la
misma de tcpdump: host 1.1.1.1, port 53,
tcp and not port 22. Lo que descartas aquí, lo pierdes para siempre. Se usa
cuando el volumen es tan alto que capturarlo todo no es viable.
Display filter — después de capturar
La barra verde ancha en la parte superior de la ventana principal. Filtra la
vista; los paquetes ocultos siguen ahí y vuelven en cuanto borras el filtro.
Sintaxis propia de Wireshark, mucho más rica: ip.addr == 1.1.1.1,
dns, tcp.flags.syn == 1 && tcp.flags.ack == 0.
Dos detalles de sintaxis que ahorran confusión: ip.addr == X significa
«origen o destino es X», mientras que ip.src e ip.dst
son direccionales. Y escribir solo el nombre de un protocolo (dns,
tls, arp) filtra todos los paquetes que lo contienen — es el
filtro más útil y más corto que existe.
Comparación lado a lado
| Capture filter | Display filter | |
|---|---|---|
| Cuándo | Antes de capturar | Sobre lo ya capturado |
| Dónde | Pantalla de inicio, bajo las interfaces | Barra ancha superior |
| Sintaxis | BPF, la de tcpdump | Propia de Wireshark |
| Reversible | No: lo descartado se pierde | Sí: borras el filtro y vuelve todo |
| Campos | Pocos, de bajo nivel | Más de 300 000 campos |
| Igualdad | host 10.2.3.1 | ip.addr == 10.2.3.1 |
| Puerto | port 53 | tcp.port == 53 || udp.port == 53 |
| Negación | not arp | !arp |
| Conjunción | tcp and port 443 | tcp && tcp.port == 443 |
| Para qué | Contener el volumen en enlaces cargados | Investigar |
El lenguaje de los display filters
Construir un filtro por capas en lugar de memorizarlo.
Un display filter es una expresión que se evalúa contra cada paquete: si da verdadero, el paquete se muestra. Hay tres formas de construirla, de menor a mayor precisión.
Nivel 1 · Solo el nombre del protocolo
Escribir el nombre de un protocolo es un filtro completo: significa «este paquete contiene ese protocolo en alguna capa».
dnsNivel 2 · Un campo comparado con un valor
La forma campo operador valor. Los operadores de comparación:
| Operador | Alias | Significado | Ejemplo |
|---|---|---|---|
| == | eq | Igual | ip.src == 10.2.3.170 |
| != | ne | Distinto | tcp.dstport != 443 |
| > | gt | Mayor que | frame.len > 1400 |
| < | lt | Menor que | ip.ttl < 10 |
| >= | ge | Mayor o igual | http.response.code >= 400 |
| <= | le | Menor o igual | tcp.window_size_value <= 1000 |
Nivel 3 · Combinar condiciones
| Operador | Alias | Significado |
|---|---|---|
| && | and | Se cumplen las dos condiciones |
| || | or | Se cumple al menos una |
| ! | not | Niega la condición |
Operadores de contenido
| Operador | Qué hace | Ejemplo |
|---|---|---|
| contains | Busca una secuencia de bytes o texto dentro del campo. Distingue mayúsculas. | dns.qry.name contains "example" |
| matches | Expresión regular PCRE. Antepón (?i) para ignorar mayúsculas. | http.host matches "(?i)cdn" |
| in | Pertenencia a un conjunto. Los elementos van separados por comas. | tcp.port in {80, 443, 8080} |
$ dftest 'tcp.port in {80, 443, 8080}' # válido
$ dftest 'tcp.port in {80 443 8080}' # error de sintaxisOtro conjunto útil es el rango, con dos puntos suspensivos: ip.ttl in {1 .. 5}
selecciona los TTL del 1 al 5, que es lo que verías en un traceroute.
Construir un filtro por capas
No escribas el filtro completo de una vez. Empieza ancho y ve estrechando, mirando cuántos paquetes quedan en Displayed después de cada paso:
- Todo lo que tenga que ver con ese equipo:
ip.addr == 10.2.3.170 - Solo lo que sale de él:
ip.src == 10.2.3.170 - Solo TCP:
ip.src == 10.2.3.170 && tcp - Solo HTTPS:
ip.src == 10.2.3.170 && tcp.port == 443 - Solo aperturas de conexión:
ip.src == 10.2.3.170 && tcp.flags.syn == 1 && tcp.flags.ack == 0
Si en un paso el resultado se queda vacío, sabes exactamente qué condición lo vació. Depurar un filtro de cinco condiciones escrito de golpe es mucho más difícil.
El atajo que hace innecesario memorizar campos
Nadie recuerda que el nombre del servidor en TLS es
tls.handshake.extensions_server_name. No hace falta: clic derecho
sobre el campo en el árbol → Apply as Filter → Selected. Wireshark escribe el
filtro correcto en la barra. Así es como se aprenden los nombres de los campos —
trabajando, no estudiando una lista.
Variantes del mismo menú que conviene conocer:
- Prepare as Filter escribe el filtro en la barra pero no lo aplica: sirve para seguir editándolo antes de pulsar Intro.
- …and Selected / …or Selected añade la condición al filtro que ya tenías, en vez de sustituirlo.
- …not Selected lo añade negado. Es la forma rápida de ir quitando ruido: aplica, ves lo que sobra, lo excluyes, repites.
Y el botón + al final de la barra guarda el filtro actual como botón con nombre. Si repites un filtro cada día, déjalo ahí.
Protocolos
Capa por capa, de la MAC al TLS: qué campos importan, cómo se filtran y qué revelan.
Ethernet
La capa 2: catorce bytes que deciden el siguiente salto.
Qué es. Ethernet mueve tramas entre dos equipos del mismo segmento de red. No sabe nada de internet ni de rutas: solo «entrega esto a la tarjeta cuya dirección física es esta».
Cómo funciona. Su cabecera son 14 bytes con tres campos:
Una dirección MAC son 6 bytes, escritos como b8:1e:a4:5a:ac:8d. Los tres
primeros son el OUI, el identificador del fabricante: Wireshark lo
traduce solo, y por eso en la columna a veces ves IntelCor_5a:ac:8d en lugar
del hexadecimal. Es información real y gratuita: te dice qué clase de dispositivo hay
detrás de una MAC.
El EtherType dice qué viene después. Los tres que verás:
| Valor | Contenido | Filtro |
|---|---|---|
| 0x0800 | IPv4 | eth.type == 0x0800 |
| 0x0806 | ARP | eth.type == 0x0806 |
| 0x86dd | IPv6 | eth.type == 0x86dd |
Unicast, broadcast y multicast
La MAC de destino determina quién recoge la trama, y el bit menos significativo del primer byte lo decide:
| Tipo | Destino | Quién la recibe |
|---|---|---|
| Unicast | Una MAC concreta | Un solo equipo. Es la inmensa mayoría del tráfico. |
| Broadcast | ff:ff:ff:ff:ff:ff | Todos los equipos del segmento. ARP y DHCP lo usan. |
| Multicast | Primer byte impar (p. ej. 01:00:5e:…) | Los que se han suscrito a ese grupo. mDNS, SSDP, IPv6. |
Cómo lo veo en Wireshark
Despliega la rama Ethernet II del panel del medio. Dentro de
Destination hay dos subcampos que Wireshark calcula por ti:
LG bit (dirección local o global) e IG bit (individual o de
grupo). Ese IG bit a 1 es precisamente la definición de multicast/broadcast.
Filtros
eth.addr == b8:1e:a4:5a:ac:8dTodo lo que sale o entra en esa tarjeta. Útil cuando investigas un equipo cuya IP cambia (DHCP) pero cuya MAC no.
eth.src == b8:1e:a4:5a:ac:8dSolo lo que ese equipo emite. Con eth.dst, solo lo que recibe.
eth.dst == ff:ff:ff:ff:ff:ffTodo el broadcast del segmento: ARP, DHCP, anuncios de servicios. Es un buen primer vistazo a «quién hay» en una red desconocida, porque los equipos se anuncian solos.
eth.ig == 1Broadcast y multicast a la vez. Si el tráfico de grupo se dispara sin motivo, aquí se ve.
Error común. Buscar la MAC de un servidor de internet en la captura. Nunca aparecerá: solo ves las MAC de tu propio segmento.
ARP
Cómo encuentra tu equipo al router — y por qué es el protocolo más fácil de abusar.
Objetivo: ver la capa 2 en acción, por debajo de IP.
En el apartado anterior tu equipo puso la MAC del router en la trama. ¿Cómo la sabía? La preguntó a gritos. Filtra:
arpFuerza uno borrando la entrada de la tabla y volviendo a hablar con el router:
$ sudo ip neigh flush all
$ ping -c 2 10.2.3.1Verás el par clásico. El primero va a destino ff:ff:ff:ff:ff:ff —
broadcast, lo recibe toda la red local — y su Info dice Who has
10.2.3.1? Tell 10.2.3.170. El segundo es la respuesta directa:
10.2.3.1 is at ....
ARP no tiene cabecera IP. Es capa 2 pura: solo funciona dentro de tu red local, y por
eso no hay ARP para 1.1.1.1 — para salir de la red, todo va al router y él
se encarga.
Los dos mensajes, y cómo separarlos
El campo arp.opcode distingue la pregunta de la respuesta:
arp.opcode == 1Request. Va en broadcast porque el emisor todavía no sabe a quién preguntar. El campo «Target MAC address» va a ceros: es justo lo que está preguntando.
arp.opcode == 2Reply. Va en unicast, directo al que preguntó. Lleva la MAC en
arp.src.hw_mac.
La caché ARP
El resultado se guarda unos minutos para no preguntar cada vez. Puedes verla:
$ ip neigh
10.2.3.1 dev wlan0 lladdr 2c:3a:fd:11:04:e0 REACHABLEEsa tabla es la que un atacante intenta envenenar, y por eso ARP importa en seguridad.
Ciberseguridad: reconocer ARP anómalo
ARP se diseñó en 1982 sin ninguna autenticación: cualquier equipo puede responder a cualquier pregunta, y el que pregunta se cree la respuesta. Un atacante en el mismo segmento puede afirmar «10.2.3.1 soy yo» y hacer que tu tráfico pase por su máquina. Eso se llama ARP spoofing o poisoning.
No vas a aprender a hacerlo aquí. Vas a aprender qué rastro deja, que es lo que te sirve como defensor:
- Dos MAC distintas afirmando ser la misma IP. Es la señal más directa. En una red sana, cada IP tiene una sola MAC.
- Replies sin request previo (ARP «gratuito» en exceso). Uno ocasional es normal —los equipos lo usan al arrancar para anunciarse—; un goteo constante hacia un mismo objetivo, no.
- La MAC del gateway cambia a mitad de la captura. El gateway es el objetivo preferido porque por él pasa todo.
- Frecuencia anormal. El envenenamiento hay que refrescarlo antes de que caduque la caché legítima, así que suele verse un ritmo regular.
Wireshark trae un detector para el primer caso, y es el filtro que deberías conocer:
arp.duplicate-address-detectedMarca los paquetes donde el disector ha visto que una IP cambia de MAC. Junto a él,
arp.duplicate-address-frame apunta al número de trama del conflicto anterior,
para poder comparar los dos.
Práctica. Aplica arp a una captura de diez minutos de tu
red y abre Statistics → Endpoints → Ethernet. Anota qué MAC corresponde a
tu gateway. Esa es tu línea base: si otro día no coincide, tienes algo que investigar.
IPv4
Veinte bytes que llevan un paquete de un extremo del mundo al otro.
Qué es. IP es el protocolo que sabe llegar a cualquier destino de internet. Es no fiable a propósito: no garantiza entrega, ni orden, ni ausencia de duplicados. Todo eso lo pone TCP encima. IP solo se ocupa de direccionar y de que el paquete no dé vueltas para siempre.
La cabecera, campo a campo
Este es el diagrama que conviene tener en la cabeza. Cada fila son 32 bits (4 bytes); la cabecera mínima son cinco filas, 20 bytes:
| Campo | Qué significa | Filtro |
|---|---|---|
| Version | Siempre 4 aquí. Es lo que distingue IPv4 de IPv6 al empezar a leer. | ip.version |
| IHL | Longitud de la cabecera en palabras de 4 bytes. Vale 5 (=20 bytes) salvo que haya opciones. Wireshark ya lo muestra en bytes. | ip.hdr_len |
| DSCP | Marca de calidad de servicio. Voz y vídeo la usan para pedir prioridad; el resto va a 0. | ip.dsfield.dscp |
| ECN | Notificación de congestión. Permite avisar de congestión sin descartar el paquete. | ip.dsfield.ecn |
| Total Length | Cabecera IP + contenido, en bytes. No incluye Ethernet: por eso es 14 menos que frame.len. | ip.len |
| Identification | Identificador del datagrama original. Todos los fragmentos de un mismo paquete lo comparten: así se reensambla. | ip.id |
| Flags | Tres bits. DF (no fragmentar) y MF (vienen más fragmentos). | ip.flags |
| Fragment Offset | Posición de este fragmento dentro del original, en unidades de 8 bytes. | ip.frag_offset |
| TTL | Cada router lo decrementa en 1. Al llegar a 0 el paquete se descarta y se devuelve un ICMP. Evita bucles infinitos. | ip.ttl |
| Protocol | Qué viene después: 1=ICMP, 6=TCP, 17=UDP. | ip.proto |
| Header Checksum | Suma de verificación de la cabecera. Se recalcula en cada salto porque el TTL cambia. | ip.checksum |
| Source / Destination | Las direcciones. Sobreviven todo el trayecto, a diferencia de las MAC. | ip.src · ip.dst |
El TTL cuenta una historia
Este es el campo que más información gratuita da. Los sistemas operativos parten de valores conocidos: Linux y macOS de 64, Windows de 128, muchos routers de 255. Como cada salto resta 1, la distancia al origen es la diferencia.
Haz un ping a 1.1.1.1 y compara: el request sale con ttl=64
y la respuesta llega con ttl=51. Como 64 − 51 = 13, esa respuesta atravesó
13 routers para llegar a ti. Y como el valor de partida era 64, el equipo
del otro lado es casi seguro un Linux.
ip.ttl < 20Paquetes que han recorrido muchos saltos. En una captura de red local no debería aparecer casi nada; si tu tráfico interno tiene TTL bajo, algo lo está enrutando de más.
Fragmentación
Si un paquete no cabe en el MTU de un enlace (típicamente 1500 bytes), se parte. Los
fragmentos comparten ip.id, todos menos el último llevan el bit
MF a 1, y cada uno indica su posición en ip.frag_offset.
ip.flags.mf == 1 || ip.frag_offset > 0Ese filtro muestra todos los fragmentos. En una red bien dimensionada la fragmentación IPv4 es rara: si aparece mucha, suele haber un problema de MTU (una VPN, un túnel) que además degrada el rendimiento. Wireshark reensambla los fragmentos y te muestra el paquete completo en el último, indicando de qué tramas lo ha compuesto.
Filtros de dirección: la diferencia que hay que tener clara
ip.addr == 10.2.3.170Origen o destino. Es «todo lo que tenga que ver con este equipo».
ip.src == 10.2.3.170Solo lo que sale. ip.dst para lo que entra.
ip.addr == 10.2.3.0/24Una red entera en notación CIDR. Combinado con una negación, aísla el tráfico que sale de tu red — que es justo lo que interesa mirar en un análisis de exfiltración:
ip.src == 10.2.3.0/24 && !(ip.dst == 10.2.3.0/24)Práctica. Captura treinta segundos de navegación normal y aplica
ip.ttl < 64 && ip.ttl > 40. Ordena por la columna Source. Los
grupos de TTL iguales son grupos de servidores a la misma distancia de ti.
IPv6
Está en tu captura aunque no lo hayas configurado.
Abre una captura cualquiera y filtra por ipv6: casi seguro que hay
tráfico. Los sistemas modernos lo traen activado y prefieren IPv6 cuando hay ambos
disponibles. Merece la pena reconocerlo aunque no lo administres.
Lo que cambia respecto a IPv4:
| IPv4 | IPv6 | |
|---|---|---|
| Dirección | 32 bits · 10.2.3.170 | 128 bits · fe80::b81e:a4ff:fe5a:ac8d |
| Cabecera | 20 bytes variables | 40 bytes fijos, más simple |
| Checksum | Sí | No: lo hacen las capas de arriba |
| Fragmenta | Cualquier router | Solo el origen |
| Equivale a TTL | ip.ttl | ipv6.hlim (hop limit) |
| Siguiente capa | ip.proto | ipv6.nxt |
| ARP | ARP | NDP, dentro de ICMPv6 |
| Broadcast | Existe | No existe: solo multicast |
Las direcciones que empiezan por fe80:: son link-local:
se autoconfiguran solas, solo valen dentro del segmento y no salen a internet. Son las
que más verás en una captura doméstica.
ipv6ipv6.addr == fe80::1icmpv6Ese último es importante: en IPv6, el descubrimiento de vecinos (el equivalente a ARP),
el anuncio de routers y la autoconfiguración van todos dentro de ICMPv6. Si filtras
icmpv6 en tu red verás los Router Advertisement y los
Neighbor Solicitation que hacen ese trabajo.
ICMP
El protocolo más simple que hay — y por eso el mejor para aprender a leer el árbol.
Objetivo: leer el árbol de capas de un paquete que entiendes entero.
Empieza la captura en wlan0. Verás una avalancha de tráfico de fondo —
es normal, tu equipo habla solo todo el rato. Pega este filtro en la barra verde para
quedarte solo con lo tuyo:
icmpLa lista se queda vacía. Ahora, en la terminal:
$ ping -c 4 1.1.1.1Aparecen ocho paquetes: cuatro Echo (ping) request y cuatro Echo (ping) reply, alternados. Selecciona el primer request y despliega el árbol del panel del medio. Vas a ver exactamente las tres capas del diagrama de arriba:
- Ethernet II — origen
b8:1e:a4:5a:ac:8d(tu tarjeta wifi) y destino la MAC de tu router. Fíjate: la MAC destino no es la de Cloudflare. Es la del siguiente salto. - Internet Protocol Version 4 — origen
10.2.3.170, destino1.1.1.1. Aquí sí está el destino final. Despliega y buscaTime to Live: es el contador de saltos que evita que un paquete perdido dé vueltas para siempre. - Internet Control Message Protocol — tipo 8 (request). En la
respuesta será tipo 0 (reply). Al final hay un campo
Datacon bytes de relleno.
Pincha el campo TTL en el árbol y mira el panel de abajo: se resalta un byte. Ese byte es el TTL. No hay magia.
Emparejar request y reply
Un ping son pares. Despliega el árbol ICMP y verás dos campos que los enlazan:
Identifier— igual en toda la serie. Identifica esta ejecución deping, para que dos pings simultáneos no se mezclen.Sequence Number— incrementa 1, 2, 3, 4. Identifica cada envío.
Wireshark hace el emparejamiento por ti: en la respuesta verás una línea
[Request In: 1], y en el request un [Response In: 2]. Y en la
respuesta añade [Response Time: …ms], que es la latencia real medida sobre
el paquete, no la que estima ping.
icmp.ident == 0xc977Aísla una ejecución concreta de ping cuando hay varias mezcladas.
Los tipos que vas a encontrar
| Tipo | Nombre | Qué significa |
|---|---|---|
| 8 | Echo Request | «¿Estás ahí?» — lo que envía ping. |
| 0 | Echo Reply | «Sí». Ojo al orden contraintuitivo: la respuesta es el tipo 0. |
| 3 | Destination Unreachable | No hay camino. El code dice por qué: 0 red, 1 host, 3 puerto, 13 prohibido administrativamente (un cortafuegos). |
| 11 | Time Exceeded | El TTL llegó a 0. Es lo que hace funcionar a traceroute. |
| 5 | Redirect | «Usa mejor este otro router». Poco frecuente y a menudo indeseado. |
icmp.type == 8icmp.type == 3 && icmp.code == 13Ese segundo es muy útil al diagnosticar: significa que un cortafuegos está bloqueando y avisando. Si no llega nada en absoluto, el cortafuegos descarta en silencio, que es lo habitual.
Ciberseguridad: qué mirar en ICMP
ICMP es una herramienta de diagnóstico legítima y necesaria. Bloquearlo entero es un error clásico que rompe el descubrimiento de MTU. Pero hay patrones que merecen mirada:
- Barrido (ping sweep). Un origen envía echo request a muchas IP consecutivas del rango en poco tiempo. La señal es la forma: un origen, muchos destinos, secuencial, sin respuestas para la mayoría.
- Volumen desproporcionado. ICMP debería ser una fracción mínima del tráfico. Compruébalo en Statistics → Protocol Hierarchy: si ICMP es un porcentaje llamativo, pregúntate por qué.
- Payload grande o con contenido. El campo
Datade un ping normal es relleno predecible. Paquetes ICMP con cargas grandes y variables, de forma sostenida y bidireccional, son el patrón de un túnel sobre ICMP. - Periodicidad. Echo requests cada N segundos exactos hacia un destino externo fijo.
icmp && data.len > 64TCP
La sección más larga, porque es el protocolo del que más se diagnostica.
Objetivo: entender cómo TCP abre una conexión — el concepto central del protocolo.
Qué es. TCP convierte el servicio no fiable de IP en un flujo de bytes ordenado y sin pérdidas. Para conseguirlo numera cada byte, confirma lo recibido, retransmite lo que falta y controla el ritmo para no ahogar al receptor ni a la red. Todo eso deja rastro en la cabecera, y ese rastro es lo que lees en Wireshark.
Puertos: cómo se identifica una conversación
Una conexión TCP se identifica por cuatro valores: IP origen, puerto origen, IP destino, puerto destino. Esa tupla es única, y es lo que permite a tu navegador tener veinte conexiones al mismo servidor a la vez: cambia el puerto origen.
El puerto de destino identifica el servicio (443 = HTTPS); el de origen lo elige el sistema al azar en el rango alto (32768–60999 en Linux) y se llama puerto efímero. Por eso, en una captura, el lado con puerto alto es casi siempre el cliente.
El handshake de tres vías
Antes de que se envíe un solo byte útil, los dos extremos se sincronizan con tres paquetes:
Vamos a verlo. Este filtro aísla exactamente los paquetes de apertura — SYN activo y ACK apagado, que solo ocurre en el primer paquete de cada conexión nueva:
tcp.flags.syn == 1 && tcp.flags.ack == 0$ curl -s -o /dev/null http://neverssl.comAparece un SYN. Ahora quita el filtro y en su lugar haz clic derecho sobre ese paquete → Conversation Filter → TCP. Wireshark escribe solo un filtro con las dos IPs y los dos puertos, y te deja la conversación completa: los tres paquetes del handshake, la petición HTTP, la respuesta, y el cierre con FIN.
En el árbol de cada paquete despliega Flags dentro de TCP. Los bits que importan:
| Flag | Significa |
|---|---|
| SYN | Abriendo conexión, sincroniza números de secuencia |
| ACK | Confirmo lo que me has mandado hasta el byte N |
| PSH | Entrega estos datos a la aplicación ya, no esperes |
| FIN | He terminado de enviar, cierre ordenado |
| RST | Corte abrupto. Casi siempre señal de problema |
Sequence y Acknowledgement, sin misterio
Estos dos números confunden hasta que se entiende que cuentan bytes, no paquetes:
tcp.seq— el número del primer byte de datos que va en este segmento.tcp.ack— el número del siguiente byte que espero recibir. Es decir: «tengo todo hasta el byte ack−1».tcp.len— cuántos bytes de datos lleva este segmento. Los ACK puros llevan 0.
La aritmética es siempre la misma: si recibo un segmento con seq=1 y
len=500, responderé con ack=501. Con números relativos esto se
lee de un vistazo.
SYN y FIN consumen un número de secuencia aunque no lleven datos. Por eso el
ack=1 del handshake, cuando no se había enviado ningún byte: el 0 lo gastó
el SYN.
Window size: el control de flujo
tcp.window_size_value es lo que el emisor anuncia; tcp.window_size
es ese valor ya multiplicado por el factor de escala que se negoció en el handshake.
Wireshark calcula el segundo por ti, y es el que debes mirar.
Significa «tengo sitio para tantos bytes más sin confirmar». Si baja mucho, el receptor no da abasto procesando. Si llega a cero, se para todo:
tcp.analysis.zero_windowVentana cero es un hallazgo de primera categoría cuando alguien reporta lentitud: el problema no está en la red, está en el equipo que anuncia el cero, que no lee su buffer lo bastante rápido.
Cerrar la conexión
Hay dos formas, y distinguirlas importa:
| Cierre | Secuencia | Qué significa |
|---|---|---|
| Ordenado (FIN) | FIN → ACK → FIN → ACK | Cada lado dice que terminó de enviar. Es lo normal y garantiza que no se pierden datos en vuelo. |
| Abrupto (RST) | RST | «Se acabó, ya». Descarta lo que hubiera pendiente. |
tcp.flags.fin == 1tcp.flags.reset == 1El motor de análisis de Wireshark
Wireshark no solo muestra los campos: sigue el estado de cada conexión y marca lo que
no cuadra. Esos son los campos tcp.analysis.*, y son la herramienta de
diagnóstico más potente del programa.
| Filtro | Qué detectó | Cómo interpretarlo |
|---|---|---|
| tcp.analysis.retransmission | Datos ya enviados vuelven a enviarse | Algo se perdió por el camino, o el ACK no llegó a tiempo. |
| tcp.analysis.fast_retransmission | Retransmisión disparada por ACK duplicados, sin esperar al temporizador | Pérdida detectada rápido. Es el mecanismo funcionando bien. |
| tcp.analysis.duplicate_ack | El receptor repite el mismo ACK | «Me falta un trozo». Tres seguidos disparan la retransmisión rápida. |
| tcp.analysis.out_of_order | Un segmento llegó antes que otro anterior | Suele ser reordenación de la red, no pérdida. No es grave por sí solo. |
| tcp.analysis.lost_segment | Hay un hueco en la numeración | Ojo: puede significar que se perdió, o solo que tú no lo capturaste. |
| tcp.analysis.zero_window | Ventana anunciada a 0 | El receptor está saturado. Problema de aplicación, no de red. |
| tcp.analysis.flags | Cualquiera de las anteriores | El filtro de barrido: empieza siempre por aquí. |
tcp.analysis.flagsMuestra solo los paquetes que Wireshark ha marcado como problemáticos. En una red sana, apenas aparece nada.
Navegar por una conexión
tcp.stream es un número que Wireshark asigna a cada conexión de la
captura, empezando en 0. Es la forma más rápida de moverse:
tcp.stream eq 3Y tcp.time_delta es el tiempo desde el paquete anterior de la misma
conexión — mucho más útil que el delta global cuando hay tráfico mezclado. Para
usarlo hay que activarlo en Edit → Preferences → Protocols → TCP → «Calculate conversation
timestamps».
tcp.time_delta > 1Paquetes que llegaron más de un segundo después del anterior de su conexión. Es la forma de encontrar dónde exactamente se quedó parada una transferencia lenta.
Práctica. Captura un curl a cualquier web, aplica
tcp.flags.syn == 1 && tcp.flags.ack == 0 para localizar la apertura,
anota el número de tcp.stream, y filtra por él. Sigue la conversación entera
contando los paquetes: tres de handshake, la petición, la respuesta, el cierre. Si sabes
explicar cada paquete de esa lista, entiendes TCP.
UDP
Ocho bytes de cabecera y ninguna promesa.
Qué es. UDP es la alternativa mínima a TCP: pone puertos sobre IP y poco más. No hay conexión, ni confirmación, ni orden, ni retransmisión. Si un datagrama se pierde, se pierde y nadie se entera — salvo la aplicación, si le importa.
Eso, que suena a defecto, es exactamente lo que quieren DNS (una pregunta, una respuesta: montar una conexión costaría más que reintentar), el vídeo en tiempo real (un fotograma retransmitido llega tarde y ya no sirve) y DHCP (todavía no tienes ni IP).
udp.srcport/udp.dstport— igual que en TCP.udp.length— cabecera más datos. Como la cabecera son 8, el contenido esudp.length − 8.udp.checksum— opcional en IPv4, obligatorio en IPv6.
TCP frente a UDP, de un vistazo
| TCP | UDP | |
|---|---|---|
| Conexión | Handshake de 3 vías | Ninguna: se envía y ya |
| Cabecera | 20 bytes mínimo | 8 bytes fijos |
| Entrega | Garantizada y en orden | Sin garantía |
| Retransmite | Sí, automáticamente | No: si acaso, la aplicación |
| Control de flujo | Sí (window) | No |
| En Wireshark | Estado por conexión, tcp.analysis.*, Follow Stream | Sin estado: cada datagrama es independiente |
| Se usa en | HTTP, HTTPS, SSH, correo | DNS, DHCP, NTP, QUIC, voz y vídeo |
udpudp.port == 53udp.length > 512DNS
Nombres a números — y el protocolo que más cuenta sobre lo que hace un equipo.
Objetivo: emparejar consulta y respuesta, y ver el primer protocolo de aplicación.
dns$ dig +short archlinux.orgDos paquetes: Standard query y Standard query response. Despliega la consulta y fíjate en el Transaction ID — un número aleatorio de 16 bits. Ahora mira la respuesta: tiene el mismo ID. Así se emparejan; DNS va normalmente sobre UDP, que no tiene conexión, así que la correspondencia hay que llevarla en el propio mensaje.
Dentro de la respuesta, despliega Answers: ahí están las direcciones IP
reales. Y observa el campo Time que Wireshark añade a la respuesta — te
dice cuánto tardó tu resolver. Eso convierte a Wireshark en una herramienta de
diagnóstico: un DNS lento se ve aquí de un vistazo.
Tipos de registro
El campo dns.qry.type dice qué se pregunta. Los que verás:
| Tipo | Nº | Devuelve | Nota para el analista |
|---|---|---|---|
| A | 1 | Una IPv4 | El caso normal. |
| AAAA | 28 | Una IPv6 | Los navegadores piden A y AAAA a la vez. |
| CNAME | 5 | Un alias hacia otro nombre | Encadena: el nombre real puede estar a varios saltos. |
| MX | 15 | Servidor de correo | Un equipo de escritorio no debería consultarlos a menudo. |
| TXT | 16 | Texto libre | Legítimo (SPF, verificaciones) pero es el registro preferido para sacar datos por DNS. |
| PTR | 12 | IP → nombre (inverso) | También lo usa mDNS para descubrir servicios en la red local. |
| NS | 2 | Servidor autoritativo del dominio | Frecuente en resolvers, raro en clientes. |
dns.qry.type == 16dns.flags.response == 0Solo las preguntas. Con == 1, solo las respuestas.
dns.qry.name contains "archlinux"dns.time > 0.5Resoluciones que tardaron más de medio segundo: el diagnóstico directo de «internet va lento» cuando la culpa es del DNS.
Cuando la respuesta es «no existe»
El código de respuesta va en dns.flags.rcode. El valor 0 es éxito; el 3 es
NXDOMAIN, «ese nombre no existe».
dns.flags.rcode == 3Algún NXDOMAIN suelto es normal: una errata al teclear, un dominio de búsqueda mal configurado. Un volumen alto y sostenido, no — y ahí empieza el interés defensivo.
Ciberseguridad: DNS es donde primero se ve casi todo
Aunque el contenido esté cifrado, el nombre que se resuelve casi nunca lo está. Por eso DNS es el registro más valioso en una investigación: te dice a dónde intentó ir un equipo, incluso si la conexión luego falló. Estos son los patrones que se miran, con lo que de verdad significa cada uno:
| Indicador | Por qué llama la atención | Explicación benigna frecuente |
|---|---|---|
| Muchos NXDOMAIN distintos | Un algoritmo que genera dominios va probando hasta acertar con el que está registrado | Sufijos de búsqueda mal configurados; un cliente de correo reintentando; antivirus con listas de reputación |
| Subdominios muy largos y aleatorios | Los datos se codifican en el propio nombre para sacarlos por DNS | CDN, antivirus en la nube y servicios de reputación usan nombres largos generados |
| Consultas a intervalos exactos | Un implante consultando a su servidor de control | Sincronización horaria, actualizaciones, telemetría, sondas de monitorización |
| Volumen alto de TXT | TXT admite más datos por respuesta que A | Validación de dominios, SPF/DKIM en servidores de correo |
| Resolver distinto del habitual | Un equipo salta el DNS corporativo y su registro | DoH del navegador activado por defecto; VPN; un móvil con su propia configuración |
Filtros para explorar cada uno:
dns.flags.rcode == 3 && dns.flags.response == 1dns.qry.name.len > 50dns && !(ip.dst == 10.2.3.1)Ese último saca las consultas DNS que no van a tu resolver habitual. Sustituye la IP por la de tu red.
Práctica. Abre Statistics → DNS sobre una captura de navegación normal. Mira el reparto por tipo de consulta y el de códigos de respuesta. Esa distribución es tu línea base de DNS: cuando algo se salga de ella, lo notarás.
DHCP
Cómo un equipo consigue una IP cuando todavía no tiene ninguna.
El problema. Un equipo que acaba de arrancar no tiene dirección IP,
así que no puede enviar un paquete dirigido a nadie. La solución es hablar en broadcast:
origen 0.0.0.0, destino 255.255.255.255, y que conteste quien
sepa.
DORA: los cuatro mensajes
- DDiscoverCliente → broadcast. «¿Hay algún servidor DHCP?»
- OOfferServidor → cliente. «Te ofrezco 10.2.3.170»
- RRequestCliente → broadcast. «Acepto esa». Va en broadcast para que los demás servidores retiren su oferta.
- AAcknowledgeServidor → cliente. «Confirmado, y aquí van máscara, gateway y DNS»
dhcpPara provocar un intercambio completo, renueva la concesión mientras capturas. En un sistema con NetworkManager basta con desconectar y reconectar la interfaz.
El tipo de mensaje va en la opción 53:
dhcp.option.dhcp == 1Discover. Los valores son 1=Discover, 2=Offer, 3=Request, 5=ACK, 6=NAK, 7=Release.
Qué mirar en un paquete DHCP
dhcp.hw.mac_addr— la MAC del cliente. Es lo que identifica al equipo en todo el intercambio.dhcp.option.hostname— el nombre que el equipo se da a sí mismo. En una red desconocida, filtrar DHCP y leer esta opción es la forma más rápida de saber qué dispositivos hay: los nombres suelen delatar el modelo y el dueño.dhcp.option.requested_ip_address— la IP que pide, normalmente la que tenía antes.- En el ACK, las opciones de router (gateway) y Domain Name Server: la configuración de red completa que va a usar el equipo.
dhcp.option.hostnameCiberseguridad: dos cosas que mirar
- Servidor DHCP inesperado. Si en tus capturas aparecen Offers desde una IP o una MAC que no es la de tu router, hay un segundo servidor DHCP en la red. Casi siempre es un accidente —alguien enchufó un router doméstico por el puerto equivocado—, pero un DHCP falso puede repartir un gateway y un DNS controlados por un tercero, y eso redirige todo el tráfico del que le haga caso.
- Inventario. DHCP es el mejor censo de una red: cada dispositivo que se conecta pasa por aquí, con su MAC y su nombre. Guarda esa lista; es la base para detectar el día que aparezca uno que no reconoces.
Práctica. Captura mientras reconectas la wifi, filtra dhcp
y localiza los cuatro mensajes. En el ACK, despliega las opciones y anota gateway y DNS:
compáralos con lo que devuelven ip route y resolvectl status.
Deben coincidir; si no coinciden, algo ha cambiado tu configuración después.
HTTP
Texto plano: todo lo que se ve, se ve porque nadie lo cifró.
HTTP es una conversación en texto sobre TCP. El cliente manda una petición, el servidor una respuesta, y ambas tienen la misma forma: una línea inicial, unas cabeceras, una línea en blanco y un cuerpo opcional.
http$ curl -s -o /dev/null http://neverssl.comLa petición
GET / HTTP/1.1
Host: neverssl.com
User-Agent: curl/8.x
Accept: */*- Método —
GETpide,POSTenvía datos en el cuerpo,HEADpide solo las cabeceras,PUTyDELETEmodifican recursos. - Host — obligatorio en HTTP/1.1. Permite alojar muchos sitios en una IP, y es el campo que te dice a qué sitio se pedía realmente.
- User-Agent — quién dice ser el cliente. Es texto libre y se puede poner cualquier cosa, pero delata la herramienta.
La respuesta
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 1256
...| Rango | Familia | Ejemplos |
|---|---|---|
| 2xx | Éxito | 200 OK · 204 sin contenido |
| 3xx | Redirección | 301 permanente · 302 temporal · 304 no modificado |
| 4xx | Error del cliente | 401 no autenticado · 403 prohibido · 404 no existe |
| 5xx | Error del servidor | 500 interno · 502 puerta de enlace · 503 no disponible |
http.requesthttp.request.method == "GET"http.response.code >= 400http.host contains "example"http.user_agentExtraer los ficheros que viajaron
File → Export Objects → HTTP lista todos los objetos que pasaron por la captura —páginas, imágenes, scripts, descargas— con su host, tamaño y tipo, y te los reconstruye en disco. En una investigación es la forma de recuperar exactamente qué se descargó.
Ciberseguridad: por qué HTTP sin cifrar es un problema
Con HTTP, cualquiera que esté en el camino ve la petición completa: la URL, las cabeceras, las cookies de sesión y el cuerpo del POST. No hace falta ninguna herramienta especial ni ningún ataque: está ahí, en claro, y Wireshark simplemente lo muestra.
Cosas concretas que quedan expuestas y por qué importan:
- La URL completa, incluidos parámetros. Si una aplicación pasa un identificador de sesión o un token en la query string, viaja visible.
- Las cookies (
http.cookie). Una cookie de sesión interceptada equivale a la sesión: por eso existe la marcaSecure. - El cuerpo de un POST (
http.file_data): el formulario tal cual se envió. - La cabecera Authorization (
http.authorization). En autenticación básica es el usuario y la contraseña, solo codificados en Base64 — que no es cifrado, es una forma de escribirlos.
http.authorizationhttp.request.method == "POST" && http.content_type contains "form"Indicadores de tráfico HTTP que merece revisar:
- User-Agent llamativo: vacío, muy corto, con errores de escritura, o de una herramienta que nadie debería estar usando en ese equipo. Recuerda que es texto libre: un agente que dice ser un navegador puede no serlo, y uno raro puede ser un dispositivo legítimo mal programado.
- Peticiones a una IP en vez de a un nombre. Un navegador humano
llega casi siempre por DNS; una petición a
http://203.0.113.9/algosin consulta DNS previa es, como mínimo, distinta del resto. - Métodos poco habituales en un cliente de escritorio: PUT, DELETE, o un CONNECT hacia un destino inesperado.
- La misma petición repetida a intervalos regulares, con respuestas pequeñas y casi idénticas. Es el patrón de beaconing, que tiene sección propia.
- Descargas de ejecutables por HTTP: mira los tipos en Export Objects.
http.user_agent matches "(?i)curl|wget|python|powershell"Error común. Filtrar http y concluir que no hay tráfico
web. Hoy casi todo es HTTPS, y con HTTPS no hay ningún paquete que Wireshark clasifique
como http: el disector solo ve TLS. Para ver el tráfico web real filtra
tls o tcp.port == 443. Y si una aplicación usa HTTP en un puerto
raro, clic derecho → Decode As… le dice a Wireshark que lo interprete
como HTTP.
HTTPS y TLS
Qué protege exactamente el cifrado — y qué sigue estando a la vista.
Objetivo: entender qué protege TLS exactamente y qué no.
tls$ curl -s -o /dev/null https://archlinux.orgAhora el Follow Stream devuelve ruido binario: el contenido está cifrado. Pero el
sobre no lo está. Selecciona el primer paquete, el Client Hello,
y despliega hasta las extensiones. Busca server_name:
tls.handshake.extensions_server_nameAhí está archlinux.org, en texto plano. Es el SNI: el cliente tiene que
decir a qué sitio se conecta antes de que exista el cifrado, porque una misma IP
aloja muchos dominios y el servidor necesita saber qué certificado enviar.
Así que un observador en la red ve: tu IP, la IP del servidor, el dominio (por SNI y por DNS), el momento, el volumen y el ritmo del tráfico. Lo que no ve es el contenido: qué páginas concretas, qué escribiste, qué te devolvieron.
Despliega también el Certificate en la respuesta del servidor — está sin cifrar y contiene el emisor, la validez y el nombre común. Es exactamente lo que tu navegador comprueba.
El handshake, mensaje a mensaje
El campo tls.handshake.type identifica cada paso:
| Tipo | Mensaje | Qué lleva y qué se ve |
|---|---|---|
| 1 | Client Hello | Versiones que acepta, cipher suites que soporta, y el SNI en claro. Su combinación concreta de opciones es tan característica del cliente que se usa como huella (JA3/JA4). |
| 2 | Server Hello | La versión y el cipher suite elegidos. A partir de aquí, en TLS 1.3, casi todo lo demás va cifrado. |
| 11 | Certificate | La cadena de certificados. En TLS 1.2 va en claro; en 1.3 va cifrada. |
| 16 | Client Key Exchange | Material para derivar la clave (solo TLS 1.2 y anteriores). |
tls.handshake.type == 1tls.handshake.type == 2tls.handshake.type == 11Distinguir la versión tiene truco: tls.record.version suele valer 1.2 por
compatibilidad incluso en conexiones 1.3. La versión real negociada está en la extensión
supported_versions del Server Hello. Si necesitas inventariar versiones de TLS,
fíjate en esa, no en la del registro.
tls.alert_messageLas alertas TLS marcan handshakes fallidos: certificado caducado, autoridad desconocida, no hay cipher suite en común. Es lo primero que hay que mirar cuando una aplicación «no conecta» y no da más detalle.
Ciberseguridad: analizar lo que no puedes leer
Que el contenido esté cifrado no deja al analista sin nada. Estos son los metadatos que siguen siendo válidos:
- El SNI — el destino real, aunque el contenido no se vea. Es el dato más valioso de una conexión TLS.
- El tamaño y el ritmo — una conexión que envía 200 bytes cada 60 segundos exactos tiene una forma reconocible aunque no sepas qué dice.
- La duración — conexiones muy largas y muy silenciosas destacan frente a la navegación normal.
- El cipher suite y la huella del Client Hello — dos programas distintos negocian TLS de forma distinta. Un cliente cuya huella no coincide con ningún navegador conocido, en un equipo donde solo debería haber navegadores, es una anomalía.
- Certificados llamativos (cuando son visibles): autofirmados, con validez muy corta, o con campos de organización claramente generados.
tls.handshake.extensions_server_name contains "duckdns"Ejemplo del método: buscar en el SNI proveedores de DNS dinámico, muy usados para infraestructura efímera. Sustituye la cadena por lo que estés investigando. Y recuerda que esos servicios también tienen usos completamente legítimos.
Wireshark a fondo
Las herramientas del programa que convierten una lista de paquetes en una investigación.
Follow Stream
Dejar de mirar paquetes sueltos y ver el diálogo.
Objetivo: dejar de mirar paquetes sueltos y ver el diálogo.
Un paquete aislado dice poco. Lo interesante es la conversación reensamblada. Con la captura de HTTP del ejercicio anterior todavía abierta, clic derecho en cualquier paquete de esa conexión → Follow → TCP Stream.
Se abre una ventana con el diálogo completo en texto: en un color lo que tú enviaste, en otro lo que respondió el servidor. Verás literalmente la petición HTTP:
GET / HTTP/1.1
Host: neverssl.com
User-Agent: curl/8.x
Accept: */*
HTTP/1.1 200 OK
Content-Type: text/html
...Eso es lo que significa que HTTP «no es seguro»: no hace falta ninguna herramienta
especial, está ahí en claro. Fíjate en que el User-Agent te identifica y el
Host dice qué sitio pides.
Al cerrar la ventana, Wireshark deja puesto un filtro tcp.stream eq N. Ese
número identifica la conexión dentro de la captura, y es una de las formas más rápidas de
moverse: cambia el número y saltas a otra conversación.
Prueba también File → Export Objects → HTTP: Wireshark lista todos los ficheros que viajaron por la captura (páginas, imágenes, scripts) y te los guarda en disco reconstruidos.
La ruta completa del menú
La entrada oficial es Analyze → Follow, y también está en el menú contextual de la lista de paquetes. El submenú ofrece un tipo de flujo por protocolo: TCP, UDP, DCCP, TLS, HTTP, HTTP/2, QUIC, WebSocket, SIP y USB CDC. Elegir el correcto importa:
- TCP Stream te da el flujo de bytes tal cual viajó, con las cabeceras HTTP incluidas.
- HTTP Stream aplica además la descompresión: si la respuesta venía
con
Content-Encoding: gzip, aquí la ves legible y en TCP Stream no. - TLS Stream muestra el contenido descifrado, y solo sirve si has configurado las claves como se explica más abajo.
El diálogo por dentro
Abajo del todo hay tres controles que se pasan por alto:
- Un desplegable de dirección: la conversación entera, solo cliente→servidor o solo servidor→cliente. Aislar un sentido es lo que hace legible una conversación larga.
- Show data as, con los formatos ASCII, C Arrays, EBCDIC, HEX Dump, UTF-8, UTF-16, YAML y Raw. Si ASCII se ve como basura, el contenido es binario: pasa a HEX Dump, que muestra offset, hexadecimal y texto a la vez.
- Un campo de búsqueda dentro del flujo, y los botones para navegar entre streams sin cerrar la ventana.
Limitaciones
- Solo reconstruye lo que capturaste. Si empezaste a capturar a mitad de la conexión, faltará el principio y Wireshark lo indicará.
- Necesita el flujo completo. Con paquetes perdidos, aparecen huecos.
- No descifra por sí solo. Sin claves, TLS es binario.
- Se carga en memoria. Seguir una descarga de dos gigabytes puede dejar el programa inutilizable un buen rato.
- El texto que ves es datos, no comandos. Un flujo puede contener cualquier cosa que el otro extremo haya querido enviar; trátalo como material a analizar.
El menú Statistics
Pasar del paquete al panorama. Aquí es donde se diagnostica de verdad.
Objetivo: pasar del paquete al panorama. Aquí es donde se diagnostica de verdad.
Captura treinta segundos de navegación normal, para y recorre el menú Statistics:
Protocol Hierarchy
Un desglose porcentual de todo lo capturado por protocolo. Es la primera parada ante una captura desconocida: en diez segundos sabes si esto es sobre todo TLS, o hay un torrente de UDP, o alguien está haciendo mucho DNS.
Conversations
Una fila por par de extremos, con bytes y duración. Ordena por la columna Bytes descendente y tienes al instante quién está consumiendo el ancho de banda. Clic derecho en una fila → Apply as Filter para bajar al detalle.
Endpoints
Lo mismo pero por dirección individual, no por pareja. La pestaña IPv4 tiene una casilla de resolución geográfica útil para ver adónde sale tu tráfico.
I/O Graph
Tráfico en el tiempo. Sirve para ver picos, cortes y patrones periódicos. Puedes añadir
varias líneas, cada una con su propio display filter — por ejemplo una con
tcp.analysis.retransmission superpuesta al total, y si las retransmisiones
suben cuando sube el tráfico, tienes congestión.
Expert Information
La lista de todo lo que Wireshark considera anómalo, clasificado por severidad. Retransmisiones, ACKs duplicados, ventanas a cero, conexiones reiniciadas. Ante «la red va lenta», este diálogo es el atajo.
Y el filtro de diagnóstico que más se usa:
tcp.analysis.flagsMuestra solo los paquetes que Wireshark ha marcado como problemáticos. En una red sana, apenas aparece nada.
Cómo se usan de verdad en una investigación
Cada diálogo responde a una pregunta distinta. En este orden:
Capture File Properties · ¿me puedo fiar de esta captura?
Antes que nada. Da el intervalo temporal cubierto, el número de paquetes y —lo
importante— cuántos se descartaron. Si hay descartes, cualquier
conclusión sobre pérdidas es sospechosa: puede que el problema fuera tu propio equipo
capturando. También tiene un campo de comentarios que se guarda dentro del
.pcapng: úsalo para anotar dónde y cuándo capturaste.
Protocol Hierarchy · ¿qué hay aquí dentro?
El árbol con el porcentaje de bytes de cada protocolo. Lo que hay que buscar no es un valor concreto sino lo que no encaja: un protocolo que no debería estar en ese segmento, un porcentaje de «Data» alto (tráfico que Wireshark no supo clasificar, a menudo por ir en puertos no estándar), o UDP dominando donde esperabas TCP. Clic derecho en cualquier fila → Apply as Filter para bajar al detalle.
Conversations · ¿quién habla con quién?
Una fila por par de extremos, con pestañas Ethernet, IPv4, IPv6, TCP y UDP. Tres columnas que se leen juntas: Bytes A→B y B→A (la asimetría cuenta la historia: descargar es normal, subir mucho no siempre), Duration y Bits/s.
Marca la casilla Limit to display filter para que el diálogo respete el filtro que tengas puesto. Sin ella verás la captura entera y te preguntarás por qué no cuadran los números.
Endpoints · ¿con cuántos sitios distintos?
Por dirección individual. La pestaña IPv4 admite resolución geográfica si tienes las bases de datos de MaxMind configuradas. Ordenar por número de paquetes revela al instante los destinos dominantes; ordenar por número de conversaciones revela a un equipo que habla con muchísimos sitios, que es la forma de un escaneo.
Packet Lengths · ¿qué forma tiene este tráfico?
Un histograma por rangos de tamaño. Es más útil de lo que parece porque cada tipo de tráfico tiene su perfil: la navegación mezcla paquetes pequeños (peticiones, ACK) con grandes (contenido). Un flujo compuesto casi solo de paquetes pequeños de tamaño casi idéntico no se parece a navegación humana — puede ser telemetría, una sesión interactiva o un canal de control.
I/O Graphs · ¿cuándo pasó?
El eje del tiempo. Añade una línea por filtro, ajusta el intervalo y compara. Con intervalos de un segundo ves ráfagas; con intervalos de un minuto ves patrones de fondo. Es la herramienta central para detectar periodicidad, y aparece otra vez en la sección de beaconing.
Flow Graph · ¿en qué orden?
Un diagrama de secuencia con el tiempo en vertical y los equipos en columnas. Limitado al flujo TCP que estés investigando, es la mejor forma de explicarle a otra persona qué pasó en una conexión: se ve el handshake, los datos y el cierre como una escalera.
Expert Information
La lista de todo lo que a Wireshark le ha parecido raro.
Se abre en Analyze → Expert Information, o pulsando el círculo de color de la esquina inferior izquierda. Agrupa los avisos por tipo, con el número de ocurrencias y un desplegable con los paquetes concretos.
| Nivel | Qué agrupa | Ejemplos |
|---|---|---|
| Error | Algo está mal formado o es inválido | Paquete malformado, checksum incorrecto |
| Warning | Comportamiento anómalo del protocolo | Conexión reiniciada, ventana a cero, ACK de segmento no visto |
| Note | Comportamiento normal pero digno de mención | Retransmisión, ACK duplicado, fuera de orden |
| Chat | Eventos normales del flujo | SYN, FIN, petición HTTP |
| Comment | Comentarios añadidos a paquetes | Anotaciones tuyas guardadas en el pcapng |
El desplegable Severity filtra la vista, y la casilla Limit to Display Filter restringe el análisis a lo que estés mirando — imprescindible en capturas grandes, donde la lista completa es inmanejable.
Cada línea tiene un menú contextual con Apply as Filter: de la lista agregada saltas directamente a los paquetes implicados.
Práctica. Abre Expert Information sobre una captura de tu navegación normal. Anota qué avisos aparecen y cuántos. Esa es tu línea base: la próxima vez que investigues algo, sabrás qué parte de la lista es simplemente cómo se comporta tu red.
Coloring rules
Que la captura te avise antes de que la mires con detalle.
Los colores de la lista de paquetes no son decorativos ni fijos: son una lista de reglas en View → Coloring Rules. Cada regla es un display filter con un color de fondo y otro de texto. Wireshark evalúa de arriba abajo y aplica la primera que coincide; el orden es, por tanto, la parte importante.
Las reglas de fábrica ya dicen bastante: negro sobre rojo es «Checksum Errors», rojo claro es «Bad TCP» (retransmisiones, ACK duplicados, resets), gris es tráfico de control TCP como SYN y FIN. Por eso «negro sobre rojo casi siempre significa problema».
Crear una regla propia
- Abre View → Coloring Rules.
- Pulsa +: aparece una regla nueva al principio de la lista.
- Ponle un nombre descriptivo, por ejemplo DNS lento.
- En el campo de filtro escribe la condición:
dns.time > 0.5. - Con la regla seleccionada, elige Background y Foreground.
- Arrástrala por encima de las reglas más generales, o nunca llegará a evaluarse.
- OK. La lista se recolorea al instante.
Un atajo que ahorra tiempo: clic derecho sobre un paquete → Colorize with Filter → New Coloring Rule… crea la regla con el filtro ya rellenado.
Un juego de reglas orientado a seguridad
Estas cinco, en este orden, hacen que las anomalías salten a la vista:
| Nombre | Filtro | Para qué |
|---|---|---|
| SYN sin respuesta | tcp.flags.syn == 1 && tcp.flags.ack == 0 | Aperturas de conexión: un escaneo se ve como una franja de color. |
| Conexión rechazada | tcp.flags.reset == 1 | Puertos cerrados y cortes abruptos. |
| DNS sin resolver | dns.flags.rcode == 3 | NXDOMAIN, para verlos agrupados. |
| Texto sin cifrar | http || ftp || telnet | Protocolos que exponen contenido. |
| Salida de la red | ip.src == 10.2.3.0/24 && !(ip.dst == 10.2.3.0/24) | Todo lo que abandona tu segmento. |
Las reglas se guardan en el perfil activo, en un fichero
colorfilters. Se pueden exportar e importar desde el mismo diálogo, que es
como se comparte un juego de reglas con un equipo.
Columnas propias
Ver el dato que importa sin abrir el árbol en cada paquete.
Las columnas por defecto son genéricas. Al investigar un protocolo concreto, poner ese campo en una columna cambia la forma de trabajar: puedes ordenar por él, compararlo entre paquetes de un vistazo y exportarlo a CSV.
La forma rápida
Selecciona el campo en el árbol → clic derecho → Apply as Column. Ya está. Para quitarla, clic derecho en su cabecera → Remove this Column.
La forma completa está en Edit → Preferences → Appearance → Columns, donde puedes reordenarlas, ocultarlas sin borrarlas y elegir el tipo (usa Custom y escribe el nombre del campo).
Columnas que merecen la pena
| Columna | Campo | Por qué ayuda |
|---|---|---|
| Puerto origen | tcp.srcport | Distinguir cliente de servidor de un vistazo. |
| Puerto destino | tcp.dstport | Ordenando por él, un escaneo de puertos se ve como una escalera. |
| Stream | tcp.stream | Saber a qué conexión pertenece cada paquete sin abrir el árbol. |
| Consulta DNS | dns.qry.name | Leer todos los dominios consultados como una lista. |
| Host HTTP | http.host | Igual, para peticiones web sin cifrar. |
| SNI | tls.handshake.extensions_server_name | El destino real de cada conexión HTTPS. La columna más útil hoy. |
| TTL | ip.ttl | Agrupar orígenes y detectar incoherencias. |
| Delta de conexión | tcp.time_delta | Medir periodicidad dentro de una misma conexión. |
Con las columnas puestas, File → Export Packet Dissections → As CSV exporta exactamente esas columnas de los paquetes mostrados. Es la forma de llevar un hallazgo a una hoja de cálculo o a un informe.
Perfiles
Un Wireshark distinto para cada tipo de trabajo.
Un perfil es un conjunto completo de configuración: columnas, reglas de coloreado, filtros guardados, preferencias de disectores y diseño de paneles. Wireshark guarda cada uno en su propio directorio y se cambia entre ellos al instante.
La razón de usarlos es práctica: la configuración que quieres para diagnosticar una red lenta no es la que quieres para investigar un incidente. En vez de reconfigurar cada vez, cambias de perfil.
Crear uno
- Abre Edit → Configuration Profiles (o pulsa la esquina inferior derecha de la barra de estado, donde pone el perfil actual).
- Pulsa + y ponle nombre, por ejemplo Cybersecurity.
- Con el perfil ya activo, añade las columnas de la sección anterior.
- Añade las reglas de coloreado de la sección de coloring rules.
- Guarda como botón los filtros que más repitas, con el + de la barra de filtros.
- Ajusta Preferences → Protocols → TCP para activar los timestamps de conversación.
Para partir de una copia de otro perfil en vez de empezar en blanco, selecciónalo y usa el botón de copiar del mismo diálogo.
Los perfiles viven en el directorio personal de configuración, dentro de
profiles/. Puedes verlo desde Help → About Wireshark →
Folders, que te da la ruta exacta en tu sistema. Copiar esa carpeta a otro equipo
lleva el perfil entero con él.
Descifrar tu propio TLS
Ver HTTPS en claro usando las claves de tu propio navegador, en tu propio laboratorio.
Objetivo: ver HTTPS en claro usando las claves de tu propio navegador.
No es un ataque: es que el navegador te presta sus claves de sesión porque tú se lo
pides. Firefox y Chrome escriben las claves efímeras en un fichero si defines
SSLKEYLOGFILE, y Wireshark sabe leerlo.
$ export SSLKEYLOGFILE=~/tls-keys.log
$ firefox --new-instanceFirefox tiene que arrancar desde esa misma terminal para heredar la variable; si ya estaba abierto, ciérralo del todo antes. Luego, en Wireshark:
Edit → Preferences → Protocols → TLS
→ (Pre)-Master-Secret log filename: /home/lucio/tls-keys.logEmpieza la captura, navega a cualquier sitio HTTPS, y filtra por http2.
Los paquetes que antes eran «Application Data» ilegible ahora aparecen desmontados:
cabeceras, cookies, JSON, todo. Follow → HTTP/2 Stream lo muestra en texto.
Por qué esto funciona
Merece entenderse, porque explica a la vez el alcance y el límite de la técnica.
TLS moderno usa intercambio de claves con secreto hacia adelante: las claves que cifran la sesión se generan al vuelo para esa conexión y no se derivan de la clave privada del servidor. Por eso, ni siquiera teniendo la clave privada del servidor se puede descifrar una sesión TLS 1.3 grabada.
Lo que sí existe es el material de la sesión, dentro de la memoria del cliente. El
navegador, si le pides que colabore, lo escribe en el fichero de
SSLKEYLOGFILE. Wireshark lee ese fichero y descifra. Es decir: funciona porque
uno de los dos extremos de la conversación —tú— coopera voluntariamente.
De ahí se sigue lo importante:
- Solo descifra las conexiones cuyas claves están en tu fichero, es decir, las que hizo tu navegador mientras la variable estaba puesta.
- No hay forma de obtener las claves de otra persona con esta técnica. No es una debilidad de TLS: es una función de depuración.
- Si capturaste antes de arrancar el navegador con la variable, esas conexiones no se descifrarán nunca.
Riesgos del fichero de claves
- Mientras la variable esté activa, todas tus sesiones TLS quedan descifrables por quien tenga el fichero y la captura. Incluidas las que no pretendías analizar: correo, banca, sesiones de trabajo.
- Un
.pcapngpuede llevar las claves dentro, si usas File → Export Packet Dissections o incrustas el secrets block. Cómodo para compartir un caso con un compañero; catastrófico si ese fichero acaba donde no debe. - Ponlo en la variable solo en la terminal donde lo necesites; jamás en
.bashrc,.profileni en el entorno del escritorio. - Bórralo al terminar, y borra también las capturas de laboratorio que ya no necesites.
tshark
Lo mismo sin ventana: servidores, scripts y sesiones SSH.
Objetivo: capturar en servidores, en scripts y en sesiones SSH.
tshark es el mismo motor sin GUI, con los mismos display filters. Captura
diez paquetes DNS y muéstralos:
$ tshark -i wlan0 -c 10 -f "port 53"Fíjate en -f: es el capture filter (sintaxis BPF). El display
filter va con -Y:
$ tshark -i wlan0 -Y "dns.flags.response == 0"Lo más potente es extraer campos concretos en columnas, listo para sort o
awk:
$ tshark -i wlan0 -Y dns -T fields \
-e frame.time_relative -e ip.src -e dns.qry.nameEl flujo de trabajo habitual es capturar sin interfaz y analizar con la GUI:
# capturar 60 s a fichero
$ tshark -i wlan0 -a duration:60 -w ~/captura.pcapng
# abrirlo en la GUI
$ wireshark ~/captura.pcapngEl formato .pcapng es estándar: lo lee cualquier herramienta de análisis,
y es lo que te pasarán si alguien te pide ayuda con un problema de red. Guardar la captura
(Ctrl+S) es parte del trabajo, no un extra.
Recetas que resuelven preguntas reales
Aquí es donde tshark supera a la interfaz: contar, agrupar y ordenar.
Los veinte dominios más consultados
$ tshark -r captura.pcapng -Y "dns.flags.response == 0" \
-T fields -e dns.qry.name | sort | uniq -c | sort -rn | head -20La primera pregunta de casi cualquier investigación. Si un dominio desconocido aparece cientos de veces, ya tienes por dónde empezar.
Todos los destinos HTTPS, por nombre
$ tshark -r captura.pcapng -Y "tls.handshake.type == 1" \
-T fields -e tls.handshake.extensions_server_name | sort -uQuién habla con quién y cuánto
$ tshark -r captura.pcapng -q -z conv,tcpLa misma tabla que Statistics → Conversations, en texto. -q silencia el
volcado de paquetes y -z pide una estadística. Otras útiles:
-z io,phs (jerarquía de protocolos) y -z endpoints,ip.
Intervalos entre conexiones, para medir periodicidad
$ tshark -r captura.pcapng \
-Y "tcp.flags.syn == 1 && tcp.flags.ack == 0 && ip.dst == 203.0.113.9" \
-T fields -e frame.time_epoch \
| awk 'NR>1 {printf "%.1f\n", $1-prev} {prev=$1}'Imprime el hueco en segundos entre cada intento de conexión. Si la columna es casi constante, tienes periodicidad — el indicador central de la sección de beaconing.
Cortar una captura enorme
# quedarse solo con un equipo
$ tshark -r grande.pcapng -Y "ip.addr == 10.2.3.170" -w recorte.pcapngTrabajar sobre un recorte es más rápido y, si vas a compartirlo, expone mucho menos.
PCAP y su custodia
El formato de las capturas, y por qué un fichero de estos es información sensible.
Hay dos formatos y conviene distinguirlos:
| Formato | Características |
|---|---|
| .pcap | El clásico. Una sola interfaz, marcas de tiempo con precisión de microsegundo, sin metadatos. Máxima compatibilidad con herramientas antiguas. |
| .pcapng | El actual, y el que Wireshark usa por defecto. Varias interfaces en un fichero, nanosegundos, comentarios por paquete, metadatos del equipo que capturó y bloques de secretos. |
Trabajar sobre ficheros en lugar de capturar en vivo es lo normal en análisis: es repetible, se puede compartir, y no te obliga a estar delante cuando ocurre el problema.
Operaciones habituales
- Abrir: File → Open, o
wireshark fichero.pcapng. - Guardar solo lo filtrado: File → Export Specified Packets…, con la opción All packets / Displayed. Es la forma correcta de reducir una captura a lo relevante.
- Anotar: clic derecho en un paquete → Packet Comment….
El comentario se guarda dentro del
.pcapngy aparece en Expert Information. Es la manera de dejar dicho por qué ese paquete importa. - Unir o dividir: las herramientas de línea de comandos
mergecapyeditcap. Por ejemplo, trocear por tiempo:
# dividir en trozos de 60 segundos
$ editcap -i 60 grande.pcapng trozo.pcapngUn PCAP es información sensible
Reglas prácticas para manejarlos:
- Captura lo mínimo necesario. Un capture filter bien puesto es también una medida de protección de datos: lo que no capturas no puede filtrarse.
- Recorta antes de compartir. Export Specified Packets con solo la conversación relevante.
- Anonimiza si el destinatario no necesita las direcciones. Existen herramientas específicas de sanitizado de PCAP; ten en cuenta que anonimizar bien es más difícil de lo que parece, porque los identificadores aparecen en muchos sitios a la vez.
- Para aprender, usa capturas públicas de laboratorio en lugar de tráfico real de una organización.
- Trátalos como evidencia si lo son: calcula el hash al obtenerlos, guarda dónde y cuándo se capturaron, y no trabajes sobre el original sino sobre una copia.
- Bórralos cuando ya no hagan falta. Una carpeta de capturas viejas es un problema esperando a ocurrir.
Ciberseguridad
Análisis defensivo: reconocer, investigar y documentar. Nada de esta parte enseña a atacar.
Wireshark para análisis defensivo
Qué se puede y qué no se puede concluir mirando tráfico.
Todo lo que viene ahora está escrito desde el lado del defensor: alguien que tiene una captura de una red que administra o que está autorizado a analizar, y que necesita responder «¿esto es normal?».
Wireshark no es un IDS. No tiene firmas, no puntúa amenazas, no avisa. Lo que aporta es la máxima resolución posible: el paquete exacto, con todos sus campos. Por eso es la herramienta de la fase de confirmación, no la de detección. El camino típico es: una alerta llega de otro sitio → se recupera la captura → Wireshark responde qué pasó exactamente.
Las tres preguntas que ordenan cualquier análisis
- ¿Qué veo? Hechos observables en la captura. «El equipo 10.2.3.55 abrió 40 conexiones al puerto 443 de 203.0.113.9 en diez minutos.» Esto no se discute: está en el fichero.
- ¿Qué significa? Interpretación, que depende del contexto. «Cuarenta conexiones en diez minutos a intervalos casi constantes no se parecen a navegación humana.»
- ¿Qué no puedo saber desde aquí? El límite. «No sé qué se envió, porque va cifrado. No sé si ese destino es legítimo. No sé si el proceso que lo generó es malicioso.»
Lo que una captura no te va a decir
- Qué proceso lo generó. La captura ve puertos, no programas. Eso se
responde en el equipo, con
ss -tanpo el registro del sistema. - Quién estaba delante. Una IP identifica un equipo, y solo mientras dure la concesión DHCP.
- El contenido cifrado. Salvo que sea tu propio tráfico y tengas las claves.
- Qué pasó fuera de la ventana capturada.
- Si el destino es malicioso. Eso es inteligencia externa, no análisis de paquetes.
Reconocer estos límites en voz alta es lo que distingue un análisis serio. Las secciones que siguen dan indicadores concretos; ninguno es una conclusión por sí mismo.
Línea base
Para reconocer el tráfico malo primero hay que conocer el normal.
Este es el consejo más importante de toda esta parte, y el que más se ignora. Sin una referencia de cómo se comporta tu red cuando no pasa nada, cualquier captura parece sospechosa: verás retransmisiones, dominios que no reconoces, conexiones a nubes de medio mundo. Y casi todo será normal.
La solución es barata: dedica una tarde a capturar tu red funcionando bien y anota qué hay. Ese documento vale más que cualquier lista de filtros.
Qué apuntar
| Dimensión | Dónde se mira | Qué anotar |
|---|---|---|
| Equipos | Statistics → Endpoints (IPv4 y Ethernet) | Qué IP y qué MAC existen; cuál es el gateway. |
| Protocolos | Statistics → Protocol Hierarchy | Reparto porcentual habitual. Qué protocolos aparecen y cuáles no. |
| Destinos | Columna SNI + consultas DNS | Los veinte o treinta dominios recurrentes. |
| Puertos | Statistics → Conversations → TCP/UDP | Qué puertos de destino son normales aquí. |
| Volumen | Statistics → I/O Graphs | Tráfico típico por minuto, y la forma de las horas punta. |
| Periodicidad | I/O Graphs con intervalo largo | Qué cosas ya laten solas: actualizaciones, NTP, monitorización. |
| Anomalías normales | Analyze → Expert Information | Cuántas retransmisiones y ACK duplicados hay de normal. |
Ese último punto es el que más disgustos ahorra: si tu wifi genera de normal un 2 % de retransmisiones, encontrarlas durante un incidente no significa nada.
# línea base de destinos: los 30 dominios más consultados
$ tshark -r baseline.pcapng -Y "dns.flags.response == 0" \
-T fields -e dns.qry.name | sort | uniq -c | sort -rn | head -30 \
> baseline-dominios.txtGuarda ese fichero. La próxima vez, genera el mismo listado sobre la captura nueva y
compáralos con comm o diff: lo que aparece y no estaba es tu
lista de candidatos a investigar. Es una técnica sencilla y sorprendentemente eficaz.
Escaneo de puertos
Cómo se ve desde el lado del que lo recibe.
Qué es. Alguien quiere saber qué servicios tiene un equipo, así que intenta abrir conexiones a muchos puertos y observa qué contesta cada uno. No es en sí un ataque: es reconocimiento. Pero rara vez hay una razón legítima para que un equipo de tu red escanee a otro sin que tú lo sepas.
Qué rastro deja. La firma no está en ningún paquete individual —cada SYN es un SYN perfectamente normal— sino en la forma del conjunto:
- Muchos SYN desde un mismo origen.
- Hacia muchos puertos distintos (escaneo de puertos) o muchas IP distintas (barrido de red).
- En una ventana de tiempo corta.
- Con pocos handshakes completos: la mayoría acaba en RST (puerto cerrado) o sin respuesta (filtrado).
- A menudo con puertos de destino secuenciales o siguiendo una lista conocida de servicios.
Cómo se investiga
- Aísla las aperturas de conexión:
tcp.flags.syn == 1 && tcp.flags.ack == 0. Mira el contador Displayed: si es un número grande respecto al total, ya es un dato. - Abre Statistics → Conversations con Limit to display filter marcado y ve a la pestaña TCP. Ordena por origen. Un escaneo se ve como cientos de filas con la misma IP A y puertos B distintos, cada una con muy pocos paquetes.
- Añade
tcp.dstportcomo columna y ordena por ella: si los puertos suben en escalera, la forma es inconfundible. - Comprueba qué contestó:
tcp.flags.reset == 1son puertos cerrados que respondieron. Los que no aparecen es que no contestaron nada. - Busca los que sí se completaron: esos son los servicios que el escaneo encontró abiertos, y son el foco de lo que venga después.
- Mira el I/O Graph con la vista filtrada por los SYN: un escaneo produce un pico compacto, no una curva suave.
tcp.flags.syn == 1 && tcp.flags.ack == 0tcp.flags.reset == 1 && tcp.flags.ack == 1tcp.completeness < 7Este último aprovecha un campo que Wireshark calcula por conexión: marca las conexiones que no llegaron a completarse. Muchas conexiones incompletas desde un mismo origen es exactamente el patrón.
¿Qué distingue un escaneo de una aplicación con problemas?
Una aplicación que reintenta conectar contra un servicio caído también genera muchos SYN sin respuesta. Se distinguen por tres cosas:
- Variedad de destino. La aplicación insiste contra el mismo puerto e IP; el escaneo recorre muchos.
- Retransmisiones. El reintento legítimo de TCP retransmite el mismo
SYN con intervalos que se van doblando (1 s, 2 s, 4 s…), y Wireshark lo marca como
tcp.analysis.retransmission. Un escáner no espera: lanza y sigue. - Puerto origen. Los reintentos de una misma conexión conservan el puerto origen; un escaneo usa uno nuevo por cada intento.
Beaconing
El latido: conexiones regulares hacia un mismo destino.
Qué es. Un programa que se comunica periódicamente con un servidor para preguntar si hay órdenes. Es el patrón de comunicación de la mayoría del software de control remoto — el legítimo y el que no lo es. Lo que lo hace detectable es que un programa es regular de un modo en que una persona no lo es.
Beaconing · intervalo constante, transferencia mínima
Navegación humana · ráfagas irregulares y silencios largos
Qué rastro deja:
- Intervalo casi constante entre conexiones al mismo destino.
- Transferencias pequeñas y de tamaño parecido — la mayoría de las veces la respuesta es «no hay nada para ti».
- Persistencia en el tiempo, incluso fuera de horario laboral, cuando nadie está usando el equipo.
- Un solo destino, o unos pocos, repetidos.
Cómo se mide la periodicidad
- Localiza al candidato en Statistics → Conversations: ordena por número de paquetes o de conexiones hacia un mismo destino externo.
- Filtra esa pareja:
ip.addr == 10.2.3.55 && ip.addr == 203.0.113.9. - Quédate solo con los inicios de conexión, que es lo que marca el ritmo: añade
&& tcp.flags.syn == 1 && tcp.flags.ack == 0. - Cambia View → Time Display Format a Seconds Since Previous Displayed Packet. La columna Time pasa a ser directamente el intervalo.
- Mira esa columna: si los valores rondan siempre el mismo número, tienes periodicidad.
- Confírmalo visualmente en Statistics → I/O Graphs, con una línea para ese filtro y un intervalo de 1 segundo: el beaconing se dibuja como un peine regular.
Y la forma rápida, en terminal, sobre una captura ya guardada:
$ tshark -r captura.pcapng \
-Y "ip.dst == 203.0.113.9 && tcp.flags.syn == 1 && tcp.flags.ack == 0" \
-T fields -e frame.time_epoch \
| awk 'NR>1 {printf "%.1f\n", $1-prev} {prev=$1}' \
| sort -n | uniq -cSi la salida se concentra en uno o dos valores, el intervalo es fijo. Si está repartida por todas partes, es tráfico irregular — probablemente humano.
El jitter
El software de control moderno introduce una variación aleatoria deliberada en el intervalo, precisamente para no dibujar un peine perfecto. Un beacon de 60 segundos con un 20 % de jitter aparecerá entre 48 y 72. Sigue siendo detectable: la distribución continúa siendo estrecha comparada con la de un humano, que salta de dos segundos a media hora.
Por eso conviene mirar la dispersión, no solo la media. Con la columna de deltas exportada a CSV y una hoja de cálculo, la desviación típica dividida entre la media da un número: cuanto más cerca de cero, más regular.
DNS sospechoso
Checklist defensivo sobre el protocolo que más cuenta.
La sección de DNS ya explicó los indicadores. Aquí van convertidos en un procedimiento que puedes ejecutar sobre cualquier captura.
Checklist
| # | Comprobación | Filtro o herramienta |
|---|---|---|
| 1 | ¿Cuántas consultas hay y a qué resolver van? | dns.flags.response == 0 |
| 2 | ¿Alguien consulta a un resolver distinto del corporativo? | dns && !(ip.dst == 10.2.3.1) |
| 3 | ¿Qué proporción de NXDOMAIN hay? | dns.flags.rcode == 3 |
| 4 | ¿Hay nombres anormalmente largos? | dns.qry.name.len > 50 |
| 5 | ¿Hay consultas TXT desde equipos de escritorio? | dns.qry.type == 16 |
| 6 | ¿Hay un dominio consultado con una frecuencia rara? | tshark + uniq -c |
| 7 | ¿Hay muchos subdominios distintos de un mismo dominio padre? | Ordenar la lista de nombres |
| 8 | ¿Aparece algún dominio que no esté en tu línea base? | comm contra el fichero base |
El punto 7 merece explicación porque es el más característico. Sacar datos por DNS obliga a codificarlos en el nombre consultado, y como cada consulta lleva pocos bytes, hacen falta muchas. El resultado es un mismo dominio padre con cientos o miles de subdominios distintos, cada uno consultado una sola vez.
# subdominios distintos por dominio padre
$ tshark -r captura.pcapng -Y "dns.flags.response == 0" \
-T fields -e dns.qry.name \
| awk -F. '{print $(NF-1)"."$NF}' | sort | uniq -c | sort -rn | headUn dominio con 3 000 consultas y 3 000 nombres distintos tiene una forma muy diferente de uno con 3 000 consultas al mismo nombre. El primero merece una mirada; el segundo es probablemente una caché mal configurada.
Qué explicaciones benignas hay que descartar primero
- Antivirus y reputación en la nube. Consultan nombres generados a partir del hash de lo que analizan. Producen exactamente el patrón de «muchos subdominios largos y únicos».
- Redes de distribución de contenido. Generan nombres largos y aparentemente aleatorios.
- Sufijos de búsqueda. Un dominio de búsqueda mal configurado hace que cada nombre se intente varias veces, multiplicando los NXDOMAIN.
- mDNS. El descubrimiento de impresoras y altavoces en la red local genera mucho tráfico con aspecto extraño en el puerto 5353. Es normal.
- DoH del navegador. Explica que un equipo «no consulte» al resolver corporativo: sus consultas van cifradas dentro de HTTPS y no las verás como DNS.
Si ninguna de estas explica lo que ves, y el equipo no debería estar haciendo eso, entonces tienes un hallazgo que documentar — todavía no una conclusión.
ARP anómalo
Ejercicio defensivo sobre el protocolo sin autenticación.
La sección de ARP explicó el mecanismo. Aquí está el procedimiento para revisar una captura buscando inconsistencias, y —lo más importante— qué hacer con lo que encuentres.
- Filtra
arpy abre Statistics → Conversations → Ethernet: obtienes las parejas de MAC que han hablado. - Aplica
arp.duplicate-address-detected. Si no hay nada, la captura no muestra conflictos y puedes pasar a otra cosa. - Si hay algo, abre uno de esos paquetes: Wireshark te dice en
arp.duplicate-address-framecon qué trama anterior choca. Compara ambas. - Anota las dos MAC y la IP en disputa. Mira el fabricante que resuelve Wireshark para cada MAC: ¿son coherentes con dispositivos que existen en tu red?
- Comprueba si la IP en disputa es el gateway. Si lo es, sube la prioridad: es el objetivo con más valor.
- Mira la línea temporal: ¿fue un instante durante un cambio de red, o es persistente y se repite?
- Contrasta con tu tabla ARP local (
ip neigh) y con la tabla de direcciones MAC del switch, si tienes acceso.
arp.duplicate-address-detectedarp.opcode == 2 && arp.src.proto_ipv4 == 10.2.3.1Ese segundo filtro muestra todas las respuestas que afirman ser el gateway. En una red
sana, todas traerán la misma MAC de origen. Añade la columna arp.src.hw_mac
y compruébalo de un vistazo.
Defensas que se aplican después, y que no dependen de Wireshark: entradas ARP estáticas para el gateway en equipos críticos, inspección dinámica de ARP en switches gestionados, y segmentación para reducir cuántos equipos comparten un dominio de difusión.
Transferencias de salida inusuales
Detectar que salen datos, desde el lado del que vigila.
Qué se busca. Volumen de datos saliendo de la red hacia un destino que no corresponde. La detección es puramente estadística: no hace falta ver el contenido, solo medir cuánto sale, hacia dónde y cuándo.
El indicador central: la asimetría. La navegación normal es asimétrica en el sentido contrario — descargas mucho más de lo que subes. Una conversación donde el equipo interno envía mucho más de lo que recibe invierte el patrón habitual, y eso es lo que llama la atención.
Procedimiento
- Abre Statistics → Conversations, pestaña IPv4.
- Ordena por Bytes A→B descendente, asegurándote de qué lado es el interno (la columna A es la que aparece primero en la fila).
- Compara las columnas A→B y B→A de las primeras filas. Busca las que envían mucho más de lo que reciben.
- Descarta los destinos conocidos de tu línea base: copias de seguridad, sincronización de ficheros, subida de registros.
- De los que quedan, mira Duration y la hora de inicio. ¿Ocurrió cuando alguien estaba trabajando?
- Filtra esa pareja y mira el I/O Graph: ¿fue un bloque continuo o goteo constante durante horas?
- Comprueba el protocolo y el puerto. ¿Encaja con lo que ese equipo debería hacer?
- Si hay DNS previo, busca qué nombre resolvió esa IP:
dns.a == 203.0.113.9.
ip.src == 10.2.3.0/24 && !(ip.dst == 10.2.3.0/24)Todo lo que abandona tu red. Con este filtro puesto y Limit to display filter marcado en Conversations, las cifras que veas son exclusivamente de salida.
dns.a == 203.0.113.9Qué nombre de dominio resolvió a esa IP. Es la forma de convertir una dirección anónima en un destino con nombre, usando la propia captura en lugar de consultas externas que avisarían al otro lado.
Otros indicadores
- Horario. Transferencias grandes fuera de la jornada, cuando el equipo debería estar inactivo.
- Destino desconocido. Una IP o un dominio que no aparece en la línea base, en un proveedor de nube que la organización no usa.
- Protocolo impropio. Un volumen alto por un protocolo que no está hecho para transportar datos: DNS, ICMP, o un puerto TCP no habitual en ese equipo.
- Continuidad. Una sesión larga a ritmo constante encaja peor con trabajo humano que un pico y una pausa.
- Puerto no estándar con protocolo estándar dentro, o al revés: Protocol Hierarchy con mucho «Data» sin clasificar es una pista.
Y el límite honesto: si el tráfico va cifrado —lo normal—, la captura te dice cuánto salió y hacia dónde, nunca qué. Determinar qué se llevaron exige el equipo de origen: registros de aplicación, auditoría de ficheros, herramientas de detección en el endpoint. Wireshark aporta la mitad de la respuesta, y hay que decirlo así en el informe.
Tráfico HTTP sospechoso
Qué revisar en el poco tráfico web sin cifrar que queda.
Que casi todo sea HTTPS hace que el HTTP restante sea, precisamente por eso, interesante: dispositivos antiguos, aparatos empotrados, portales cautivos... y programas que no se molestan en cifrar.
Qué revisar, en orden
| Qué | Filtro | Qué buscas |
|---|---|---|
| Inventario de destinos | http.request | Añade http.host como columna. ¿Reconoces todos? |
| Agentes de usuario | http.user_agent | Vacíos, con erratas, o de herramientas que ahí no pintan nada. |
| Peticiones a IP directa | http.host matches "^[0-9.]+$" | Sin resolución DNS previa: poco propio de un navegador. |
| Métodos poco comunes | http.request.method != "GET" && http.request.method != "POST" | PUT, DELETE, CONNECT donde no se esperan. |
| Errores repetidos | http.response.code >= 400 | Muchos 404 seguidos: alguien probando rutas. |
| Descargas | File → Export Objects → HTTP | Tipos de fichero ejecutables o comprimidos. |
| Repetición regular | http.request.uri contains "/api" | La misma petición cada N segundos: ver la sección de beaconing. |
http.user_agent matches "(?i)curl|wget|python|powershell"Credenciales en texto claro
Por qué los protocolos sin cifrar son un riesgo, demostrado con datos ficticios.
Algunos protocolos veteranos transmiten la autenticación sin ninguna protección. No es un fallo de implementación: se diseñaron cuando la red era un entorno de confianza.
| Protocolo | Qué expone | Alternativa |
|---|---|---|
| Telnet | La sesión entera, incluida la contraseña tecleada carácter a carácter | SSH |
| FTP | Usuario y contraseña en los comandos USER y PASS | SFTP o FTPS |
| HTTP básico | Usuario y contraseña en Base64, que no es cifrado | HTTPS |
| SNMPv1/v2c | La community string, que funciona como contraseña | SNMPv3 |
| POP3 / IMAP sin TLS | Credenciales de correo | Sus variantes sobre TLS |
Demostración de laboratorio
Así se ve un inicio de sesión FTP en un Follow TCP Stream. Los datos son ficticios y el servidor, uno de laboratorio propio:
220 Servidor FTP de laboratorio
USER usuario_demo
331 Please specify the password.
PASS password_demo
230 Login successful.No hay ninguna técnica detrás: es Follow TCP Stream sobre una conexión FTP. El protocolo envía esas dos líneas tal cual.
ftp.request.command == "PASS"ftp || telnethttp.authorizationResets, retransmisiones y cómo no equivocarse
Los hallazgos que más veces se malinterpretan.
Un RST o una retransmisión no dicen por sí solos qué ha pasado. Dicen que algo interrumpió el flujo esperado. La causa hay que deducirla del contexto, y hay varias posibles con firmas distintas.
Un RST: cuatro explicaciones
| Causa | Cómo se distingue |
|---|---|
| Puerto cerrado | El RST responde inmediatamente a un SYN. Nunca hubo conexión. Es la respuesta correcta del sistema operativo. |
| La aplicación cerró de golpe | Hubo handshake y datos, y luego RST en vez de FIN. El programa terminó sin cerrar bien; muy común y no indica nada malo. |
| Un intermediario cortó | RST a mitad de una sesión sana, a menudo desde los dos lados o con un TTL que no encaja con el del resto de la conversación. Cortafuegos o proxy. |
| Tiempo de espera agotado | RST después de un silencio largo. Un equipo de red descartó el estado de una conexión ociosa. |
El truco del TTL es el más útil de la tabla: si todos los paquetes del servidor llegan con TTL 51 y de pronto aparece un RST «del servidor» con TTL 64, ese RST no lo envió el servidor. Lo envió algo mucho más cercano.
tcp.flags.reset == 1Retransmisiones: qué las causa de verdad
- Pérdida real en la red. Congestión, enlace saturado, wifi con interferencias. Suele venir con ACK duplicados y afecta a varias conversaciones a la vez.
- Pérdida solo en tu captura. Tu equipo no dio abasto y
dumpcapdescartó paquetes. Wireshark ve un hueco y lo marca. La red estaba perfectamente. - Punto de observación. Capturando en el cliente ves lo que le llegó al cliente; el paquete pudo llegar bien al servidor.
- Reordenación. Marcado como out-of-order, no como pérdida. Es benigno.
- Comprueba primero Statistics → Capture File Properties: si hay paquetes descartados, sospecha de tu propia captura antes que de la red.
- Mira si el problema afecta a una sola conversación o a todas. Una sola apunta a ese servidor o esa ruta; todas apuntan al enlace local.
- Compara el porcentaje con tu línea base. En wifi, un pequeño porcentaje de retransmisiones es normal.
- Mira si hay
tcp.analysis.zero_window: si lo hay, el cuello de botella es un extremo saturado, no la red. - Superpón en el I/O Graph el tráfico total y las retransmisiones. Si suben juntas, es congestión.
Flujo de análisis en diez preguntas
El procedimiento que aplicar a cualquier captura, en este orden.
Cuando llega una captura y hay que decir algo sobre ella, el error es empezar a mirar paquetes al azar. Esta secuencia va de lo general a lo concreto y evita perderse.
-
¿Quién habla?
Statistics → Endpoints
Inventario de equipos que aparecen. ¿Reconoces todas las direcciones? ¿Hay alguna que no debería estar en este segmento?
-
¿Con quién?
Statistics → Conversations
Parejas y volumen. Ordena por bytes y por número de paquetes. Los extremos de la lista son siempre lo más informativo.
-
¿Qué protocolo?
Statistics → Protocol Hierarchy
Reparto por protocolo. Busca lo que no debería estar, y el porcentaje de tráfico sin clasificar.
-
¿Cuándo?
Columna Time · Capture File Properties
Ventana temporal cubierta y a qué hora ocurrió lo interesante. Pon el formato de hora absoluta para poder correlacionar con otros registros.
-
¿Con qué frecuencia?
I/O Graphs · delta de tiempo
¿Es un evento único, una ráfaga o un latido regular? Cambia la escala del gráfico: lo que a un segundo parece ruido, a un minuto puede ser un patrón.
-
¿Cuánto tráfico?
Conversations · bytes A→B y B→A
Volumen y sobre todo dirección. La asimetría cuenta más que el total.
-
¿Qué contenido?
Follow Stream · Export Objects
Si está en claro, léelo. Si va cifrado, quédate con los metadatos: SNI, tamaños, tiempos. Y dilo explícitamente en el informe.
-
¿Es normal?
Tu línea base
La pregunta que da sentido a las siete anteriores. Sin referencia, todo parece sospechoso y nada lo es.
-
¿Qué evidencia tengo?
Números de trama · marcas de tiempo · hash del fichero
Anota tramas concretas, no impresiones. Otra persona debe poder abrir la misma captura y ver lo mismo.
-
¿Qué hipótesis tengo?
Escrito aparte de la evidencia
Formúlala como hipótesis, con lo que la apoya y lo que la contradice. Y anota qué haría falta para confirmarla, porque casi nunca está en la captura.
Mini informe de incidente
Una plantilla corta que obliga a separar lo observado de lo supuesto.
Un informe no tiene que ser largo. Tiene que ser reproducible: cualquiera con la misma captura debe llegar a los mismos hechos.
Fecha: 2026-09-08 14:05–14:35 UTC-6
Captura: incidente-20260908.pcapng
SHA-256 de la captura: 3f9a… (calculado al obtenerla)
Punto de captura: switch principal, puerto espejo del segmento 10.2.3.0/24
Equipo origen: PC-CONTABILIDAD-04
IP origen: 10.2.3.55 (MAC 00:1a:2b:3c:4d:5e)
Destino: 203.0.113.9
Puerto / protocolo: 443/tcp · TLS 1.3 · SNI: api.ejemplo-desconocido.net
Primera conexión: 14:07:12
Última conexión: 14:34:48
Frecuencia: cada 60 s ± 6 s (28 conexiones)
Bytes enviados: 41 kB
Bytes recibidos: 12 kB
DNS relacionado: trama 812 · A api.ejemplo-desconocido.net → 203.0.113.9
Indicadores observados:
- Intervalo casi constante entre conexiones (tramas 815, 1042, 1288…)
- Transferencias pequeñas y de tamaño similar en cada conexión
- Dominio ausente de la línea base de 2026-08-15
- Actividad continúa fuera del horario del usuario
Evidencia:
- tcp.stream 14, 15, 16 … 41 en la captura citada
- Consulta DNS en la trama 812
- Statistics → Conversations: 28 conexiones, 53 kB totales
Hipótesis (NO confirmada):
Proceso automatizado en el equipo consultando periódicamente un servicio
externo. La periodicidad y el destino desconocido son compatibles con un
canal de control, pero también con software legítimo no inventariado.
Lo que esta captura NO permite determinar:
- Qué proceso del equipo generó el tráfico
- Qué contenido se transmitió (TLS 1.3, sin claves)
- Si el destino es legítimo
Siguientes pasos:
1. En el equipo: ss -tanp durante una ventana de conexión
2. Revisar inventario de software autorizado del puesto
3. Consultar reputación del dominio en fuentes de inteligencia
4. Ampliar la ventana de captura a 24 h para confirmar el patrón
5. Revisar si otros equipos contactan el mismo destinoLos tres apartados que hacen que esta plantilla funcione:
- Evidencia — números de trama y de stream. Verificable.
- Hipótesis — marcada como tal, con la alternativa benigna incluida.
- Lo que no se puede determinar — el apartado que casi nadie escribe y que evita que otra persona lea de más en tus conclusiones.
Práctica
Doce laboratorios sobre tu propia máquina, desafíos con solución razonada y la chuleta completa.
Doce laboratorios
Wireshark en una ventana, terminal en la otra. En orden. Cada uno se apoya en el anterior; todos sobre tu propio equipo.
Encontrar tu propia IP y tu interfaz
FundamentosObjetivo: no volver a capturar en la interfaz equivocada.
Preparación: ninguna. Solo una terminal.
- Ejecuta
ip addry localiza la interfaz con estadoUPy una direccióninet. - Anota interfaz, IP y máscara. Aquí:
wlan0,10.2.3.170/24. - Ejecuta
ip route | head -1y anota el gateway. - Ejecuta
ip linky anota tu dirección MAC. - Ejecuta
tshark -Dy comprueba que tu interfaz aparece la primera.
Qué observar: el /24 te dice el tamaño de tu red local.
Todo lo que esté fuera de 10.2.3.0–10.2.3.255 saldrá por el gateway.
Comprobación: abre Wireshark y verifica que la sparkline de esa interfaz se mueve.
Error común: elegir any «por si acaso». Funciona, pero
no tiene cabecera Ethernet real y luego los ejercicios de capa 2 no salen.
Qué has aprendido: los cuatro datos —interfaz, IP, máscara, gateway— que hacen falta antes de cualquier análisis.
Capturar un ping y leer el árbol
FundamentosObjetivo: leer las tres capas de un paquete que entiendes entero.
Preparación: Wireshark capturando en tu interfaz, filtro
icmp puesto.
- En una terminal:
ping -c 4 1.1.1.1. - Selecciona el primer Echo (ping) request.
- Despliega Ethernet II y compara la MAC destino con la de tu gateway.
- Despliega IPv4 y localiza el TTL.
- Despliega ICMP y localiza tipo, identificador y número de secuencia.
- Pincha el campo TTL y mira qué byte se resalta abajo.
icmpQué observar: ocho paquetes, cuatro request y cuatro reply. El identificador es igual en todos; la secuencia va 1, 2, 3, 4.
Explicación: el TTL de salida es 64 y el de vuelta menor; la diferencia son los saltos que recorrió la respuesta.
Comprobación: 64 menos el TTL de la respuesta debe dar un número razonable de saltos (entre 5 y 25 para un destino de internet).
Error común: no ver nada porque el filtro está en la barra de captura y no en la de visualización.
Qué has aprendido: a leer el árbol completo y a relacionar campo y byte.
Provocar y leer un intercambio ARP
ProtocolosObjetivo: ver la capa 2 en acción, por debajo de IP.
Preparación: capturando, filtro arp.
- Vacía la tabla:
sudo ip neigh flush all. - Provoca la resolución:
ping -c 2 10.2.3.1(tu gateway). - Localiza el par request/reply.
- En el request, comprueba que el destino Ethernet es
ff:ff:ff:ff:ff:ff. - En el reply, anota la MAC del gateway.
- Contrasta con
ip neighen la terminal.
Qué observar: el request va en broadcast y el reply en unicast. En el request, el campo «Target MAC» está a ceros: es lo que se pregunta.
Comprobación: la MAC del reply y la de ip neigh deben
coincidir.
Error común: esperar ARP para 1.1.1.1. No existe: para
salir de la red todo va al gateway.
Qué has aprendido: cómo se resuelve IP→MAC, y cuál es la MAC de tu gateway — el dato base del laboratorio 12.
Observar una resolución DNS completa
ProtocolosObjetivo: emparejar consulta y respuesta y leer los registros.
Preparación: capturando, filtro dns.
- Ejecuta
dig +short archlinux.org. - Selecciona la consulta y anota el Transaction ID.
- Selecciona la respuesta y comprueba que el ID coincide.
- Despliega
Answersy anota las IP devueltas. - Busca el campo
[Time: …]que Wireshark añade a la respuesta. - Repite con
dig AAAA archlinux.orgy compara.
dnsQué observar: el nombre viaja en claro. El ID es lo único que empareja pregunta y respuesta, porque UDP no tiene conexión.
Comprobación: las IP de Answers deben ser las mismas que
imprime dig +short.
Error común: no ver nada porque el sistema usa DNS sobre TLS o sobre
HTTPS. Si es tu caso, dig a un resolver concreto: dig @10.2.3.1
archlinux.org.
Qué has aprendido: que DNS delata a dónde va un equipo aunque el resto vaya cifrado.
Reconstruir un handshake TCP
ProtocolosObjetivo: identificar los tres paquetes de apertura y su aritmética.
Preparación: capturando, sin filtro.
- Ejecuta
curl -s -o /dev/null http://neverssl.com. - Aplica
tcp.flags.syn == 1 && tcp.flags.ack == 0y localiza el SYN. - Clic derecho sobre él → Conversation Filter → TCP.
- Cuenta los paquetes e identifica: SYN, SYN-ACK, ACK, petición, respuesta, cierre.
- En cada uno, despliega Flags y anota cuáles están activos.
- Anota
SeqyAckde los tres primeros.
tcp.flags.syn == 1 && tcp.flags.ack == 0Qué observar: con números relativos, SYN lleva Seq=0; SYN-ACK lleva Seq=0 y Ack=1; el ACK lleva Ack=1. El 0 lo consumió el SYN.
Comprobación: si sumas Seq + Len de un segmento con
datos, obtienes el Ack con que responde el otro lado.
Error común: buscar el handshake en HTTPS y perderse entre los paquetes de TLS. Empieza por HTTP, que es más corto.
Qué has aprendido: a leer el estado de una conexión TCP a partir de sus flags y sus números.
Analizar un handshake TLS
ProtocolosObjetivo: ver qué revela HTTPS aunque el contenido esté cifrado.
Preparación: capturando, filtro tls.
- Ejecuta
curl -s -o /dev/null https://archlinux.org. - Localiza el Client Hello (
tls.handshake.type == 1). - Despliega hasta las extensiones y encuentra
server_name. - Añade
tls.handshake.extensions_server_namecomo columna. - Localiza el Server Hello y anota la versión y el cipher suite.
- Intenta un Follow TCP Stream y comprueba que el contenido es ilegible.
tls.handshake.type == 1Qué observar: el SNI está en claro. Con TLS 1.3 probablemente no veas certificados: van cifrados.
Comprobación: la columna SNI debe mostrar archlinux.org
exactamente en el Client Hello y estar vacía en el resto.
Error común: concluir que «Wireshark no ve HTTPS». Ve bastante: el destino, el tamaño y el ritmo. No ve el contenido.
Qué has aprendido: a distinguir metadatos de contenido — la base de todo el análisis de tráfico cifrado.
Follow TCP Stream sobre HTTP
IntermedioObjetivo: dejar de mirar paquetes y leer la conversación.
Preparación: la captura del laboratorio 5, con la petición a
neverssl.com.
- Clic derecho en cualquier paquete de esa conexión → Follow → TCP Stream.
- Identifica en la ventana qué parte enviaste tú y cuál el servidor: van en colores distintos.
- Localiza la línea
GET / HTTP/1.1y las cabecerasHostyUser-Agent. - Cambia el desplegable de dirección a solo cliente → servidor.
- Cambia Show data as a HEX Dump y compara.
- Cierra y observa el filtro que Wireshark ha dejado puesto:
tcp.stream eq N.
Qué observar: no hace falta ninguna herramienta especial para leer HTTP. Eso es lo que significa que no esté cifrado.
Comprobación: cambia el número de tcp.stream y verás
otra conversación distinta de la captura.
Error común: usar Follow sobre TLS y concluir que está roto. El contenido cifrado se ve como basura binaria; es lo esperado.
Qué has aprendido: a reensamblar un diálogo completo y a moverte por
la captura con tcp.stream.
Inventariar los endpoints principales
IntermedioObjetivo: pasar del paquete al panorama con Statistics.
Preparación: captura de 2–3 minutos de navegación normal.
- Abre Statistics → Capture File Properties y comprueba que no hay paquetes descartados.
- Abre Statistics → Protocol Hierarchy y anota los tres protocolos con más bytes.
- Abre Statistics → Endpoints → IPv4 y ordena por bytes. Anota los cinco primeros.
- Abre Statistics → Conversations → TCP y ordena por bytes.
- Añade la columna SNI y anota los dominios que aparecen.
- Guarda todo esto: es tu primera línea base.
Qué observar: unos pocos destinos concentran casi todo el tráfico, y hay una cola larga de conexiones pequeñas. Esa forma es la normal.
Comprobación: los bytes de Protocol Hierarchy deben cuadrar aproximadamente con el tamaño del fichero.
Error común: olvidar Limit to display filter y no entender por qué los números no coinciden con lo que se ve en pantalla.
Qué has aprendido: el recorrido de Statistics que abre cualquier investigación, y tu primera referencia de normalidad.
Encontrar y explicar retransmisiones
IntermedioObjetivo: diagnosticar sin saltar a conclusiones.
Preparación: una captura larga de wifi, mejor si la haces alejándote del router mientras descargas algo.
- Aplica
tcp.analysis.flagsy anota cuántos paquetes quedan. - Abre Analyze → Expert Information y mira el reparto por severidad.
- Calcula el porcentaje: paquetes con anomalía sobre el total. Ese número es tu línea base de wifi.
- Aplica
tcp.analysis.retransmissiony comprueba si se concentran en una conversación o están repartidas. - Comprueba en Capture File Properties si hubo descartes en la captura.
- Superpón en I/O Graphs el tráfico total y las retransmisiones.
tcp.analysis.flagsQué observar: si las retransmisiones suben cuando sube el tráfico, es congestión. Si están repartidas y son pocas, es el wifi comportándose como el wifi.
Comprobación: repite la captura pegado al router. El porcentaje debe bajar de forma apreciable.
Error común: concluir que la red está mal sin comprobar antes si fue tu propia captura la que perdió paquetes.
Qué has aprendido: que una anomalía necesita una línea base antes de significar algo.
Buscar tráfico llamativo en tu propia captura
CiberseguridadObjetivo: aplicar el checklist defensivo sobre datos reales y tuyos.
Preparación: una captura de 10–15 minutos de tu equipo con actividad
normal. Guárdala en .pcapng.
- Lista los dominios consultados y ordénalos por frecuencia con
tshark. - Aplica
dns.flags.rcode == 3y cuenta los NXDOMAIN. - Aplica
dns.qry.name.len > 50y mira si hay nombres largos. - Busca conexiones de salida:
ip.src == 10.2.3.0/24 && !(ip.dst == 10.2.3.0/24). - En Conversations, ordena por bytes enviados y busca asimetrías hacia arriba.
- Para cada destino que no reconozcas, busca el SNI o el DNS que lo resolvió.
- Escribe, para cada uno, la explicación benigna que encuentres.
Qué observar: vas a encontrar muchos destinos que no reconoces, y casi todos tendrán explicación: CDN, telemetría, actualizaciones, servicios del sistema.
Explicación: ese es exactamente el punto del ejercicio. Aprender a explicar lo desconocido es más útil que aprender a alarmarse.
Comprobación: deberías poder justificar el 90 % de los destinos. El resto es tu lista de pendientes.
Error común: dar por sospechoso todo lo que no se reconoce.
Qué has aprendido: que la mayor parte del trabajo defensivo consiste en descartar, no en encontrar.
Detectar un patrón periódico
CiberseguridadObjetivo: medir periodicidad con datos que generas tú.
Preparación: vas a fabricar tu propio patrón periódico para tener un caso conocido. En una terminal, mientras capturas:
$ while true; do curl -s -o /dev/null https://example.com; sleep 30; doneDéjalo cinco minutos y detén la captura con Ctrl+C.
- Filtra las aperturas hacia ese destino:
tls.handshake.type == 1 && tls.handshake.extensions_server_name contains "example". - Cambia View → Time Display Format a Seconds Since Previous Displayed Packet.
- Lee la columna Time: deberían ser todos cercanos a 30.
- Abre Statistics → I/O Graphs, pon intervalo de 1 s y una línea con ese filtro.
- Compara la forma con la de tu navegación normal en el mismo gráfico.
- Repite el cálculo de intervalos con la receta de
tsharkde la sección de beaconing.
Qué observar: el peine regular frente a las ráfagas irregulares de la navegación humana. Esa diferencia visual es la señal.
Comprobación: los intervalos deben agruparse en torno a 30 s con muy poca dispersión.
Error común: concluir que todo lo periódico es malicioso. Acabas de generar tú un patrón perfectamente periódico y perfectamente inocente.
Qué has aprendido: a medir periodicidad, y por qué la periodicidad sola no basta.
Redactar un informe de incidente
CiberseguridadObjetivo: convertir observaciones en un documento revisable.
Preparación: la captura del laboratorio 11, que contiene un patrón periódico conocido, provocado por ti.
- Copia la plantilla de la sección «Mini informe de incidente».
- Rellena los datos objetivos: fechas, IP, puerto, protocolo, SNI, bytes en ambos sentidos.
- Calcula el hash de la captura:
sha256sum captura.pcapng. - Anota los números de trama concretos que sostienen cada observación.
- En «Indicadores observados» escribe solo hechos, sin interpretación.
- En «Hipótesis» escribe tu explicación — que aquí conoces: el bucle que lanzaste.
- Rellena «Lo que esta captura NO permite determinar». Sé estricto.
- Dale el informe a otra persona con la captura y comprueba si llega a lo mismo.
Qué observar: el ejercicio real es el último apartado. Con la captura delante, no puedes saber qué proceso lo generó ni qué contenía la conexión.
Comprobación: si alguien puede reproducir tus hechos abriendo la captura, el informe sirve. Si tiene que fiarse de tu palabra, no.
Error común: mezclar evidencia e hipótesis en el mismo párrafo.
Qué has aprendido: a documentar de forma que otro pueda revisarte — la parte del análisis que más importa cuando hay consecuencias de por medio.
Desafíos
Preguntas sin respuesta inmediata. Intenta resolverlas antes de desplegar la solución.
Trabaja sobre una captura tuya de navegación normal, de unos minutos. Cada desafío tiene primero la misión, luego unas pistas, y solo después la solución razonada.
Reconstruir una visita web completa
IntermedioMisión: elige un dominio de tu captura y reconstruye toda la secuencia que llevó a conectar con él.
Debes poder rellenar esta cadena con datos concretos de tu captura:
DNS consulta de ___________ → responde ___________
↓
TCP SYN a ___________:443 (trama ____)
↓
TLS Client Hello, SNI = ___________ (trama ____)
↓
Datos ____ bytes intercambiados en ____ segundosVer pistas
- Empieza por el final: pon
tls.handshake.extensions_server_namecomo columna y elige un dominio. - De ahí sacas la IP del servidor. Ahora busca hacia atrás en el tiempo.
- Para encontrar el DNS que resolvió esa IP, el filtro es
dns.a == esa.ip. - Para el handshake TCP, filtra por
tcp.streamdel Client Hello. - Los bytes y la duración están en Statistics → Conversations.
Ver solución razonada
El orden de trabajo correcto es hacia atrás, y esa es la lección del ejercicio. En una investigación real casi nunca empiezas por el principio: empiezas por el indicador que te llamó la atención —una IP, un dominio— y reconstruyes cómo se llegó hasta ahí.
- SNI → IP. El Client Hello te da nombre e IP a la vez. Es el punto de partida más rico de una captura moderna.
- IP → DNS.
dns.a == 93.184.216.34localiza la respuesta DNS que devolvió esa dirección. Si no aparece ninguna, es un dato en sí mismo: el equipo llegó a esa IP sin resolverla en esta captura (la tenía en caché, la llevaba escrita, o usó DoH). - DNS → consulta. El Transaction ID te lleva a la pregunta, y con ella al momento exacto en que empezó todo.
- TCP. El
tcp.streamdel Client Hello te da la conexión entera: SYN, SYN-ACK, ACK, handshake TLS, datos, cierre. - Volumen y tiempo. Conversations, con Limit to display filter marcado.
Si en el paso 2 no encuentras DNS, no des por hecho que es sospechoso: comprueba
primero si tu navegador usa DNS sobre HTTPS, en cuyo caso las consultas van cifradas
dentro de otra conexión y no aparecerán nunca como dns.
Quién inició, quién respondió
FundamentosMisión: dada una conversación TCP cualquiera de tu captura, responde sin mirar los puertos conocidos.
- ¿Qué equipo inició la conexión?
- ¿Qué puerto usó cada extremo?
- ¿Se completó el handshake?
- ¿Cómo terminó: FIN o RST?
- ¿Hubo retransmisiones?
- ¿Cuántos bytes fue en cada sentido?
Ver pistas
- El que inicia es el que envía el SYN sin ACK. Ese único paquete responde a las dos primeras preguntas.
- El puerto alto y aleatorio es el del cliente; el bajo y estable, el del servicio.
tcp.completenessresume el estado de la conexión.- Para el final, mira los últimos paquetes del
tcp.stream.
Ver solución razonada
Quién inició: el emisor del SYN sin ACK. Es el único paquete de una
conexión con esa combinación, y por eso tcp.flags.syn == 1 &&
tcp.flags.ack == 0 es el filtro más usado de todo Wireshark.
Los puertos: el cliente elige uno efímero (en Linux, entre 32768 y 60999); el servidor escucha en uno fijo. Si ves 51234 → 443, la dirección está clara sin necesidad de saber que 443 es HTTPS.
Si se completó: tienen que estar los tres paquetes. Un SYN al que
responde un RST es un puerto cerrado; un SYN sin ninguna respuesta es un puerto
filtrado o un servidor caído. tcp.completeness lo resume en un valor.
Cómo terminó: FIN por ambos lados es un cierre limpio. Un RST puede ser normal (la aplicación cerró de golpe) o significar que alguien intervino: revisa el TTL del RST y compáralo con el del resto de paquetes de ese extremo.
Retransmisiones: añade && tcp.analysis.flags al
filtro de la conversación.
Bytes: Statistics → Conversations, columnas A→B y B→A. La asimetría te dice si el equipo descargaba o subía.
El equipo que no debería estar hablando
CiberseguridadMisión: en tu captura, encuentra el equipo con más destinos externos distintos y explica por qué.
Ver pistas
- Statistics → Endpoints → IPv4, y ordena por la columna de número de conexiones o de paquetes.
- Filtra la salida de tu red y vuelve a mirar con Limit to display filter.
- Para cada destino, busca el SNI o el DNS asociado.
- Pregúntate qué software del equipo explicaría esa cantidad de destinos.
Ver solución razonada
En una red doméstica el equipo con más destinos externos suele ser aquel en el que hay un navegador abierto: una sola página web moderna contacta con decenas de dominios —CDN, analítica, fuentes tipográficas, publicidad, APIs—. Eso, que parece alarmante, es simplemente cómo funciona la web hoy.
Lo que convierte este dato en interesante es el contraste: un servidor, una impresora o una cámara que hablan con decenas de destinos externos no tienen la misma explicación. La pregunta correcta no es «¿cuántos destinos?», sino «¿cuántos destinos para lo que es este equipo?».
Y el método para responderla es el mismo de siempre: mirar el SNI de cada destino, buscar la consulta DNS que lo resolvió, y comprobar si encaja con el software que debería estar corriendo ahí. Cuando no encaje y no encuentres explicación, tienes un hallazgo — y entonces se aplica el flujo de diez preguntas y la plantilla de informe.
Errores comunes
Los once tropiezos que se repiten, y cómo evitarlos.
| Error | Qué pasa | Solución |
|---|---|---|
| Capturar en la interfaz equivocada | La captura sale vacía o llena de tráfico que no es el tuyo | ip addr primero; fíjate en la sparkline |
| Confundir capture filter y display filter | La sintaxis se rechaza y parece que «el filtro no funciona» | BPF abajo en la pantalla de inicio; Wireshark en la barra verde de arriba |
| Pensar que todo lo rojo es malo | Alarma por retransmisiones normales de wifi | Los colores son reglas configurables; compara con tu línea base |
| Retransmisión = ataque | Se concluye compromiso donde hay congestión | Es TCP corrigiendo errores. Mira si afecta a una conversación o a todas |
| Analizar sin contexto | Todo parece sospechoso porque no hay referencia | Construye la línea base antes de necesitarla |
| Olvidar los timestamps | No se puede correlacionar con registros de otros sistemas | View → Time Display Format → hora absoluta; anota la zona horaria |
| Ignorar el DNS | Se investigan IP sueltas sin saber a qué nombre corresponden | El DNS de la propia captura te da los nombres sin consultar fuera |
| Esperar leer HTTPS | Frustración con Follow Stream sobre TLS | Va cifrado. Analiza metadatos: SNI, tamaños, tiempos |
| Ejecutar Wireshark como root | Se expone todo el equipo a un fallo en un disector | Grupo wireshark y dumpcap con capabilities |
| Capturar demasiado | Ficheros enormes, paquetes descartados, y un problema de privacidad | Capture filter, límites de tamaño o de tiempo, ficheros en anillo |
| Concluir con un solo paquete | Se construye una teoría sobre una coincidencia | Un indicador no es evidencia. Busca varios independientes |
Chuleta de display filters
Los que se usan a diario, por protocolo. Todos verificados contra el motor de filtros de Wireshark 4.7.
Los de uso diario
| Filtro | Qué muestra |
|---|---|
| ip.addr == 10.2.3.1 | Todo lo que va o viene de esa IP |
| ip.src == 10.2.3.170 | Solo lo que sale de tu equipo |
| tcp.port == 443 | Tráfico HTTPS por puerto |
| dns || icmp || arp | Varios protocolos a la vez |
| !(arp || dns) | Todo menos el ruido de fondo |
| http.request | Solo peticiones HTTP, sin respuestas |
| http.response.code >= 400 | Errores HTTP |
| tcp.flags.reset == 1 | Conexiones cortadas de golpe |
| tcp.analysis.retransmission | Paquetes reenviados: pérdida en la red |
| tcp.stream eq 3 | Una conversación TCP concreta |
| frame contains "password" | Busca una cadena en el contenido crudo |
| frame.len > 1400 | Paquetes grandes, cerca del MTU |
Ethernet y ARP
| Filtro | Qué muestra |
|---|---|
| eth.addr == b8:1e:a4:5a:ac:8d | Todo lo de esa tarjeta, entre y salga |
| eth.src · eth.dst | Direccional: solo emitido o solo recibido |
| eth.dst == ff:ff:ff:ff:ff:ff | Broadcast del segmento |
| eth.ig == 1 | Broadcast y multicast juntos |
| eth.type == 0x0806 | Tramas ARP por EtherType |
| arp.opcode == 1 · 2 | Preguntas · respuestas |
| arp.src.proto_ipv4 == 10.2.3.1 | Quién dice ser el gateway |
| arp.duplicate-address-detected | Una IP con dos MAC distintas |
IPv4 e IPv6
| Filtro | Qué muestra |
|---|---|
| ip.addr == 10.2.3.0/24 | Una red entera en notación CIDR |
| ip.ttl < 20 | Paquetes que han dado muchos saltos |
| ip.ttl in {1 .. 5} | Rango de TTL: la firma de un traceroute |
| ip.flags.mf == 1 || ip.frag_offset > 0 | Paquetes fragmentados |
| ip.proto == 6 | Por número de protocolo: 1 ICMP, 6 TCP, 17 UDP |
| ip.len > 1400 | Paquetes IP grandes |
| ipv6 | Todo el tráfico IPv6 |
| ipv6.hlim < 20 | El equivalente al TTL en IPv6 |
| icmpv6 | Descubrimiento de vecinos y anuncios de router |
ICMP
| Filtro | Qué muestra |
|---|---|
| icmp.type == 8 · 0 | Echo request · echo reply |
| icmp.type == 3 | Destino inalcanzable |
| icmp.type == 3 && icmp.code == 13 | Bloqueado por un cortafuegos que avisa |
| icmp.type == 11 | TTL agotado: la base de traceroute |
| icmp.ident == 0xc977 | Una ejecución concreta de ping |
TCP y UDP
| Filtro | Qué muestra |
|---|---|
| tcp.flags.syn == 1 && tcp.flags.ack == 0 | Aperturas de conexión. El filtro más usado |
| tcp.flags.fin == 1 | Cierres ordenados |
| tcp.port in {80, 443, 8080} | Conjunto de puertos. Con comas |
| tcp.len > 0 | Solo segmentos con datos, sin ACK vacíos |
| tcp.analysis.flags | Todo lo que Wireshark marca como anómalo |
| tcp.analysis.duplicate_ack | «Me falta un trozo» |
| tcp.analysis.zero_window | Receptor saturado |
| tcp.analysis.lost_segment | Hueco en la numeración |
| tcp.completeness < 7 | Conexiones que no llegaron a completarse |
| tcp.time_delta > 1 | Pausas dentro de una misma conexión |
| tcp.window_size < 1000 | Ventana pequeña: posible cuello de botella |
| udp.port == 53 | DNS por UDP |
| udp.length > 512 | Datagramas UDP grandes |
DNS y DHCP
| Filtro | Qué muestra |
|---|---|
| dns.flags.response == 0 · 1 | Consultas · respuestas |
| dns.qry.name contains "ejemplo" | Consultas de un dominio concreto |
| dns.qry.type == 1 · 28 · 5 · 15 · 16 · 12 | A · AAAA · CNAME · MX · TXT · PTR |
| dns.flags.rcode == 3 | NXDOMAIN: el nombre no existe |
| dns.qry.name.len > 50 | Nombres anormalmente largos |
| dns.time > 0.5 | Resoluciones lentas |
| dns.a == 203.0.113.9 | Qué nombre resolvió a esa IP |
| dns.count.answers == 0 | Respuestas sin registros |
| dhcp | Todo DHCP (era bootp antes de la 2.6) |
| dhcp.option.dhcp == 1 · 2 · 3 · 5 | Discover · Offer · Request · ACK |
| dhcp.option.hostname | El nombre que se da cada equipo |
HTTP y TLS
| Filtro | Qué muestra |
|---|---|
| http.request.method == "GET" | Por método. Las comillas son obligatorias |
| http.host contains "ejemplo" | Por sitio de destino |
| http.user_agent | Paquetes que declaran agente de usuario |
| http.user_agent matches "(?i)curl|wget" | Agentes que no son navegadores |
| http.authorization | Autenticación HTTP: credenciales expuestas |
| http.cookie | Cookies viajando en claro |
| http.file_data | Cuerpo de la petición o la respuesta |
| tls.handshake.type == 1 · 2 · 11 | Client Hello · Server Hello · Certificate |
| tls.handshake.extensions_server_name | El SNI: el destino real de cada conexión |
| tls.alert_message | Handshakes TLS fallidos |
| tls.record.content_type == 23 | Datos de aplicación cifrados |
Análisis y ciberseguridad
| Filtro | Para qué |
|---|---|
| ip.src == 10.2.3.0/24 && !(ip.dst == 10.2.3.0/24) | Todo lo que abandona tu red |
| dns && !(ip.dst == 10.2.3.1) | Consultas a un resolver que no es el tuyo |
| tcp.flags.syn == 1 && tcp.flags.ack == 0 | Indicio de escaneo, junto con Conversations |
| tcp.flags.reset == 1 && tcp.flags.ack == 1 | Puertos cerrados que respondieron |
| ftp || telnet || http.authorization | Auditar protocolos que exponen credenciales |
| ftp.request.command == "PASS" | Envío de contraseña por FTP |
| frame.len > 1400 && ip.dst != 10.2.3.0/24 | Paquetes grandes hacia fuera |
| http.host matches "^[0-9.]+$" | Peticiones a IP directa, sin nombre |
Operadores: == != > < para
comparar; && o and, || o or,
! o not para combinar; contains para subcadenas y
matches para expresiones regulares.
Y el atajo que hace innecesario memorizar nada: clic derecho sobre cualquier campo del árbol → Apply as Filter → Selected. Wireshark escribe el filtro correcto y así es como se aprenden los nombres de los campos — trabajando, no estudiando una lista.