Protecting against malicious payloads over DNS using Azure Sentinel

No matter how tightly you control your network, you probably allow DNS queries and UDP/53 traffic on your network.

Bad actors can abuse this to establish a stealthy command & control (C2) channel and/or exfiltrate data using DNS tunneling.

Azure Sentinel can help detect these types of attacks, and provide insights in the various stages of the kill chain of this attacker.

Delivering a payload over DNS

Samy Baiwir recently published a project on GitHub called DNSlivery that aims to deliver payloads over DNS. It is a lightweight solution built on Python and the Scapy library.

No need for a full-fledged DNS server, DNSlivery will listen on UDP/53 and serve the payload through TXT records. Here’s the GitHub repository:

Use DNSlivery to bootstrap DNS tunneling

How is DNSlivery different from for instance PowerDNS? With DNSlivery there is no need for a client on the target, you can just use native PowerShell in the operating system.

However, this does mean that it is one-way communication. But because it will not touch on disk, it can help bootstrap the next phase of your attack, DNS tunneling:

“Even though more complete DNS tunneling tools already exist (fi: dnscat2 and iodine), they all require to run a dedicated client on the target. The problem is that there is probably no other way then DNS to deliver the client in such restricted environments. In other words, building a DNS communication channel with these tools require to already have a DNS communication channel.
In comparison, DNSlivery only provides one-way communication from your server to the target but does not require any dedicated client to do so. Thus, if you need to build a reliable two-way communication channel over DNS, use DNSlivery to deliver the client of a more advanced DNS tunneling tool to your target.”

Setting up the DNS server

You will of course need a domain name and be able to change and administer the NS records. Point the NS record(s) to the external IP of the machine you’ll be using for this.

Nameserver records
Ubuntu Linux VM

To set up the rogue DNS server itself you need a Linux operating system instance. You will also need Python3 and the right version of the Scapy library (v2.4.0).

DNSlivery makes things easy for you, just run these commands:

git clone https://github.com/no0be/DNSlivery.git && cd DNSlivery
sudo pip install -r requirements.txt

Create a directory on disk that has the file that contains the payload you want to serve over DNS. In this sample we’ll be serving “atp-cat.txt” with an ASCII picture of ATP cat.

Run the following command:

sudo python3 dnslivery.py <eth0> <yourdomain.com> <nameserver.yourdomain.com> -p /path/to/the/payload
PRO TIP: If you’re getting errors that Python can’t load the Scapy module, make sure that sudo has the same environment variables as your current user. If not, use this command to solve that, before your run DNSlivery: alias sudo=’sudo env PATH=$PATH’

Consuming the payload on the target

As mentioned earlier, DNSlivery is different from other solutions in that it does not require a dedicated client. The content can be consumed by Powershell out of the box.

On the target, start by retrieving the launcher of the desired file by requesting its dedicated TXT record. The following three launchers are supported:

Copy and paste the response into the PowerShell console again, to retrieve the payload over DNS:

How can I defend against these types of attacks?

While most companies will have some form of network security solution in place that might already trigger on these types of attacks, Azure Sentinel can also play a role in detecting this malicious intent.

Looking at the Security eventlog on this specific server we find an event with ID 4688 that shows us the execution of the initial ‘dnslookup’:

If we execute a Kusto (KQL) query on the Log Analytics workspace that this agent is connected to, we quickly find the event:

SecurityEvent
| search “nslookup” and “TXT”

Capturing the malicious transfer itself

When we dig further, there is no logged event in the Windows security eventlog on the next stage of the attack that receives the multi-part base64 encoded payload. Because it uses Invoke-Expression (IEX) it does not spawn a new (child) process and therefore no extra event is created in the security eventlog.

However, we can use the DNS client logging in Windows. That is not enabled by default, but enterprises could (and should?) enable this:

You will see the following events appear in the DNS client log:

PRO TIP: Type 16 is the TXT record in DNS. There is a Wikipedia page that outlines all the various types and Type ID’s: https://en.wikipedia.org/wiki/List_of_DNS_record_types

Collecting the Powershell log

Going into Workspace Settings in Azure Sentinel, you will find Advanced Settings of the Log Analytics workspace associated and it will allow you to collect the DNS client log:

It will take a couple of minutes to start gathering and processing this new log, but directly afterwards you can query the data in Kusto format, returning the malicious command:

Event
| where EventLog == “Microsoft-Windows-DNS-Client/Operational”
| where RenderedDescription contains “type 16”

Azure Sentinel

The next step is to create a Case trigger in Azure Sentinel. This can be done through the ‘Analytics’ section:

Here are the properties you can use:

Status: Enabled
Name: Potential DNS tunneling
Description: We've found a large number of DNS queries for TXT records in a short period, which might indicate malicious DNS tunneling
Severity: High
Alert Query: 
Event
| whereEventLog == "Microsoft-Windows-DNS-Client/Operational"
| whereRenderedDescription contains "type 16"
| extend HostCustomEntity = Computer
Entity mapping
- Account: <empty>
- Host: Computer
- IP address: <empty>
Operator
- Number of results greater than: 5
Alert Scheduling
- Frequency: 5 minutes
- Period: 5 minutes
Alert suppression: On (for 60 minutes)

PRO TIP: make sure you map the entities as part of the rule creation — this is a very important step since this will enable the investigation experience that will be released soon as part of Azure Sentinel!

The wizard has an Alert simulation feature that shows you if the specified query and scheduling properties will return events and if they will “meet the bar” (red line):

Azure Sentinel cases

Now that we created an advanced alert rule in Azure Sentinel, it will generate cases that you can assign and use to deeply investigate:

A case can include multiple alerts. It’s an aggregation of all the relevant evidence for a specific investigation:

PRO TIP: clicking the number under “Hits” (in this example: 110) will bring you to the actual query to see the events that triggered the detection.

In the Entities tab, you can see all the entities that are involved:

Conclusion

A potentially better approach for enterprises is to block DNS / port 53 traffic at the edge by default. This ensures that all port 53 traffic has to go out via the corporate DNS servers, providing a central point for logging. At that point it is sufficient to do centralized logging on the DNS server itself.

Without central logging, or if you do allow DNS traffic at the edge, client-level logging is valuable for detecting DNS tunneling attacks. Client-level logging also means you directly get the name of the impacted host in the logs, which is an added value for Threat Hunting.

While DNS client logging wasn’t there out-of-the-box, Azure Sentinel makes it easy to start detecting the DNS attack vector.

Happy hunting!

— Maarten Goet, MVP & RD