I recently attended the SANS' SEC530: Defensible Security Architecture and Engineering On-Demand course. This course covers various aspects of security tactics and techniques to defend your network. "Think Red, Act Blue."
I wanted to learn more about how to defend a network from DNS exfiltration. To make this exercise more interesting and perhaps beneficial to the security engineer who does not have the budget to get the latest "new-shiny" security solution from your local Value Added Retailer, I imposed some restrictions on myself. One, the solution should be at low or minimal cost. Open source software may be a good fit here. Secondly, it should be simple and straight forward as possible to implement and analyze.
What is DNS exfiltration? It is a tactic to transfer data from a "protected" system to another system that the adversary uses for a repository. The technique used is to transfer the data inside DNS packets. Encapsulating the data inside of DNS packets is often called DNS Tunneling. The reason DNS is used is probably the fact that it is often unlikely to be block, filtered, or monitored by most network administrators.
In my proposed solution, I'll use Suricata (IDS) (https://suricata.io/) for the software which is open sourced. It can be used as an IPS or IDS, but for this I'll use it in IDS mode. For the server, I'll use Fedora Server (https://getfedora.org/en/server/download/). Technologies that will be implemented are the IDS, Suricata, and custom signatures.
I started with a base install of Fedora.
Then, I installed Suricata with: dnf install suricata
I discovered that I had to modify /etc/sysconfig/suricata to match the interface that my virtual machine was using for monitoring the network. For this post, I used a packet capture for the easy of repeated testing and validating the rules that I was creating.
[root@fedora suricata]# cat /etc/sysconfig/suricata
# The following parameters are the most commonly needed to configure
# suricata. A full list can be seen by running /sbin/suricata --help
# -i <network interface device>
# --user <acct name>
# --group <group name>
# Add options to be passed to the daemon
OPTIONS="-i ens192 --user suricata "
Now let's create a custom rule for detecting DNS exfiltration. Since this is my first time with creating a rule for Surciata from scratch, I needed to familiarize myself with the syntax and the rules of the rules. I found that the documentation at Suricata (https://suricata.readthedocs.io/en/latest/quickstart.html) was good and a good place to start for anyone starting to learn about IDSs and creating rules for them.
What I have learned so far is that DNS exfiltration utilizes DNS queries to pass data or information in an encoded way. It appears that one utility used for that, DNScat, encodes its control channel and its data channel using xxx and appear in the form of:
dnscat.adc1034207000000008c65a9a404820a11e6f14a093102e5206ab3805436.44fb3b2ac12f56797ddeb0995cc166e768c1205ba401480977109ac2ddb1.7431c8c4af93f14084417d9715
I noticed that the hostnames and sub-domains are unique in the sense of how they start and the length. The length caught my eye in that all of the domains and sub-domains are not much beyond 8 or 16 characters long. As I learn more, I'll adjust that opinion. So, I create my first rule to look for a DNS query where the query begins with "dnscat" and has sub-domains with 16 characters or more. Since these are custom or local rules, I created a new file for them and added the file to the Suricata configuration file at /etc/suricata/suricata.yaml.
##
## Configure Suricata to load Suricata-Update managed rules.
##
default-rule-path: /var/lib/suricata/rules
rule-files:
- suricata.rules
- custom.rules
[root@fedora suricata]# vi /var/lib/suricata/rules/custom.rules
alert dns any any -> any any (msg:"DNS DGA - possible DNS DGA detected - DNScat"; dns.query; content:"dnscat"; startswith; pcre:"/dnscat\.[a-z-A-Z0-9]{16,}\.[a-zA-Z0-9]{16,}/"; sid:1000001; rev:1;)
Now what if our adversary changes the being to be something different than "dnscat"? My next rule will look for hostnames that are 8 characters or more and sub-domains 16 characters or more:
alert dns any any -> any any (msg:"DNS DGA - possible DNS DGA detected - DNScat"; dns.query; pcre:"/^[a-zA-Z0-9]{8,}\.[a-z-A-Z0-9]{16,}\.[a-zA-Z0-9]{16,}/"; sid:1000002; rev:1;)
Cool. Let's look at what I have so far. I ran my packet capture through Suricata.
[root@fedora suricata]# /sbin/suricata -c /etc/suricata/suricata.yaml -r /root/dnscat.pcap
Now let's look at the results.
[root@fedora suricata]# cat /var/log/suricata/eve.json | jq 'select(.event_type=="alert")' | less
{
"timestamp": "2022-03-15T22:02:29.679222-0400",
"flow_id": 476751120915766,
"pcap_cnt": 1,
"event_type": "alert",
"src_ip": "5.30.5.1",
"src_port": 34336,
"dest_ip": "5.30.5.2",
"dest_port": 53,
"proto": "UDP",
"tx_id": 0,
"alert": {
"action": "allowed",
"gid": 1,
"signature_id": 1000001,
"rev": 1,
"signature": "DNS DGA - possible DNS DGA detected - DNScat",
"category": "",
"severity": 3
},
"dns": {
"query": [
{
"type": "query",
"id": 58118,
"rrname": "dnscat.adc1034207000000008c65a9a404820a11e6f14a093102e5206ab3805436.44fb3b2ac12f56797ddeb0995cc166e768c1205ba401480977109ac2ddb1.7431c8c4af93f14084417d9715",
"rrtype": "TXT",
"tx_id": 0
}
]
},
"app_proto": "dns",
"flow": {
"pkts_toserver": 1,
"pkts_toclient": 0,
"bytes_toserver": 215,
"bytes_toclient": 0,
"start": "2022-03-15T22:02:29.679222-0400"
}
}
I now have an alert in Suricata's logs with all the detail of who, what, where (source and destination), and when.
Just for fun, I'll create another example. This time I created one for another DNS exfiltration tool called dns2tcp. From what I have learned so far is that dns2tcp creates query in the form of:
adc1034207000000008c65a9a404820a11e6f14a093102e5206ab3805436.44fb3b2ac12f56797ddeb0995cc166e768c1205ba401480977109ac2ddb1.=auth.tunnel.domain.tld
adc1034207000000008c65a9a404820a11e6f14a093102e5206ab3805436.44fb3b2ac12f56797ddeb0995cc166e768c1205ba401480977109ac2ddb1.=connect.tunnel.domain.tld
I noticed that the queries contain "=auth" or "=connect". So I created additional rules based on the information and came up with:
alert dns any any -> any any (msg:"DNS DGA - possible DNS DGA detected - DNS2TCP"; dns.query; content:".=auth."; sid:1000003; rev:1;)
alert dns any any -> any any (msg:"DNS DGA - possible DNS DGA detected - DNS2TCP"; dns.query; content:".=connect."; sid:1000004; rev:1;)
Well that was a learning experience. Rather than taking packet captures and processing them later, I would place the Fedora Server with Suricata with one of its interface on a SPAN or mirror port on a switch. This post was more about learning the individual pieces required for a bigger solution. This solution needs a web interface, maybe the ELK Stack (Kibana, Beats, and Logstach), but that is another discussion that is beyond the scope of this post.
This solution is good for a lab and learning the technologies for professional development and possible professional certifications.
This post is not meant for the intermediate for expert threat hunter. I hope that this will inspire the beginner who wants to learn more about IDSs and rules creation.
All in all, I discovered that I have a lot more to learn about Tactics, Techniques, and Procedures (TTPs) to help defend the network, a never ending process.