DNS Tunneling made easy
Yesterday I came across a technique to tunnel any traffic through the DNS protocol: All the packages you send are base32 encoded and prepended as the hostname of a DNS lookup request. A specially prepared DNS server will then forward your packages and reply with TXT answers.
What is it good for? It's an interesting way to hide your traffic. Cory Doctorow wrote about it in Little Brother for example. But it can also be used to sneak into certain public hotspots which are protected by HTTP redirections only. Those hotspots will allow web traffic to some few restricted websites (or some login page) only, but often allow all DNS traffic. It should also work to circumvent restrictive company firewalls.
I googled for implementations and came across two.
One is NSTX which makes use of the tun device support in Linux. This seems to be an excellent choice when you plan to use DNS tunneling on a regular basis.
The second option are some Perl scripts by Dan Kaminsky included in his OzymanDNS scripts. These are better fitted for the occasional use and easier to set up IMHO.
Those scripts can be combined with SSH to tunnel arbitrary traffic and there's an excellent documentation how to do that at dnstunnel.de.
However I found those scripts to be a bit messy and some things simply didn't work. They also contained code that was unrelated to DNS tunneling traffic.
I spent some hours to clean up the OzimanDNS scripts by doing the following things:
- fixed code indention
- fixed most warnings with
use warnings
- fixed bugs (like non working listen option in the daemon, or the messed up resolver settings in the client)
- cleaned usage notices
- renamed some option switches (was needed to avoid name collisions)
- removed all unneeded code (like storing data in the DNS server) – less code, less potential flaws
- added privilege dropping after opening port 53
- added init scripts
You can download the whole thing here: dnstunnel.tgz
Read on for a quick guide how to use it.
Setting up a DNS Tunnel Web-Proxy
The goal is to use SSH's builtin Socks proxy to be used with Firefox to tunnel all traffic through DNS requests only.
Here's what you need:
- The tarball above
- Control over a DNS server
- If you run your own – good, but see below
- Maybe your ISP gives you enough control in a WebGUI1)
- Ask at dnstunnel.de for a free setup
- A server to set up the daemon
- It can not already run an external DNS service
- You need to have root access
- Perl, a bunch of Perl modules, screen, SSH
- Some Unix and DNS knowledge helps as well
DNS Setup
For making DNS tunneling work we'll setup our own DNS server that has to be authoritative for a given (sub)domain. Let's assume we have our own root server running at www.example.com
using the IP 123.123.123.123
. That box also will run our tunnel daemon. Our new subdomain for DNS tunneling should be tunnel.example.com
.
This means we have to setup DNS delegation for that subdomain on the nameserver that is responsible for example.com
. In Bind this can be done using something like this:
tunnel.example.com. IN NS www.example.com. www.example.com. IN A 123.123.123.123
All DNS requests for *.tunnel.example.com
will now go to the IP 123.123.123.123
.
Server Setup
On to the server at www.example.com
. Here you should install a few needed software packages first. The following should suffice on Debian:
#> apt-get install screen libnet-dns-perl libmime-base32-perl
Then download dnstunnel.tgz and unpack it to /opt/
– creating /opt/dnstunnel
.
Edit the config at the top of the dnstunneld.wrapper
' script. Eg. if you're running a caching DNS on the local interface you may want to bind the tunnel server to the external interface explicitly. You also may want to specify the user and group the daemon will run as. Run dnstunneld
without arguments to get a list of possible options.
Here's an example:
DNSHOST="tunnel.example.org" REPLYIP="127.0.0.1" OPTIONS="-l 123.123.123.123 -u nobody -g nogroup"
Now link the init script and start the server
#> ln -s /opt/dnstunnel/dnstunneld.init /etc/init.d/dnstunneld #> /etc/init.d/dnstunneld start
A DNS lookup for foo.tunnel.example.com
should now return 127.0.0.1
.
Client Setup
On the laptop, we need libnet-dns-perl
and libmime-base32-perl
again. Then copy the dnstunnelc
script somewhere in your PATH. I suggest /usr/local/bin/
.
To test the connection let's try to login via SSH using the tunnel client as proxy:
$> ssh -C -o ProxyCommand="dnstunnelc -v sshdns.tunnel.example.com" you@localhost
Notice the sshdns
bit? The tunnel daemon will only answer with tunnel replies when this is set. You can change the name on the server with the -f
option. The secrecy of the DNS name is the only “authentication” for the tunnel it self, so choose wisely.
Of course the access to the box behind the tunnel is protected by the usual SSH mechanisms. Notice the use of localhost
? That localhost
refers to the tunnel server of course, because when SSH arrives at the end of the tunnel it is localhost
already.
Now if everything works, you can use SSH to open a Socks proxy:
$> ssh -D 8000 -N -C -o ProxyCommand="dnstunnelc sshdns.tunnel.example.com" you@localhost
Refer to my Conference WiFi Security article on how to set it up with Firefox.
Run the dnstunnelc
script without any arguments to learn about a few more options. It has some interesting mechanisms to spread your DNS requests over many DNS servers.
PS: Circumventing access restrictions with this method might be illegal depending on where and what for you use it. Use it at your own risk.