Using Bro for building Passive DNS data

Passive DNS

Passive DNS describes an historical database of DNS resolutions. I’ve written a previous post on Using Passive DNS for Incident Response, more specifically combining it with Moloch.

If you run your own corporate -internal- nameservers it makes sense to monitor what domains have been queried and what results were returned in the past. You can use the collection of internal queries for future incident response. You can use this collected information to cross-check with information that you gathered from intelligence feeds or for example via your internal MISP instance.

Using Bro for passive DNS

There are different ways for gathering passive DNS data. The method I describe is via Bro. Bro is network analysis framework that can be extended with different plugins.

The bulk of information in this article comes from a post Building Your Own Passive DNS Collection System, I added some additional configuration notes.

Prepare the system

I installed Bro on an Ubuntu 12 (note that the this is not the latest Ubuntu) version. Bro requires some additional packages that can be easily installed.

sudo apt-get update
sudo apt-get upgrade
sudo apt-get install cmake make gcc g++ flex bison
sudo apt-get install libpcap-dev libgeoip-dev libssl-dev python-dev zlib1g-dev libmagic-dev swig2.0

Next thing we have to do is download Bro, import the GPG key of Bro and verify the package. The GPG verification step is optional but assures you that you have a legitimate version of Bro, you verify the package signature that was signed with the Bro GPG key.


wget -O bro.key ""
gpg --import bro.key


gpg --verify bro-2.4.1.tar.gz.asc bro-2.4.1.tar.gz

The last command should return output containing

gpg: Signature made Sun Sep  6 21:44:21 2015 CEST using RSA key ID 6F9AD2A2
gpg: Good signature from "The Bro Team <>"

Now extract the Bro package, run the configure file and build the package. Note the prefix argument, this defines where Bro will be installed on your system.

tar zxvf bro-2.4.tar.gz
./configure --prefix=/nsm/bro
sudo make install

Bro needs to watch a network interface in order to get the necessary data. Defining what interface to monitor is done in a configuration file node.cfg.

vi /nsm/bro/etc/node.cfg



In order to store the passive DNS data we will also need a database. We’ll use mysql. I assume you already have mysql installed. If not you can do this via

sudo apt-get install mysql-server python-mysqldb

If you already have mysql installed you need to add an extra database, preferably with a dedicated user. Log in to mysql and create the database and user.

create user 'pdns'@'localhost' identified by 'pdns';
create database pdns;
grant all privileges on pdns.* to 'pdns'@'localhost';
flush privileges;

Get the pdns package

The next step is getting the pdns module for Bro and installing it. First we need to prepare the system. I assume you already have pip installed (if not, install it as ‘python-pip’). Next install the bottle package.

pip install bottle

Continue with installing SQLAlchemy

sudo apt-get install python-sqlalchemy

The pdns package is available from Github. Once downloaded it has to be moved inside the Bro folder.

git clone
mv bro-pdns /nsm/bro/share/bro/site/

We now have to make Bro aware of the new module and the configuration settings. Open the configuration file local.bro and add the database connection.

vi /nsm/bro/share/bro/site/local.bro

@load ./bro-pdns
redef PDNS::uri = "mysql://pdns@localhost/pdns";

Starting Bro

Now that all the configuration is done it is time to start Bro.

[BroControl] > install
[BroControl] > start
[BroControl] > status

Getting process status ...
Getting peer status ...
Name         Type       Host          Status    Pid    Peers  Started
bro          standalone localhost     running   18624  0      05 Sep 23:10:46

The above indicates that Bro was successfully installed and started. You can exit the Bro console with quit.

DNS logging in Bro

The first thing you now have to do is check the Bro logs for the DNS queries that were captured on the monitored interface. You can do this easily with a tail of the log.

tail -f /nsm/bro/logs/current/dns.log

The next step is to use the Bro module for pdns to parse the DNS logs.

BRO_PDNS_DB=mysql://pdns:pdns@localhost/pdns /nsm/bro/share/bro/site/bro-pdns/ process /nsm/bro/logs/current/dns.log

The number returned (241) is the number of records processed.

If you now use mysql to look what’s inside the database you will have an overview of the data that was gathered.

mysql> select * from dns;
| query                           | type | answer                       | count | ttl    | first               | last                |
|           | -    |                |     3 |     26 | 2016-09-05 23:20:27 | 2016-09-05 23:20:27 |
|           | -    |                |     3 |     26 | 2016-09-05 23:20:27 | 2016-09-05 23:20:27 |
|               | -    |               |     1 |     30 | 2016-09-05 23:17:45 | 2016-09-05 23:17:45 |

The mysql interface is not a very convenient way to look at the data. There’s a web interface that you can use that returns JSON. Start the interface with

BRO_PDNS_DB=mysql://pdns:pdns@localhost/pdns /nsm/bro/share/bro/site/bro-pdns/ serve

and then query for a record via curl

curl http://localhost:8081/dns/

{"records": [{"count": 2, "last": "2016-09-05 23:11:04", "ttl": 3600, "answer": "", "query": "", "type": "-", "first": "2016-09-05 23:11:04"}]}


The above process describes how to gather passive DNS data from the DNS queries in your environment but it still has some rough edges.

The processing of the logs is not something that you’d like to do manually. So ideally you run the process from cron. You can put it in a cron job. One note on delay. If you do a query on a machine with less resources it might take some time (1 / 2 seconds) before it shows up in the DNS log of Bro. This is something to take into account if you are doing live debugging. You should allow Bro the necessary time to process the request and output the log file.

The JSON output is ideal for further processing, it’s an easy to parse format. If you are using MISP you should be aware of its MISP module feature (see where you can enrich information of attributes in MISP with external information. One of the next steps that you could take is write a module that queries your local passive DNS database to check if a domainname attribute from MISP is seen in your queries.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.