DNscat logo-

© 2004 Tadeusz Pietraszek

DNScat

DNScat (pronounced "D-N-S cat") is a "swiss-army knife" tool to tunnel traffic through DNS servers. It provides a bi-directional communication through DNS servers, and in conjunction with PPP, can be used to set up a virtual private network (VPN).

DNScat, like a swiss army knife can be used for a variety of purposes, including:

  • penetration testing of networks behind firewalls
  • sending messages though firewalled networks
  • setting up a VPN though firewalled networks
  • learning how to detect covert channels through DNS servers
  • and more...

The idea of DNScat was started by NSTX, which performs IP tunnelling over DNS. The functions of the above programs are similar, although they differ in many design and implementation issues. Please refer to this section for a closer comparison.

DNScat is a small program, written in the spirit of Unix tools: small, command line, flexible, highly configurable and thus powerful. On the other hand, DNScat is written in Java and uses several open-source libraries, thanks to which DNScat has extremely small footprint and its source code is easy to understand.

NOTICE: before you continue any further, please note that the use of DNScat may be against the policy of your network. Please make sure with your network administrator, that installing DNScat does not violate them. You are authorized to use DNScat for educational purposes only. The author of DNScat takes absolutely no responsibility for any misuse of DNScat.

News

31.10.04

DNScat is released into the wild!

Download

DateVersionFileComments
31.10.040.01dnscat-0.01.tar.gz (@ sourceforge)Initial release
27.08.050.02dnscat-0.02.tar.gz (@ sourceforge)Minor bug fixes

Installation

Prerequisites

First things first, to be able to run DNScat you need the following components:
  1. Java1.4+ - DNScat uses nio library which only exists in Java1.4. No, it won't work with older versions.
  2. Ant - the build system
  3. Unix like system - actually DNScat should be able to run on any system with Java, however, if you want to to IP tunnelling, you will need a system on which you can run pppd.

DNScat uses the following open-source components. The runtime versions have been included in DNScat distribution jar file, so you don't need to have them installed. However, please feel free to download the newer version (note that in this case you may need to update build.xml file).

  1. DNSJava - An excellent library of DNS classes written entirely in Java
  2. Log4J
  3. Gnu Getopt

Install

To install DNScat, download the archive, untar it (tar xvfz dnscat*.tar.gz). Running ant in the directory should create two shell scripts: DNScatServer and DNScatClient. You can try running them with a parameter "?" to see all available options.

Running DNScatServer

To be able to tunnel traffic though DNS server you need to have a domain delegated to a server. You can either buy one of the domains available on the internet, or get a free subdomain of some domain. For example, to can register a subdomain of .afraid.org at freedns.afraid.org. Note that in this case you need an NS record of such domain to point to the server, on which you will be running DNScat.

In the following paragraphs we will describe how to run DNS server in different configurations. In any case, you will need (at least temporary) root access to the machine.

Machine with no DNS server, DNScat running as root

DNScat as a DNS server needs to be running as root to be able to connect to port 53. This could be the simplest setup (you just need to run ./DNScatServer -o <domain_name>) and the easiest one to check if you got DNS delegation right.

Note, I do not recommend this setup. Running anything as root may lead to the compromise of your machine.

Machine with no DNS server, DNScat running as normal user

To be able to do this, to need to make port redirection to the port DNScat is listening on. In the case of Linux with iptables it will look like this: iptables -t nat -I PREROUTING -p udp --destination-port 53 -j REDIRECT --to-ports <non-privileged port> and running DNScat ./DNScatServer -o <domain_name> -p <non-privileged port>).

Machine with a DNS server (bind), DNScat running as normal user

In this case, you need to add a name delegation in BIND (/etc/named.conf):

zone "<domain>" in {
type forward;
forward only;
forwarders { <ip_address> [port <port>] ; };
};

As you see, you can run the DNS server on a different port (actually, you have to, if you want to run in on the same machine and don't want to do some weird iptables tricks).

Running DNScatClient

DNScatClient can be run using the following command: ./DNScatClient -o <domain_name>, in which case it will use the default DNS server in your network. If you want to prevent it, you can specify the DNS server it will use using option -d <server_name>

and then...

DNScat enables tunnelling of standard input and standard output from client to the server. Before continuing with the next step, please make sure that the basic tunnelling works for you. Now that you have both DNScat client and server running we can see how it can be used to do IP tunnelling.

Tunnelling IP over DNS

DNScat is a flexible tool, which can be used to build setup an IP tunnel using PPP daemon. In this section we describe how to achieve this. Note, that you need to have PPP support compiled in the kernel and root access on both client and server machines to complete the setup.

Simple setup - no authentication, running as root

Server side: pppd persist noauth nodetach silent 10.0.0.1:10.0.0.2 pty "./DNScatServer -o <domain_name>"

Please note that both client and the server terminates if any of the sides has closed the connection. Therefore you may want to add persist option for the server, or run it in a loop.

Client side: pppd noauth nodetach pty "./DNScatClient -o <domain_name>"

If everything works fine, you should be able to connect to the server at address 10.0.0.1 and to the client at address 10.0.0.2. To terminate the connection, kill the PPP daemon of DNScat on any of the ends.

Complex setup - with authentication, not running as root

To be able to run IP tunnelling not as root, you need DNScat server running on a non privileged port (how to do this is explained in the section installation). Second, you need to be able to run PPP as non-root.

First things first, you need to add the user you're running pppd as to a group which is allowed to run pppd (group dip in Debian). This should allow you to run PPP as non-root, but will also require to use the authentication.

If you really don't want the authentication (which I do not recommend, you can edit the file /etc/ppp/peers/<somename> and put noauth (and all the remaining options including the the execution of DNScat) there. You then need to call pppd with call <somename> option.

As an alternative you may want to enable authentication. I use authentication with MS-CHAP-V2. What you need to do is:

  1. Edit /etc/ppp/chap-secrets and append the following line * * <password> * setting the password authentication. You should edit these files on both client and the server, so that the client and server can mutually authenticate. Make sure that the file is only readable by root.
  2. Run PPP with the following options on the server: /usr/sbin/pppd persist nodetach silent 10.0.0.1:10.0.0.2 require-mschap-v2 refuse-pap pty "./DNScatServer -o <domain> -p <non-priv port>"
  3. Run PPP with the following options on the client: pppd nodetach require-mschap-v2 refuse-pap pty "./DNScatClient -o tadekp.afraid.org"

Note that this setup ensures mutual client-server authentication, but the traffic itself is not encrypted. This means that you should assume that all the data you transfer is known to the eavesdropper. If you want all your traffic to be encrypted as well, you need MPPE - (require-mppe-128 on client and server). Unfortunately, this is not a standard option in the kernel and you need to patch and recompile the kernel to use it.

Documentation

Runtime options - DNScatClient

DNScatClient reads configuration options from a property file DNScatClient.properties and then from the command line. Some options are obligatory, if they are not set anywhere, the program will terminate. Property file is in the JAR file and is loaded using the default class loader. If you write your own property file, you can override the default one by prepending your directory to the classpath.

Runtime OptionProperty NameDescription
-o <domain name>DOMAINSetting the domain name DNS server will be using. It has to be the same on both client and the server.
-d <dns server>DNS_SERVERDNS server to send requests to. If not set, DNScat will try to detect and use the system default DNS server.
-p <dns port>DNS_PORTThe port to send requests to. Unless testing DNScat I would not recommend to change it to something else than 53.
-r <retries>DNS_RETIRESHow many times each packet is sent before giving up.
-t <timeout>DNS_TIMEOUTTimeout for DNS reply (s).
-L <send delay>DNS_DELAY1If there's no data to transmit from the client to the server, the client will periodically poll the server to enable back traffic. This delay defines how frequently the client polls the server (ms).
-l <send delay>DNS_DELAY2This is the minimal delay before sending each DNS request, when there's data to be sent from the client or the client knows that the server has more data to send.
-AAQUERYDetermines that the server uses A query instead of CNAME. This can be a bit slower with some DNS proxies, but probably easier to detect.
-iIGNORE_TIMEOUTSDon't terminate even if the server is dropping packets.
-s <buffer size>BUFF_SIZEThe buffer size to of requests. These buffers should be the same for client and the server. There's no checks if the total frame does not exceed DNS frame size (512 bytes), so be careful.
-S <send prefix>SEND_PREFIXA prefix to identify sent and received frames. Must be the same on both client and server and may not be a suffix of RECV_PREFIX
-R <recv prefix>RECV_PREFIXA prefix to identify sent and received frames. Must be the same on both client and server and may not be a suffix of SEND_PREFIX

Runtime options - DNScatServer

DNScatServer reads configuration options from a property file DNScatServer.properties and then from the command line. Some options are obligatory, if they are not set anywhere, the program will terminate. Property file is in the JAR file and is loaded using the default class loader. If you write your own property file, you can override the default one by prepending your directory to the classpath.

Runtime OptionProperty NameDescription
-o <domain name>DOMAINSetting the domain name DNS server will be using. It has to be the same on both client and the server.
-i <interface address>INTERFACEInterface on which listen to, if not given, the default one 0.0.0.0 will be used.
-p <dns port>DNS_PORTThe port to receive requests from. The default one (53) requires root privileges, so if you want to avoid it, you can run DNScatServer on some non-privileged port and redirect DNS requests using an appropriate iptables rule.
-iIGNORE_TIMEOUTSDon't terminate if the server received out of sync data.
-aAUTHORITATIVEDetermines if the response is authoritative (authoritative record has to be set).
-A <authoritative_data>AUTHORITATIVE_DATAAuthority record, if authoritative replies are enabled. The record needs to be in the following format: 3600,ns1,root,20041031,86400,7200,604800,0
-I <ip_address>IPIP address to generate for A queries. The value does not matter, but you can set it nonetheless. The default value 0.0.0.0 means that the IP address will be generated randomly with each reply.
-t <ttl>TTLTTL value to set for each record. Small values (0 = no cache) are ok, but can make anomaly detection easier. Large values make DNS servers cache the reply (performance!) and can mess things up if the DNS server is restarted. Use with caution.
-c <timeout>TIMEOUTNumber of seconds after which the server terminates if it has not received any valid requests (0== don't terminate). Note, that the server waits for the first valid request infinitely.
-s <buffer size>BUFF_SIZEThe buffer size to of requests. These buffers should be the same for client and the server. There's no checks if the total frame does not exceed DNS frame size (512 bytes), so be careful.
-S <send prefix>SEND_PREFIXA prefix to identify sent and received frames. Must be the same on both client and server and may not be a suffix of RECV_PREFIX
-R <recv prefix>RECV_PREFIXA prefix to identify sent and received frames. Must be the same on both client and server and may not be a suffix of SEND_PREFIX

How does it work?

The idea is very simple. If you own a DNS server, let's say server.com, any DNS requests to something.server.com will be transmitted to this server. That means that the client can communicate a message something to the DNS server.

The reverse communication is a little bit more tricky. Since DNS server is a request-response, communication, the server cannot send messages to the client directly. Therefore client has to implement polling, that is periodically send some messages, even if there is no data to be sent. This way bidirectional communication can be implemented

Another problem is that the standard response to an A type of query contains just an IP address, that is 4 bytes. This is not the most efficient way of communicating long messages. DNScat transmits data slightly more efficiently, by means of CNAME records. It is still not too efficient, but is absolutely standard and very similar (only slightly longer) to legitimate DNS traffic. A single message exchange can transmit approximately 150 bytes of data in both directions simultaneously.

The communication client-server communication looks as follows:

Client: Query: Type="A" Query="data_from_the_client.domain.com"
Server: Response: Query="data_from_the_client.domain.com"
                  Response="data_from_the_client  = CNAME data_from_the_server.domain.com"
                  Response="data_from_the_server = A "some IP address"

As you can see the actual A record is not used at all. Therefore the a client could ask directly for a CNAME record:

Client: Query: Type="CNAME" Query="data_from_the_client.domain.com"
Server: Response: Query="data_from_the_client.domain.com"
                  Response="data_from_the_client  = CNAME data_from_the_server.domain.com"
The second version is slightly more efficient (less redundant), but also easier to detect, because normal DNS clients rarely ask for CNAME records directly. DNScat can ask for both of these types of records.

Detecting and preventing the use of DNScat

If you're a network administrator, you may want to configure your network in a way to prevent DNScat-like programs from transmitting data. This paragraph describes ways to prevent the use or detect the use of DNScat.

Preventing covert channels through DNS

Does is really matter? There are numerous ways to set up a covert channel in normal networks and DNScat is not the most efficient of them all ;-) Make sure that all other network services, including HTTP are blocked and there is no way of sending packets from your secured network to the outside world. This also includes HTTP traffic, even with the use of transparent proxies - you can easily imagine someone transmitting data in HTTP requests and replies).

Now that there's no way of transmitting data from your protected network to the outside world, it probably does not make sense to be asking queries for an external DNS server. In case of bind, you can do this by either removing or setting an appropriate acl for the following line in named.conf:

zone "." {
				type hint;
				file "root.servers";
};

Another scenario where you may want to prevent DNScat is when the network requires some kind of authorization before allowing outgoing traffic. As in this case the firewall allows selective access to the outer network based on some criteria (e.g., IP or hardware address), the obvious solution would be to block DNS access as well. If the DNS access is required in the blocking state, the requests should be redirected to a restricted (see above) DNS server, if the client is not authorized to access the network.

If you want to redirect your clients to some kind of a webpage (e.g., requiring payment), blocking DNS request completely is not a good idea. In this scenario, you probably want to have the DNS lookups to be performed correctly (just in case the client caches them and, after making the payment, the user still gets the "redirected" webpage) and have a transparent proxy making the redirects. In this scenario, I would suggest two alternatives:

  • Perform "DNS proxy and filtering" - by limiting DNS replies to a single "A" record (even if the server returns something else, like a CNAME and an A) will ultimately limit the usable bandwidth to 4 bytes per request rendering covert channels using DNS useless. If you are paranoid, you may also limit the bandwith of DNS queries to, let's say, 5 requests per second.
  • Faking DNS responses with TTL 0 - for any DNS query return some bogus IP address with TTL equal to zero. This should ensure that the client makes the DNS query each time it wants to make a request (may not work with some "smart" browsers).

Detecting covert channels through DNS

If preventing covert channels is not possible, you may want to build a simple detector to check if people are using DNS server. The possible strategies would include:

  • detecting unusual and malformed DNS packets (DNScat will evade this)
  • detecting high number of unusual types of DNS queries (e.g. TXT) (DNScat will also evade this)
  • Anomaly detection: DNS query and response length
  • Anomaly detection: profiling the amount of traffic per client source IP address

The last one can easily be done using tools such as ntop

Contact

Tadeusz Pietraszek <tadek-at-pietraszek.org>

Acknowledgements

Many thanks to Annie Chen for help with this webpage and to Michal Pietraszek for the logo.

License

GPL. If you're interested in other licensing, please contact the author.

Misc

DNScat and NSTX

If you think the idea of transmitting data through DNS servers is not completely new, you're right ;-) The idea of DNScat was inspired by NSTX, which serves the similar purpose. However, DNScat is different:

  • Written using an open source DNS library - this makes the code simpler and the program more powerful and more extensible. Finally we avoid essentially reimplementing all DNS server functions.
  • Written in a high level language, should limit the problems with buffer overflows and other exploitable vulnerabilities (which you definitely don't want in the program running as root).
  • Can run on any OS (however, tunnelling with PPP is only possible on Linux)
  • Is a generic cat-like program (cf. cat, netcat), not dedicated to do IP tunnelling. It is possible (and intended to run DNS cat in conjunction with PPP daemon). By using properly configured PPP, we achieve the following:
    • better compression for small packets,
    • authentication and access control,
    • automatic configuration of default routes.
  • Does not use TUN/TAP interface, which may not be compiled in your Linux kernel).
  • Uses only standard DNS queries A, CNAME, which makes it more difficult to detect.
  • Is more configurable with command line parameters and properties file.

Troubleshooting

Well, I'm running DNScat and nothing happens

  1. Look carefully. DNScat is a simple, yet powerful, tool. What it actually does is forwarding the standard input of DNScatClient to standard output of DNScatServer and vice versa. If does not have any verbose text output - check if it really does not work.
  2. Try again ;-) It sometimes helps with computer programs.
  3. Try is your domain works: host -a <domain_name>, check if DNScat is responding there host -t A something.<domain_name>
  4. Try sending packets directly to your server running DNScat ./DNScatClient -d <server_address>
  5. Try ethereal on client and server to figure out what is going on.

Valid XHTML 1.0! Valid CSS!VI powered

Last modified: $Id: index.html 54 2005-09-16 09:08:46Z tadekp $