Automated Anomaly-Detection in DNS Zones
TL;DR — I open-sourced Dnsbeat, a custom Elastic Beat which periodically parses DNS zones using zone transfers. It supports advanced configurations such as outbound IP address selection, TSIG authentication and fail-over name servers. A proof-of-concept is available.
Are you aware of what happens in your DNS zones? And in the ones of your company? According to the US CERT, attackers have already successfully redirected and intercepted web and mail traffic by compromising name servers. Besides the usual mitigations of credential rotation and 2FA usage, the US CERT advises organizations to audit DNS records. And to do so, I open-sourced Dnsbeat.
The objective of Dnsbeat is to perform regular zone transfers of the monitored domains. All entries of the zone are then parsed and send to the Elastic Stack in order to reflect the state of the zone.
+--------------+ Zone Transfers +---------+ Entry State Events +---------------+
| Name Servers +------------------->+ Dnsbeat +------------------->+ Elastic Stack |
+--------------+ +---------+ +---------------+
Features
A single Dnsbeat instance can monitor multiple zones, each with their completely independent configuration. Each zone supports the configuration of:
- The optional outbound IP address to use for the zone transfer request.
- A list of name servers to contact for the zone transfer, each with an optional configuration of TSIG authentication.
- An optional file path for instances where the zone is recovered through other means (such as Azure PowerShell for Microsoft Azure-hosted zones).
- The polling period as well as different server-related timeouts.
The processing of the entries retrieved by Dnsbeat is fully passive and PAP:RED
-compliant, no ping
, nslookup
or other operations are performed.
Organisations looking at performing PAP:GREEN
or lower actions can configure Dnsbeat to use the Elastic Logstash.
Sending events through Logstash can enrich them through filters such as Geoip
, which locates IPs, and Dns
, which resolves domains such as those referred to by CNAME
entries.
Finally, Dnsbeat ships with multiple default Kibana dashboards, allowing you to start monitoring as soon as results flow in.
Limitations
Some limitations do apply.
Given the working of zone transfers, Dnsbeat must be configured for each zone as, as I far as I’m aware of, there is no such thing as a wildcard transfer.
Additionally, per RFC 5936, all zone transfers must occur over TCP.
This requires the used name servers to allow inbound TCP on port 53
or any other configured port.
Another notable limitation, although this might be implemented at a later stage, is the absence of incremental zone transfers and updates. The current working of Dnsbeat is to reflect the state of the zone, rather than changes made to it. This has the implicit effect that new IoCs can be cross-referenced with the most recent zone states.
A Honeypot as Proof-of-Concept
To demonstrate the usage of Dnsbeat, let’s build a “too permissive” honeypot name server. The objective of this proof-of-concept will be to detect anomalies in the name server’s state.
Architecture
The core architecture we will use is the same as the one we described initially.
A single name server is configured to authorize the outbound transfer of our sample honeypot.local
domain to the Dnsbeat host.
The Dnsbeat host is then itself configured to transfer any monitored domain into an Elastic Stack.
The vulnerability we will introduce is a too permissive allow-update
clause in the Bind9 name server’s configuration, authorizing malicious actors to add and delete records from our zone.
zone "honeypot.local." IN {
type master;
file "/etc/bind/master/db.honeypot.local";
allow-update {
any;
};
};
Readers comfortable with docker-compose
are welcome to play with the final setup, which includes the to-be introduced improvements.
Adding Statistical Analysis
Detecting unwanted DNS states is easy on small zones… but how about large and numerous zones?
The art of statistical analysis can help us identify rare combinations as well as abnormal values. The ee-outliers tool, build by NVISO, is a handy Elasticsearch-based software which allows us to build models to identify outliers. As shown below, ee-outliers regularly polls our Elastic Stack given a base query, computes statistical models and tags outlier records.
Statistical Queries
+---------------+------------------->+-------------+
| Elastic Stack | | ee-outliers |
+---------------+<-------------------+-------------+
Outlier Events
There is an infinite amount of things one can monitor through DNS statistical analysis. The following examples outlines some basic use cases which do apply to most organizations.
To create additional models and fully understand the following samples, take some time to understand the ee-outliers configuration.
Rare Entry
In a typical company, any record change is worth investigating as most DNS records are usually stale.
Some of the exceptions are the widely used RRSIG
records, which must often be rotated, and SOA
record, which should be incremented at each change.
The following statistical model aggregates all stale records based on the event.dataset
field which matches the zone’s domain (honeypot.local.
in our case).
It then flags any record whose event.original
field, which is the zone’s record, is observed in less than 10% of the maximum observed cases.
In short, this model will trigger on any new record which is not of the RRSIG
or SOA
type.
[terms_rare_record]
es_query_filter=NOT dns.type: ("RRSIG" OR "SOA")
aggregator=event.dataset
target=event.original
target_count_method=within_aggregator
trigger_on=low
trigger_method=pct_of_max_value
trigger_sensitivity=10
outlier_type=Rare Value
outlier_reason=Rare Record
outlier_summary=Rare record for '{event.dataset}'
As this model will flag any changed record, alerts generated from it should be considered as a low severity ones.
Rare CNAME Target
Companies often rely on a select set of hosting providers such as Amazon Web Services or Microsoft Azure.
Detecting a variation or anomaly in hosting providers can be done by monitoring CNAME
targets’ second-level domain (dns.rdata.sld
) for rare values.
The following outliers model creates buckets per monitored domain (dns.sld
) and flags any canonical name record’s target (dns.rdata.sld
) which is observed in less than 10% of the most observed cases.
[terms_rare_cname_target]
es_query_filter=dns.type: "CNAME" AND _exists_: dns.rdata.sld AND _exists_: dns.sld
aggregator=dns.sld
target=dns.rdata.sld
target_count_method=within_aggregator
trigger_on=low
trigger_method=pct_of_max_value
trigger_sensitivity=10
outlier_type=Rare Value
outlier_reason=Rare Target
outlier_summary=Rare target '{dns.rdata.sld}' for '{dns.sld}'
Alerts generated from this model should be of medium severity as variations are possible but could also have a high impact.
Rare Mail Entry
Some entries only change exceptionally such as mail exchanger (MX
) records or text (TXT
) records related to email authentication (SPF, DKIM and DMARC).
The following model aggregates all mail-related records based on the event.dataset
field which matches the zone’s domain.
It then flags any record whose event.original
field, which is the zone’s record, is observed in less than 10% of the maximum observed cases.
In short, this model will act as the terms_rare_record
model, only does it monitor mail-related records.
[terms_rare_mail_record]
es_query_filter=dns.type: "MX" OR (dns.type: "TXT" and dns.rdata.txt: ("*spf*" OR "*DKIM*" OR "*DMARC*"))
aggregator=event.dataset
target=event.original
target_count_method=within_aggregator
trigger_on=low
trigger_method=pct_of_max_value
trigger_sensitivity=10
outlier_type=Rare Value
outlier_reason=Rare Mail Record
outlier_summary=Rare '{dns.type}' mail-related record for '{event.dataset}'
Obviously, any alerts resulting from this model should be treated as high severity alerts and be prioritized for investigation.
Sample Results
To exploit the vulnerability in our honeypot, we can use the nsupdate
command which will launch the dynamic DNS update utility.
From there, the server
command will allow us to target the honeypot name server, which in our case is available at 127.0.0.1:5053
.
nsupdate
server 127.0.0.1 5053
Injecting a Mail-Related Record
Lets simulate the injection of a MX
record of higher priority to hijack incoming mails.
update add honeypot.local 300 MX 1 malicious.example.com.
send
After the outliers have executed, which takes up to 1 minute in our proof-of-concept code, you can search for entries whose outliers.reason
is “Rare Mail Record”.
As observable in the following image, our malicious MX
record has been flagged as “Rare Mail Record” as well as “Rare Record”.
Altering a CNAME Record
To test our “Rare CNAME Target” model, lets alter the lorem.honeypot.local
domain to point to a previously unseen target.
update delete lorem.honeypot.local CNAME
update add lorem.honeypot.local 300 CNAME malicious.example.com.
send
After the outliers have processed the zone’s state, you can search for entries whose outliers.reason
is “Rare CNAME Target”.
As observable in the beneath capture, our malicious CNAME
record has been flagged as “Rare CNAME Target” as well as “Rare Record”.
Additional Remarks
Throughout the building of the proof-of-concept, we relied on a trigger_sensitivity
of 10%.
This number has been chosen to work nicely with our zone configuration.
If you are looking to apply the same architecture in production, do not hesitate to fine-tune this number to reach the desired balance between false positives and false negatives.
The proof-of-concept does not cover the alert generation due to the complexity of automating its deployment. Readers looking into integrating the above-generated outliers should have a look at YELP’s Elastalert tool which supports many alerting methods (Email, Jira, Microsoft Teams, Slack, TheHive, …).