Some Notes on DNS Tunnels
I've been spending a decent number of frustrating evenings fighting with DNS tunnels and wanted to write a quick post to capture my thoughts while they were fresh in my head.
DNS Recursion
DNS tunnels work through the magical properties of DNS recursion. Without getting too far into it, here's how that works:
- You ask your local DNS server if it knows where you can find
foo.bar.mydomain.com
. It has no idea. If it is not configured for recursion, and most of the ones I've seen are, it sends a big fat nope to you and that's that. Otherwise, one of two things will occur. - A) It will forward your request to another DNS server or B) It will forward it to the root DNS servers. Since option A) eventually ends up in step 1 or option B, we'll move forward.
- The root servers contain a list of all top-level domains (.com, .net, .ninja, etc.). The root name servers will have no idea where
foo.bar.mydomain.com
is, but they do know which server is responsible for.com
, so it helpfully forwards your request there - The
.com
name servers receive the request and similarly have no idea wherefoo.bar.mydomain.com
is, but they do know of a NS record formydomain.com
. It forwards your request there. - The name server for
mydomain.com
receives the query and looks at the list of zones it is authoritative for and see that it, too, doesn't know much aboutfoo.bar.mydomain.com
, but it does know where to find the name server forbar.mydomain.com
and passes your query along. - Finally your DNS query arrives at the name servers for
bar.mydomain.com
. Since they're authoritative for the zone, they know exactly where to findfoo.bar.mydomain.com
and sends a response, allowing you to do whatever it is that you were doing to a hostname. Great.
Tunneling Through DNS
If we keep the above example in mind, let's imagine that you were on a locked down network with a recursive DNS server and I was in possession of the bar.mydomain.com
DNS server.
If you wanted to send me a message, you could just do something like this:
dig hi-liam.bar.mydomain.com
and I would see a DNS query come in for hi-liam. I could then send a response using a TXT record that says something like 'sup?'. You could then respond with a:
dig oh-not-much.bar.mydomain.com
And we'd have a painfully slow but pretty stealthy conversation. DNS tunnelling works more or less the same way, but is automated.
So this seems pretty neat, right? We've got a covert comms channel baked into the architecture of the internet that will almost always be working.
The cake is a lie, man.
You see, not really, because DNS tunnels exist in this strange limbo where they're feasible enough to exist, but not widely useful enough to actually have solid solutions in place.
You're also swimming upstream against some decent technical restrictions imposed on us as a result of us co-opting the backbone of the internet for covert C2 traffic.
The Contenders
I tested out four DNS tunnels with varying degrees of success. I stuck my DNS server in Azure since I've got credits fo' DAYS, and configured a name server for a $1 domain I'd purchased.
Here's the DNS configuration I used for the mydomain.com
domain:
|
|
Let's unpack what I've just done. The ns1
A record is just a normal host record that tells us where to find a host. In my previous example, this would be foo
in foo.bar.mydomain.com
.
The next line is where the magic happens. What we're doing here is defining name servers for the tunnel.mydomain.com
domain (or bar.mydomain.com
domain if you're stuck on the previous example still). Our messages will be sent in the form <message text>.tunnel.mydomain.com
.
The tunnel
part names the subdomain, and the ns1.mydomain.com
tells us where to find the DNS servers for that domain. In practice, these are usually in different zones. Here's what the NS records for smallsec.ca look like:
|
|
These NS records tell us where to send queries for the domain in question.
Smashing systemd-resolve
Linuxes using systemd
may need to kill systemd-resolve
to free up 53/udp
: sudo systemctl stop systemd-resolve.service
. Reverse the process when you're done, or name resolution will be less functional than you'd like.
Iodine
I got Iodine up and running with minimal fuss, but it was slow as fuck. One neat thing about it is that it tunnels IP, so you can route through it if you like, making this totally transparent to the tools you're using. The examples below assume a Linux client and server, but Windows is supported as well.
First we start the server:
|
|
-f
- Keep in foreground.-DD
- Lotsa debug output.-c
- Disable check of client IP/port on each request.-4
- Use IPv4.-P
- Password for tunnel.IP
- IP for local interface.DOMAIN
- The domain to listen for queries on.
Then the client:
|
|
-f
- Keep in foreground.-P
- Password for tunnel.DOMAIN
- The domain to call home on
Here's what the initial communication looks like:
|
|
This shows the first lookup (foo.bar.mydomain.com from our first example) and then I've cut out the client/server negotiation. The last two RX/PING pairs are just keepalives. You should now have a new local interface on each end of the tunnel that you can communicate with.
DNS2TCP
This... didn't work. A tunnel would start, then disconnect and refuse to connect again. I don't know why, but I discovered dnscat2 before I found a solution and then I no longer cared.
TUNS
I read about TUNS and got really excited, I think mainly because I'd been swearing at DNS2TCP for days. The author wrote a paper on the topic of DNS tunneling, which is definitely worth a read, that introduces the tool. Here's the part that made me giddy:
an IP over DNS tunnel, focused on simplicity and protocol compliance. Comparison of TUNS and the other implementations showed that this approach is successful: TUNS works on all the networks we tested, and provides reasonable performance despite its use of less efficient encapsulation techniques, especially when facing degraded network conditions
dnscat2
I kept coming back to DNS2TCP for some reason and reached out to a colleague for help who sent me to dnscat2. I'll let the author speak for himself:
dnscat2 strives to be different from other DNS tunneling protocols by being designed for a special purpose: command and control.
This isn't designed to get you off a hotel network, or to get free Internet on a plane. And it doesn't just tunnel TCP.
It can tunnel any data, with no protocol attached. Which means it can upload and download files, it can run a shell, and it can do those things well. It can also potentially tunnel TCP, but that's only going to be added in the context of a pen-testing tool (that is, tunneling TCP into a network), not as a general purpose tunneling tool. That's been done, it's not interesting (to me).
It's also encrypted by default. I don't believe any other public DNS tunnel encrypts all traffic!
This one gets my vote. It's also somehow faster than the others, which was a nice surprise.
Conclusion
There's a lot to like about DNS tunnels. I love that they're built into the infrastructure. I love that recursion is almost always enabled and provides a way for this traffic to sneakily exit the network. There are almost certainly ways to detect and block this traffic, but I think it's unlikely most sites will implement them in the near future.