How DNS Tunneling Works
In order to establish communication between two hosts using DNS traffic,
we need to control both ends of the communication:
the client that makes the requests, and the DNS server.
This means that in order to receive the DNS requests generated by the client,
we need to register our DNS server as the authoritative server for a given target
domain, i.e. we need to assign an NS record to our domain.
This typically means that we must purchase a domain and under its
configuration, set the NS record to our DNS tunnel server.
This will cause the DNS server to forward all subdomain requests to our server.
Once the infrastructure is in place, we can communicate between hosts
by encapsulating our malicious data in legitimate DNS packets.
From the client, we can encapsulate data into the name field,
which contains the domain name.
However, since the top-level domain is fixed,
we can only encapsulate data as subdomains.
These can be up to 63 characters long but the total length of a domain
can’t exceed 253 characters.
From the server side, we have much more flexibility and can return data
in a variety of fields based on the record type that was requested.
An “A” record can only contain IPv4 addresses, which means we can only
store four bytes of information, but “TXT” records allow up to 64k.
However, one challenge in C2 communications is that if we want to send
any data from the server to the client,
we can’t initiate the transfer from the server.
Because of this malicious client applications are designed to continuously
poll the server for updated data.
Let’s clarify this with a simple example.
Imagine we want to create a C2 channel in which the server can issue commands
and the client can return the results.
Clients will continuously poll the server for new commands because the server
can’t initiate connections to the client.
The client will execute new commands and send the results via new query messages.
Within these exchanges, we will generally hex-encode our data,
which allows us to transfer custome data.
Let’s walk through the specific steps involved in this example.
First, the client will poll the server.
Here, the numerical string represents the hex-encoded string
of “aretherenewcommands”.
If there is nothing to run, the server will return an empty TXT record.
If there are commands to execute, the server will return the hex-encoded string
of the command to be executed by the client.
For example, to instruct the client to run the “hostname” command,
the server would return this hex-encoded representation:
Next, the client executes the command and captures results.
In order to send the results, it will generate a new DNS lookup
that includes the output of the requested command.
In this case, the response would include the hex-encoded hostname,
“client” in the request.
The client could safely use a single “A”
record lookup in this case due to the short response.
If the response was longer, the client would use multiple DNS queries.
This example is just a demonstration.
Proper tunneling tools account for various issues such as DNS retransmission,
in which the client resends queries because it didn’t receive an answer
in time, or DNS caching, in which the client caches the result of DNS queries.
Full-featured tools can potentially tunnel arbitrary TCP/IP traffic,
as opposed to the simple data in our example, and can also encrypt data.
Now that we understand the basic concepts of tunneling, let’s try it out.