Passive DNS data is a good source of threat intelligence. We show in this post how to build such database for your environment using Bro IDS and the ELK stack. The only requirement here is that your bro sensor is seeing all the DNS traffic originating from your local network. You can use Brostash to deploy a Bro based sensor.
The Bro logs for DNS traffic combine in one single entry the queried domain and the corresponding answer. If the query is successful and the domain exists, the log entry includes the IP associated with the domain and the corresponding TTL.
1# Bro DNS log
21515995103.332099 CV4PAq1OLVM2ZhyKC1 10.1.20.100 57357 10.1.20.1 53 udp 15608 3.910198 s1.lemde.fr 1 C_INTERNET 1 A 0 NOERROR F F T T 0 93.184.220.239 60.000000 F
In our Logstash pipeline for processing the Bro logs, we are parsing the DNS logs and storing the resolved IP in the field domain_ips
. In building the passive DNS database, we start first by using the Logstash clone
filter plugin. We apply this filter to any DNS event going through our processing pipeline and where the field domain_ips
exists. Next, we change the logtype
field value and then apply the split
filter on the list of domain answer IP. The output of this filter is a list of new events where we have a one to one association between a domain and an IP. Following the application of this filter, we use the ruby filter to extract from the original event the DNS answer TTL associated with the given domain and IP.
1filter {
2 if ![is_dns_clone] and [logtype] == "brodns" and [domain_ips] {
3 clone {
4 clones => ["logstash-bro"]
5 add_field => { "is_dns_clone" => "true" }
6 }
7 }
8 ...
9 split {
10 field => "domain_ips"
11 target => "ip"
12 }
13 if [ip] {
14 ruby {
15 code => "
16 aa_list = event.get('dns_answers')
17 at_list = event.get('dns_answers_ttls')
18 ll = aa_list.length
19 x = event.get('ip')
20 event.set('ips', [x])
21 (1..ll).each do |i|
22 vv = aa_list[i-1]
23 if vv == x
24 tt_l = at_list[i-1]
25 event.set('ttl', tt_l)
26 break
27 end
28 end
29 "
30 }
31 }
32 ...
33}
In the final step of the log pipeline processing, we use the Logstash mutate
filter to convert the ttl
field to an integer
, replace the value of the field dst_ip
with the domain’s IP and change the document type to logstash-passive
. With the document type change, our passive DNS database will be stored in a new index.
1mutate {
2 convert => { "ttl" => "integer" }
3 replace => [ "dst_ip", "%{ip}" ]
4 replace => [ "type", "logstash-passive" ]
5
6}
With the configuration above, we have now our own Passive DNS database. This database associates with every domain seen an IP, a TTL and a timestamp. The same approach we showed here can be used to build a Passive X509 certificates database. The needed bro scripts and the Logstash filters/patterns are available in our github repositories.