Imagine you are sitting in an airport, and you feel a sudden urge to browse the Internet. You take out your phone, and there seems to be an open network for travelers. Having safety in mind, you fire up your VPN client. But wait - It can’t connect? You open your browser and witness a horrible sight when you try to look something up in DuckDuckGo…
“Damn!”, you say to yourself. “I don’t want to pay for that! There has to be a way…”
Enter DNS tunneling!
DNS is, in short, a service to translate domain names, such as 0x00sec.org, to IP adresses, such as 104.18.49.48. A typical exchange looks like this:
- Client sends a UDP packet containing the domain name to translate.
- Server replies with the IP address corresponding to the domain.
There are more DNS record types, for example TXT, which allow the server to respond with arbitrary data instead of an IP. Now, someone smart thought to themselves, would it be possible to communicate using DNS requests and replies? As it turns out, it is! Imagine something like the following:
- Client sends a DNS packet of type TXT containing “hello-server.domain.tld”
- Server receives the packet, reads data from the request and sends back “hello-client”
See where this is going? Now, let’s go a step further and create (almost) a full blown VPN! With some base64 or other encoding sprinkled in, you can send whole IP packets encapsulated in DNS requests. Here’s an example:
- Client reads a packet from a TUN device, encodes it and sends a request containing the packet to the server. Let’s say it’s a SYN packet to 0x00sec.org.
- Server receives the request, and decodes the packet.
- The packet’s source address is changed to indicate the server’s address, so replies go back to the server instead of the client.
- The packet is then sent on its way, and a reply shortly arrives: a SYN/ACK packet!
- Packet source is changed back to client so his networking software doesn’t bitch about malformed packets and other such frivolities. It’s then encoded into a DNS reply and sent back.
- Client receives the SYN/ACK and writes it into the tun device.
Now the client’s browser/netcat/metasploit will respond with an ACK packet and a connection will be estabilished. There’s a caveat, though. What if the server needs to send data? It can’t just send another DNS reply, as the client’s router won’t route it to the client anymore. The solution is a bit hacky but simple: the client just needs to send an empty DNS request every so often, so the server can reply with the data.
It might look simple on paper, but the implementation is somewhat difficult. Trust me, I tried. Thankfully, there already are programs for DNS tunneling. The one I’m using is called Iodine. You can install it by using apt-get install iodine
. Here’s what you will need:
- A server and client. They’re both included in the
iodine
package. - A domain name, with the ability to set nameservers. You can get one from dot.tk.
- Another couple domains to set up nameservers.
- A computer you can forward port 53 to.
You’ll have to set up nameservers to domains which point to your iodine server.
Setting up is quite simple. On the server, run:
iodined -P <strong password> <IP of tun device> <domain>
for example, iodined -P 1234 10.0.0.1 tunnel.tk
On the client, run:
iodine -P <password> <domain>
for example, iodine -P 1234 tunnel.tk
And voila! Free internet access everywhere! (Unless the router doesn’t fall for it and blocks all DNS queries, but shh…)