← Blog
// BLUE TEAM · THREAT HUNTING

Detección de DNS Tunneling con KQL en Microsoft Sentinel

Publicado el 14 jul 2026 · 8 min de lectura
KQLMicrosoft SentinelDNSThreat HuntingExfiltración

El DNS es el "listín telefónico" de internet y casi ningún firewall lo bloquea. Precisamente por eso los atacantes lo abusan: encapsulan datos dentro de consultas y respuestas DNS para exfiltrar información o mantener un canal de Command & Control (C2) que pasa desapercibido. En este artículo veremos cómo cazarlo en Microsoft Sentinel con KQL, sin comprar nada extra.

¿Por qué el DNS es un canal encubierto ideal?

La huella que deja es característica: subdominios largos y de alta entropía, un volumen anómalo de consultas hacia un mismo dominio y tipos de registro poco habituales (TXT, NULL, CNAME).

Señal 1 — Longitud y entropía del subdominio

Un dominio legítimo como cdn.contoso.com es corto y pronunciable. Un túnel produce algo como M FRGGZDF.k7x2.exfil.attacker.com. Podemos aproximar la entropía contando caracteres únicos frente a la longitud:

DnsEvents
| where TimeGenerated > ago(24h)
| where isnotempty(Name)
| extend sub = tostring(split(Name, ".")[0])
| extend subLen = strlen(sub)
| extend uniqueChars = array_length(set_difference(
        extract_all(@"(.)", sub), dynamic([])))
| where subLen > 30 and uniqueChars > 15
| project TimeGenerated, ClientIP, Name, subLen, uniqueChars
| order by subLen desc

Ajusta los umbrales (subLen, uniqueChars) a tu entorno tras una fase de baseline.

Señal 2 — Volumen anómalo por dominio de segundo nivel

Un host que hace cientos de consultas únicas hacia el mismo dominio padre en poco tiempo es sospechoso: está "chorreando" datos subdominio a subdominio.

DnsEvents
| where TimeGenerated > ago(1h)
| extend parts = split(Name, ".")
| extend parentDomain = strcat(parts[array_length(parts)-2], ".", parts[array_length(parts)-1])
| summarize queries = count(), uniqueSub = dcount(Name) by ClientIP, parentDomain
| where uniqueSub > 200
| order by uniqueSub desc

Señal 3 — Tipos de registro poco comunes

El tráfico normal es mayoritariamente A/AAAA. Un pico de TXT o NULL desde un endpoint de usuario es una bandera roja:

DnsEvents
| where TimeGenerated > ago(24h)
| where QueryType in ("TXT", "NULL", "CNAME")
| summarize count() by ClientIP, QueryType, bin(TimeGenerated, 1h)
| where count_ > 50
💡 Consejo de analista: combina las tres señales en una regla analítica de Sentinel y puntúa (score) cada host. Una sola señal genera ruido; las tres juntas, casi nunca fallan. Añade una watchlist de dominios corporativos conocidos para excluir falsos positivos (telemetría de EDR, CDNs, etc.).

De la detección a la respuesta

  1. Triaje: ¿el dominio padre es conocido? ¿el proceso que lanza las consultas es legítimo (correlaciona con DeviceNetworkEvents de Defender)?
  2. Contención: bloquea el dominio en el resolver/EDR y aísla el host si se confirma.
  3. Erradicación: identifica el binario responsable y su persistencia.
  4. Lecciones: convierte la caza en una regla analítica programada para no repetir el trabajo manual.

Si quieres practicar el lado ofensivo/forense de esto, en la plataforma tienes el reto OP: GHOST_TRAFFIC, donde analizas una captura con un túnel DNS real.

Sergio Belmonte Morales
Sergio Belmonte Morales
Analista de Ciberseguridad · SOC · Especialista en Sentinel/KQL