Demostración práctica

Write-ups & detecciones

Investigaciones centradas en la metodología, de mis KrakenSOC-Labs: hipótesis, la SPL/filtros exactos, la lógica de detección y el mapeo ATT&CK. Se omiten las flags para no destripar los labs.

Network ForensicsWireshark · tsharkT1048.003T1071.004

Silent Harvest — Exfiltración por DNS tunneling

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

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.

Investigación

Rankear los dominios padre que reciben más consultas y buscar etiquetas largas de alta entropía:

# 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
Cuantificar y reconstruir

Las consultas con datos usan prefijo dNNNN y alfabeto base32 (a-z, 2-7). Contarlas, y luego ordenar, unir y decodificar en base32 para reconstruir el fichero:

tshark -r dns-exfil.pcap -Y 'dns.flags.response==0' -T fields -e dns.qry.name \
  | grep -E '^d[0-9]{4}\.' | sort -t. -k1.2n | awk -F. '{print $2}' \
  | tr -d '\n' | python3 -c 'import sys,base64;s=sys.stdin.read().upper();print(base64.b32decode(s+"="*((-len(s))%8)).decode("utf-8","replace"))'
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
Resultado

Exfiltración confirmada y cuantificada; fichero robado reconstruido desde la captura. Lab completo, reglas y capa ATT&CK:

silent-harvest ↗
SIEM · SplunkWindows SecurityT1110.003T1078

Battering Ram — Password spraying & account takeover

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.

Investigación (SPL)
# 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
Pivote al compromiso

El punto de inflexión es un 4624 exitoso desde la misma IP que fallaba. Lo que viene después (4720 alta de cuenta, 4732 alta en Administradores) es persistencia.

index=northwind sourcetype=WinEventLog:Security EventCode=4624
  Source_Network_Address=<attacker_ip>
| stats values(Account_Name) values(Computer)
Detección (Sigma)
detection:
  selection: { EventCode: 4625 }
  timeframe: 15m
  condition: selection | count(Account_Name) by Source_Network_Address > 10
level: high  # attack.t1110.003
Resultado

Spraying identificado, IP atacante y cuenta comprometida halladas, y la cuenta backdoor rastreada. Lab completo:

battering-ram ↗
SIEM · SplunkMulti-source correlationT1071.001T1059.001T1048.003

Overwatch — Correlación de una intrusión completa

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.

Línea base y pivotes (SPL)
# 1) línea base por fuente
index=northwind | stats count by sourcetype
# 2) sign-in de alto riesgo (acceso inicial)
index=northwind sourcetype=azuread:signin riskLevel=high
# 3) ejecución ofuscada (implante)
index=northwind sourcetype=Sysmon EventID=1 CommandLine="*-EncodedCommand*"
# 4) 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
Resultado

Kill chain reconstruida de principio a fin (acceso inicial → ejecución → C2 → colección → exfiltración) entre cinco fuentes — el capstone que une los labs atómicos. Lab completo:

overwatch ↗