DNS Packet Tunneling Home

Home | Code | Exhibit | Media

EOH: Original Undergraduate Research
Our project placed 2nd in the Original Undergraduate Research category at EOH, second only to our good friends in SIGMusic with their awesome Tacchi multi-touch music table. We'll be getting all the code ready some time around May 20th. We're sorry for the delays, the system on which our implementation runs is old, buggy, and being replaced.

The goal of this project is to implement a proxy tunnel that passes data through DNS queries and responses. Captive portal networks, as used at airports and by many wireless access point providers, have one fatal flaw, and it is one that can not easily be solved. This hole exists in the DNS system: the network must accept DNS requests and handle them appropriately or it could have devastating effects on users. Because the DNS network is recursive - servers calling other servers until they get an answer - we can gain access to our own hardware in the outside world and send it a payload using DNS requests.

Our implementation is based on the one used by Dan Kaminsky. We use two types of queries in our client: The A requests are used to send data to the server, while another thread sends TXT requests to retrieve data. Outgoing data is encoded to a format that can be fit into a string of subdomains, concatanated with an identifier and then attached to a tunnel domain (ie "t.example.com"). On a real DNS server, this domain is assigned an NS entry that points to our server (ie, ns.example.com, ns. being a standard subdomain for nameservers). When we make our query to the local network's DNS server, it continues to pass the request along, first to find who manages example.com and then to find who manages t.example.com, at which point we have achieved a connection to our own system. Our fake server will read the subdomain, decode its data, and push it to a another server (specifically, an SSH server). The second request type is used to query data back from the server. Our client periodically sends a TXT request with an identifier (containing a random value and an incrementing counter). This reaches the server in the same way as an A request, but the server handles it differently, finding that it is a "down" request (noted by a ".d." in the identifier, as well its "TXT" query type), pulls data from its connection to the proxy server, encodes it, and then puts that data in a series of TXT chunks (raw text data) and sends back its response. If the server has no data to respond with, it will do nothing, so no answer is cached and we can continue to ask for the same identifier (therefore not wasting identifiers on unused requests).

Resources Used
To develop our implementation, we spent significant time reverse engineering the original proof-of-concept code by Dan Kaminsky (as noted in the "Implementation" section). We then found ways to get more data into our requests and responses to improve performance. Our server is written in C using the Poslib library. Our client is written in Python and uses a third-party DNS module combined with a TCP socket server.