Security

Bypassing Firewalls with DNS Tunneling: Testing Five Popular Tools

When a firewall has completely cut off network access but you absolutely need to transfer data, DNS tunneling can come to the rescue. Even under the strictest settings, DNS queries sometimes still get through, and you can leverage that by replying from your own server on the other side. The connection will be extremely slow, but it’s enough to reach into an organization’s internal network or, for example, to quickly get online via paid Wi‑Fi while abroad. Let’s see which tools can help and what pros and cons each of them has.

About the Authors

The authors of this article are penetration testers from the FBK CyberSecurity team. It is part of FBK, one of Russia’s largest audit and consulting groups (Financial and Accounting Consultants). The company specializes in applied cybersecurity services.

FBK CyberSecurity’s work includes:

  • Penetration testing
  • Digital forensics and incident response
  • Compliance and audits for PCI DSS and SWIFT security standards
  • Hardware security (ATMs, IoT, etc.)
  • IT audit and IT consulting
  • Smart contract audits and security for ICOs

You might also have read articles in Hacker magazine written by one of FBK CS specialists and a co-author of this piece.

Here’s the overall diagram that illustrates what we’re going to do. The theory is straightforward: even when egress is blocked, requested URLs still have to be resolved, so DNS is often left unrestricted. That leaves a narrow but usable loophole.

You can now find plenty of tools online for exploiting this technique—each with its own features and bugs. We selected the five most popular ones for a comparative test.

dnscat2

dnscat2 is a popular tool by Ron Bowes for establishing a command-and-control (C2) channel over DNS. It includes a Ruby-based server and a C client. There’s also a Windows PowerShell client.

dnscat2 encodes data in hexadecimal. The data is transmitted sequentially; for example, the value AAAA is equivalent to A.AAA, AAA.A, and so on.

The protocol is case-insensitive, meaning a1 and A1 are the same. To use the tool, you need a server you control with a domain whose NS records point to that specific machine. The client can choose whether to include the domain name or add the dnscat. tag to the message when sending data.

Messages are encoded as <encoded data>.<domain> or <tag>.<encoded data>. If the data is formatted differently, uses an unsupported record type, or the domain is unknown, the server may discard it or forward it to an upstream DNS server.

Dnscat2 supports the common DNS record types: TXT, MX, CNAME, A, and AAAA. The response type matches the type of the incoming query:

  • TXT answers — hexadecimal values.
  • CNAME and MX are encoded the same way as the query: either with a tag prefix or by appending the domain. This is necessary because intermediate DNS servers won’t forward the traffic unless the name ends with the corresponding domain.
  • A and AAAA — likewise. For TXT, the data is sent without appending the domain or the tag.

The dnscat2 Protocol

A session is initiated by the client sending a SYN packet to the server, which replies in kind. The client and server then exchange MSG packets. When the client decides to close the connection, it sends a FIN to the server, and the server responds likewise. If the server decides to terminate, it replies to the client’s MSG with a FIN, and the session ends.

Notably, the dnscat2 server can handle multiple sessions and supports basic cryptography, though without any guarantees about its security.

For more details on the protocol and the tool’s specifics, see the page in the developer’s repository.

Launching

Following the GitHub instructions, we’ll build everything we need and try to run it. First, on the server we’ll monitor what’s happening on port 53. To do this, run the following command.

Now let’s start the server. We’ll pass only the domain name as an argument, since the direct-IP case is out of scope for us.

Similarly, launch the client and verify that the session is established. Great—looks like it’s working!

On the server, we observe the following.

Great, let’s start the session.

Let’s see what the utility provides.

Great! To verify, let’s start a shell.

Great! The shell session is up, even though we got “bad sequence” instead of a banner. To suspend the session, press Ctrl+Z and switch to session 2.

Create a file, write text to it, then display its contents and delete it.

After the output shows up, you have to press Enter once more to type the next command. It’s not interactive, sure, but it’s no big deal.

That’s all well and good, but we need to get the tunnel up. Let’s try pulling a file over SCP from some server via the client and, while we’re at it, measure the average throughput. Bringing up the tunnel.

In the client session, we configured the server to listen on port 9090 and forward the client’s traffic to 178.128.34.53:22. Now let’s start SCP. In tcpdump, you can observe the client’s communication with the server.

We ended up with an average throughput of 0.8 KB/s—4K movies are obviously out of the question, but we did manage to tunnel the traffic.

Let’s take a look at the boot process.

As we can see, even though the transfer rate was only about 10 KB/s, the utility ended up running for quite a while.

We previously ran the client on Kali; now let’s see how it performs on Windows. The outlook isn’t good. In the same test, the client eventually established a connection, but only after an excessive number of attempts.

However, any attempt to tunnel SCP caused the client to disconnect unexpectedly.

I couldn’t even measure the average connection speed. The client was tested on Windows 7 and 10 with identical results.

Finally, let’s take a look at the PowerShell client. To do this, you’ll need to restart the server with the --no-cache flag. In the end, we managed to get the client running and even have it talk to the server for a while.

There was even one time when it turned out like this.

However, in most cases this led to the situation shown in the screenshots below.

Summary

  • Easy setup
  • Rich feature set
  • Multi-session support
  • Clients can be compiled
  • Unstable on Windows (if you can even call it “working”)
  • Download speed ~0.6–0.8 KB/s
  • Upload speed ~10 KB/s, but with a weird delay

Iodine

Iodine is a utility developed by Erik Ekman. It lets you tunnel IPv4 traffic over DNS using virtual interfaces. It consists of a compiled server and client written in C. Iodine clients must be run with root privileges, but can run on multiple architectures (ARM, IA-64, x86, AMD64, SPARC64) across many OSes: Linux, FreeBSD, OpenBSD, NetBSD, macOS, and Windows (with the OpenVPN TAP32 driver).

Server installation

To install Iodine on the server, simply run the following command:

$ sudo apt-get install libz-dev && git clone https://github.com/yarrick/iodine.git && cd Iodine && make && make install

Here’s the command to start the server:

$ sudo ./iodined -f -c -P secretpassword 172.17.0.1 oversec.ru

Starting the client

To get started with the client, write something like:

$ ./iodine -f -P secretpassword oversec.ru

A virtual interface named dns0 has now appeared on the client, and the client will obtain an IP address. You can connect to that IP, and the traffic will be routed over DNS.

Let’s try connecting over SSH.

$ ssh root@172.17.6.2

It works! Here’s what tcpdump shows on the Iodine server’s port 53.

Iodine can automatically choose the fastest available encoding (Base128, Base64, Base32) and DNS record type (NULL, TXT, MX, CNAME, A), which yields relatively high throughput—around 10 KB/s when using SCP.

Let’s test the Windows client. To do this, first install the TAP/TUN interface drivers. Then launch the application—just like on Linux—with an administrator account.

dрай­веры интерфей­са TAP/TUN

The interface seems to come up, but when I try to send data, nothing happens.

In short, attempts to run the Iodine client on Windows were unsuccessful.

We’ll test upload and download speeds.

As we can see, the DNS tunnel performs excellently: 9.8 KB/s for both upload and download over SCP.

Summary

  • Automatic selection of encodings and packet types
  • Requires root privileges to run
  • Client must be compiled from source
  • Requires driver installation on Windows (and it’s questionable whether it works there at all)
  • Download speed ~9.8 KB/s
  • Upload speed ~9.8 KB/s

dns2tcp

dns2tcp is a tool for tunneling TCP over DNS. Both the client and server can be built from source, and the server is also available via APT. Its distinguishing feature is that it tunnels traffic from the client to the server.

Getting started

Let’s start by setting up the server. First, edit the /etc/dns2tcpd.conf file.

Now let’s start the server with the following command:

$ dns2tcpd -f /etc/dns2tcpd.conf

Okay, now let’s move on to the client.

Here we specified that we’ll be forwarding SSH (there’s an SMTP mode as well), set the port we’ll connect to, and the domain. Let’s go ahead and download the file.

While we’re at it, let’s also check the export.

Summary

  • Server and client can be compiled
  • Operates in inbound network pivoting mode
  • Average download speed ~5 KB/s
  • Average upload speed ~13 KB/s

Heyoka

Heyoka is a utility written in C, with the client and server packaged as the same executable. It creates a bidirectional DNS tunnel. According to the authors, it runs about 60% faster than comparable tools (as of 2009). The project site offers a prebuilt Windows binary, while the Unix version on GitHub was produced by a third-party developer.

Getting started

After reading the description and instructions on the site, let’s put this thing through its paces. We’ll start by launching the server on a Windows 10 machine.

Great, looks like it’s working. Now let’s start the client.

Uh-oh! Looks like it didn’t work, even though we ran it with administrator privileges. Fine—let’s build the tool for Unix instead. Start the server the same way and test the client.

Bottom line

Following the developer’s instructions, we still couldn’t get the client to run, and making sense of the source code and the protocol would take some serious heavy lifting. Since we don’t drink at work, let’s move on to the next tool.

OzymanDNS

An old-school tool for creating DNS tunnels over SSH, written by Dan Kaminsky back in 2005.

Getting started

To get started, install Perl along with the MIME::Base32 and Net::DNS libraries, and make sure your package manager is up to date.

$ sudo perl -MCPAN -e shell
cpan[1]> install CPAN
cpan[2]> reload cpan
cpan[3]> install MIME::Base32
cpan[3]> install Net::DNS

Download and extract the archive.

$ wget https://github.com/mubix/stuff/blob/master/stolen/ozymandns_src_0.1.tgz?raw=true
$ tar -xf ozymandns_src_0.1.tgz?raw=true

If you run the script now, it will most likely crash with an import error. To fix it, remove the highlighted section from the nomde.pl file.

Starting the server is straightforward:

$ perl ./nomed.pl -i 0.0.0.0 oversec.ru

If you run into import errors, try installing the missing modules from CPAN.

Launch the client.

$ ssh -D 8080 -C -o ProxyCommand="perl droute.pl lol.oversec.ru" oversec.ru

We’re seeing an error: Perl isn’t happy with the DNS server addresses. Let’s try specifying our own.

$ ssh -D 8080 -C -o ProxyCommand="perl droute.pl -r 138.197.178.150 lol.oversec.ru" oversec.ru -v

We can see the server is consuming resources, but no connection was established.

After watching articles and videos where everything looked flawless, we spent several days wrestling with OzymanDNS and still couldn’t get it to transmit even a single bit. Maybe some readers will have more patience—but is it worth it? The person who managed to connect through OzymanDNS reported around 17 kbps and unstable operation, and given the limited feature set, you might as well move on to something else.

Results

So, we’ve covered the most popular tools for DNS tunneling. This is by no means an exhaustive list, and you can find plenty of alternatives online if you look. Still, there’s already plenty to choose from.

Name Incoming speed, KB/s Outgoing speed, KB/s Pros Cons
dnscat2 0.7 10 Easy setup, rich feature set, supports multiple sessions Clients must be built from source, unstable on Windows
Iodine 9.8 9.8 Automatic selection of encodings and packet types, high performance Requires superuser privileges to run, client must be built from source, needs driver installation on Windows
dns2tcp 5 13 None found Client must be built from source, only supports inbound network forwarding
Heyoka NaN NaN None found Difficult to launch
OzymanDNS NaN NaN None found Difficult to launch

As a result, the most common pain points are the need to build the client from source and its unstable behavior on Windows. Is there any way around this?

But we’ll talk about that another time. 🙂

it? Share: