Silent Harvest — Exfiltración por DNS tunneling

Network Forensics

Una estación filtra un fichero de nóminas fuera de la red usando solo DNS. Demostrarlo, cuantificarlo y reconstruir lo robado.

Idea clave & Hipótesis

No hay subida HTTP ni correo, pero sí un pico de DNS. Hipótesis: DNS tunneling, con datos codificados en las etiquetas de subdominio hacia un dominio del atacante.

# dominios más consultados en el PCAP
tshark -r dns-exfil.pcap -Y 'dns.flags.response==0' -T fields -e dns.qry.name \
  | rev | cut -d. -f1-2 | rev | sort | uniq -c | sort -rn | head

Detección Sigma

Alertar sobre nombres DNS con etiquetas muy largas y de alta entropía hacia un mismo dominio padre — tunneling clásico.

detection:
  selection_long_label:
    dns.query.name|re: '([a-z2-7]{40,})\.'
  condition: selection_long_label
level: high # tags: attack.t1048.003, attack.t1071.004
Ver Lab Completo ↗

Battering Ram — Password spraying & takeover

SIEM / Splunk

Un aluvión de logins fallidos. Distinguir spraying de fuerza bruta, hallar la IP atacante y la cuenta que cayó.

Idea Clave

Spraying = una contraseña contra muchas cuentas (muchos usuarios distintos, pocos fallos cada uno, una IP). Fuerza bruta = una cuenta, muchos fallos. Ambos son 4625; se distinguen contando por IP y por cuenta.

# una IP fallando contra MUCHAS cuentas = spraying
index=northwind sourcetype=WinEventLog:Security EventCode=4625
| stats count dc(Account_Name) as cuentas by Source_Network_Address
| where cuentas >= 10 | sort -cuentas
Ver Lab Completo ↗

Overwatch — Correlación Multi-fuente

Advanced SIEM

Una intrusión completa vista desde el SOC: ninguna fuente por sí sola cuenta la historia — se correlacionan.

Enfoque

Azure AD da el QUIÉN (un sign-in de alto riesgo), Sysmon el QUÉ (PowerShell -EncodedCommand → un implante), proxy/Zeek el CON-QUIÉN (beaconing C2) y DNS el QUÉ-SE-LLEVARON (exfiltración base32). El valor está en cruzarlos.

# beaconing: cadencia casi fija hacia un dominio
index=northwind sourcetype=proxy:web
| streamstats current=f last(_time) as prev by src,dest_host
| eval gap=_time-prev | stats avg(gap) dc(gap) by src,dest_host,http_user_agent
Ver Lab Completo ↗