The Bro Blog

Thursday, August 7, 2014

Meet the Bro Teaching Community

We are happy to announce the newly started Bro Teaching Community,
a community project of educators interested in collaboratively
exploring Bro's use as a teaching tool, and sharing experiences and material.
The goal is to create a knowledge base and
resource collection for educators, ranging from example curricula and
slide sets to exercises for all purposes and skills levels.

We invite you to participate in our open discussion every
Tuesday at 10:00 AM PDT. In these meetings we discuss planned curricula,
practical and technical topics around exercises, slide sets, and general
questions related to teaching security, networks and systems with Bro

For details see or contact us directly via info<at>

Tuesday, June 17, 2014

Bro 2.3 Release

We are happy to announce the release of Bro v2.3.  The source distribution and binary packages are available on our downloads page.  For a brief overview of new features and bug fixes you may review our previous blog post about the v2.3 beta.

See NEWS for the preliminary release notes and CHANGES for the exhaustive commit list.

Feedback is encouraged and should be sent to the Bro mailing list.

We extend sincere thanks to all who have helped make this release possible, especially those members of the community who have given us their feedback and support.

The Bro Team

Friday, May 23, 2014

Bro 2.3 Public Beta

We are happy to announce the public beta of Bro v2.3 is available for download! The majority of our development time has been focused on improving performance, reliability, and memory use.

Here is a brief summary of the new features and improvements:
  • Support for GRE tunnel decapsulation 
  • Heartbleed detector on the SSL analyzer 
  • Analyzers for SNMP and Radius 
  • BroControl now supports PF_RING+DNA 
  • File type detection via Bro’s own signature engine instead of external libraries 

See NEWS for the preliminary release notes and CHANGES for the exhaustive commit list.

Feedback is encouraged and should be sent to the Bro mailing list. As we have stated in the past, we do not recommend using a beta release for production use.

Tuesday, April 8, 2014

Detecting the heartbleed bug using Bro

Update: The heartbleed detector is now part of bro master. You should switch if you are still using the development branch. You still have to load policy/protocols/ssl/heartbleed.bro

We just added support to Bro to detect the recent heartbleed attack on TLS servers that are using OpenSSL 1.0.1a-f.

In TLS the payload size of a heartbeat packet and the size of the whole packet is specified in two different places. The heartbleed attack exploits the fact - vulnerable OpenSSL versions return random bits of server memory, when the request packet specified that the payload size is bigger then the size of the whole data packet.

Bro can detect this attack in several different ways. In the simplest incarnation, which is the only one we have seen in the wild so far, the heartbeat message is sent very early, before the TLS encryption kicks in.

In these cases, Bro just compares the payload and message sizes. If there is a mismatch, we know that an exploit has been tried. If the server responds to the message it very probably was vulnerable to the attack.

In theory, the attack also can take place after the TLS encryption started. In this case, we only know the message size, the payload size in the request is encrypted.

In these cases, we use several different heuristics to deduce when an attack is taking place. We count the numbers of heartbeats sent by the client and the server. If there is a divergence of more than a few packets, an attack is likely.

We also check if TLS heartbeat messages are smaller then the minimal length they are required to have, which probably also is only the case in an attack. Furthermore, we check if the encrypted heartbeat packets returned by the server have the same size as the packets sent by the client. If they diverge, the server is returning more data than the client sent in the first place -- which only can happen due to this attack.

To use this detection, you have to use the topic/bernhard/heartbeat branch of Bro. To checkout the branch from our git server, use

git clone --recursive git:// -b topic/bernhard/heartbeat

To enable the heartbeat detection, you have to load the policy/protocols/ssl/heartbleed script. If you use broctl, it will be loaded by default in a new installation using this branch. If using bro on the command line, e.g. to read a trace, you have to specify it directly like this:

bro -r [trace] policy/protocols/ssl/heartbleed

The alerts will be written into notice.log.

Wednesday, March 5, 2014

Dissecting the GnuTLS Bug

Update: we now host a test server at See gnutls command lines below.

The recent  GnuTLS certificate verification bug made it possible to craft an arbitrary certificate in a way that GnuTLS would validate correctly against a given CA root certificate store.

Since we started our SSL Notary service about a year ago, whenever a big SSL or TLS security incident happens, we scan all the certificates we have seen so far to see if they could have been used for an attack. For this bug, we dived into the GnuTLS source, examined the conditions that trigger the bug, and figured how an attacker would exploit the bug. Based on our analysis, we believe that there exist multiple methods to trigger the bug. In the following, we describe one that worked.

Looking at the patch that fixes this bug, we observe that the return codes for error cases were not set properly in a few examples. For example, the function _gnutls_verify_certificate2 performs the actual certificate verification starting at line 465. GnuTLS first attempts to extract the part of the certificate that is signed, the signature, and the signature algorithm. If any of these lookups fail, the verification still succeeds due to missing adjustments of the variable result, which denotes the function return value. On success, the function should return a non-zero value, but the code lacked checks to set the value to zero.

From an attacker perspective, making the signature lookup fail is probably the easiest method to exploit the bug. According to the function _gnutls_x509_get_signature, the signature verification fails if the number of bits in the certificate signature is not divisible by 8. Certificate signatures have an ASN.1 bit string encoding, which theoretically may exhibit an arbitrary number of zeros and ones, and may not necessarily be divisible by 8. But the GnuTLS function assumes a byte-aligned signature, hence the check. In the ASN.1 DER encoding, used in X509 certificates, a bit string begins with a single byte which denotes the number of missing bits in the last byte. For all normal certificates, this value is always zero, and the function continues. But if we change this byte to a non-zero value, the function fails the divisibility check and returns with wrong error code, causing the certificate verification to succeed.

Moreover, we also looked at a few other entry points with the goal to make the signature algorithm verification fail. However, none of them seemed to be as easy to exploit as the signature algorithm.

To trigger the bug, we patched the certificate for, exchanged the private key, and tried to validate it with GnuTLS. Indeed, the verification succeeds with gnutls-certtool and we could establish a secure connection to the server using gnutls-cli.

You can test the vulnerability of your GnuTLS installation by trying to connect to our test server:

    gnutls-cli -p 443 --x509cafile [root store]

You also can test it by downloading the following certificate chain and verifying it using

    gnutls-certtool --verify --infile exploit.pem --load-ca-certificate [root store]

Usually, you can find your operating system root store in /etc/ssl, or you can use our root-store copy. Note that the output of gnutls-certtool is slightly truncated when using a chain that exploits the bug, nevertheless certificate verification (including hostname verification) works.

At the moment we are scanning all the certificates contained in the ICSI SSL Notary to see if there is any certificate that specifies a non 8-bit-divisible signature. Due to the size of our data set - at the moment it consists or more than 1.8 million certificates extracted from more than 50 billion connections - the scan is still running; so far there have been no hits.

Thursday, January 23, 2014

Intelligence Data and Bro


Intelligence data, or feeds, are an important source of network security information. Many internet security research centers, non-profit organizations, and commercial organizations provide intellegence data sets freely available to the public. (e.g. Emerging Threats, Shadow Server, etc.)

A solid solution for handling multiple intelligence feeds and acting upon them is to use Bro's Intel Framework in conjunction with its Input Framework to log hits seen on your network.

Hits, or matches, are logged and stored in intel.log.

$ head /bro/logs/current/intel.log
#fields ts      uid     id.orig_h       id.orig_p       id.resp_h       id.resp_p       fuid    file_mime_type  file_desc       seen.indicator  seen.indicator_type     seen.where      sources
#types  time    string  addr    port    addr    port    string  string  string  string  enum    enum    table[string]
1389646914.469513       Cb1T1Y3r56rjSRr0ac   49379  80      -       -       -  Intel::ADDR     Conn::IN_RESP   snort
1389646925.095172       CeHuLr2IfATgjhQPUg  43471  5900    -       -       -  Intel::ADDR     Conn::IN_ORIG   CIF - need-to-know
1389646979.298695       Cj9bjq43KThmM8TOA6  60430   80      -       -       -  Intel::DOMAIN   HTTP::IN_HOST_HEADER    CIF - need-to-know
1389636016.229788       CNXlzu1VdMhKVEDCPf    52518   443     -       -       -   Intel::ADDR     Conn::IN_RESP   tor
1389636187.690988       CsGYCjrhwI313rWob   41270  3389      -       -       -   Intel::ADDR     Conn::IN_ORIG   ciarmy

Each log entry consists of a number of fields describing the connection:

uid:Unique ID of connection
id.orig_h:Connection originator's endpoint IP address
id.orig_p:Connection originator's endpoint TCP/UDP or ICMP code
id.resp_h:Connection responder's endpoint IP address
id.resp_p:Connection responder's endpoint TCP/UDP or ICMP code
fuid:File indentifier (if file was found in connection)
file_mime_type:Libmagic file type (e.g. application/x-dosexec)
file_desc:Optional file type description
seen.indicator:The indicator that triggered the match (e.g. IP)
 The type of indicator (e.g. ADDR, DOMAIN)
seen.where:Location in Bro's where the event triggered (e.g. DNS::REQUEST)
sources:Intel data source description (e.g.

Intel Framework

The Intel Framework provides the facilities to handle intelligence data in a meaningful manner (e.g. categorization, types, source, etc.). [1]

Supported types of intelligence data indicators are:


Before we can use the framework we must load it by adding the following lines to local.bro or equivalent:

@load frameworks/intel/seen
@load frameworks/intel/do_notice

The next step is to properly format the data set. Each field must be separated by a single tab character.

#fields indicator       indicator_type  meta.source     meta.url        meta.do_notice  meta.if_in   Intel::ADDR     ciarmy       T       -    Intel::ADDR     ciarmy       T       -   Intel::ADDR     ciarmy       T       -     Intel::ADDR     ciarmy       T       -     Intel::ADDR     ciarmy       T       -     Intel::ADDR     ciarmy       T       -   Intel::ADDR     ciarmy       T       -    Intel::ADDR     ciarmy       T       -    Intel::ADDR     ciarmy       T       -

Also, each field has a particular type of value. Two worthy of mention are meta.do_notice and meta.if_in because they work with the Notice Framework. meta.do_notice expects a boolean value which determines whether matches will be sent to the Notice Framework where entries will end up in notice.log, in addition to the normal intel.log.

$ grep Intel notice.log
1389636016.229788       CNXlzu1VdMhKVEDCPf  52518   443     -       -       -       tcp     Intel::Notice   Intel hit on at Conn::IN_RESP   443
1389636016.517027       Cr1u7g2pFxgSzHBsRf 52519   443     -       -       -       tcp     Intel::Notice   Intel hit on at Conn::IN_RESP   443

meta.if_in concerns itself with where a particular match was found in network traffic (e.g. HTTP::IN_HOST_HEADER) and serves as a restriction for matches sent to the Notice Framework i.e. they must be found in the location of meta.if_in.

Note: meta.if_in takes a single location value. If you would to like to specify more than one location for an indicator you will need an entry for each location you desire to be seen. e.g.

#fields indicator       indicator_type  meta.source     meta.url        meta.do_notice  meta.if_in   Intel::DOMAIN   mandiant        -       T       DNS::IN_REQUEST   Intel::DOMAIN   mandiant        -       T       HTTP::IN_HOST_HEADER   Intel::DOMAIN   mandiant        -       T       SMTP::IN_FROM

The list of possible meta.if_in locations are: [2]


Input Framework

The Input Framework [3] provides the facilities to read information from a text file, and in our case send it to the Intel Framework for processing.

Note: If you're running a Bro cluster, the intelligence files only need to be stored and read on the manager.

An absolute file path is required to read from a file. Three ways to do this are:

  1. Specify the file's full path

  2. Append the file name to @DIR which stores the directory path of the calling script. If the script with Intel::read_files is not in the same directory as the intel data sets this will not work.

  3. Create a constant that's value is the directory path in local.bro or equivalent.

    const feed_directory = "/opt/bro/feeds";

Here's an example using all three methods:

redef Intel::read_files += {
        @DIR + "/",
        @DIR + "/",
        feed_directory + "/",
        feed_directory + "/",

Obtaining Feeds

Two solutions for obtaining pre-formatted feeds for Bro to use are mal-dns2bro, a helper script for mal-dnssearch, or the Collective Intelligence Framework and its Bro output plug-in.


Mal-dnssearch [4] is a shell script I wrote that downloads, parses, and compares intelligence feeds against a number of popular application log files, reporting any matches. mal-dns2bro [5] is a helper script included with mal-dnssearch that formats feeds for Bro's Intel Framework to extend the application of intelligence data directly against live network traffic. mal-dns2bro has the ability to customize Intel Framework fields like setting meta.source, meta.url, meta.do_notice, and meta.if_in.

mal-dnssearch supports a number of feeds, ``mal-dnssearch -h'':

Malware List Options:
        -M <list>               Name of list, e.g. \`\`-M snort\'\'

        List:      |     Description:
        snort      - (IP)
        et_ips     - (IP)
        alienvault - (BIG file) (IP)
        botcc      - (IP)
        tor        - (IP)
        rbn        - (IP)
        malhosts   - (DNS)
        malips     - (IP)
        ciarmy     - (IP)
        mayhemic   - (DNS)
        mandiant   - (DNS)

Download and install mal-dnssearch:

$ git clone
$ cd mal-dnssearch
$ sudo make install

Download Mandiant's APT1 data set, parse, and pipe (``-p'') it to mal-dns2bro for formatting:

$ mal-dnssearch -M mandiant -p | mal-dns2bro -T dns -s mandiant >

Sample file output:

#fields indicator       indicator_type  meta.source     meta.url        meta.do_notice  meta.if_in       Intel::DOMAIN   mandiant        -       F       -    Intel::DOMAIN   mandiant        -       F       -   Intel::DOMAIN   mandiant        -       F       -     Intel::DOMAIN   mandiant        -       F       -

In the example above, mal-dns2bro reads in the mandiant list from stdin and sets the indicator type (``-T'') to DNS because the mandiant list consists of only DNS names. The source (``-s'') field is also set which is a short description of where the intelligence data came from.

mal-dns2bro will add the necessary tab separated columns for the Intel Framework. It accepts a list of a specific indicator type, but supports all of them, with one entry per line. It can read from stdin or from a file (``-f''). If you don't want to use mal-dnssearch, you can create your own lists with a text editor or other program and have mal-dns2bro format them for Bro.

Another example, downloading a list of tor nodes and customizing all fields:

$ mal-dnssearch -M tor -p | mal-dns2bro -T ip -s tor -n true -u >

Sample file output:

#fields indicator       indicator_type  meta.source     meta.url        meta.do_notice  meta.if_in   Intel::ADDR     tor  T       Conn::IN_RESP   Intel::ADDR     tor  T       Conn::IN_RESP  Intel::ADDR     tor  T       Conn::IN_RESP   Intel::ADDR     tor  T       Conn::IN_RESP

In this last example, two new options are introduced: mal-dns2bro sets to true (``-n'') which will send intel matches to the notice framework: the source URL, when applicable, is set (``-u'').

Collective Intelligence Framework

The Collective Intelligence Framework (CIF) is a cyber threat intelligence management system that pulls and stores feeds into a database for querying with CIF's tools. [6] CIF comes with a number of output plug-ins including one for Bro.

Installing CIF is pretty involved so I will refer the reader to its documentation. [7]

The CIF plug-in for Bro outputs a few different fields than we've seen so far: meta.cif_impact, meta.cif_severity, and meta,cif_confidence. Because of this we will need to load a Bro script, in addition to those required for the Intel Framework, that can handle these.

Add the following line to local.bro or equivalent:

@load policy/integration/collective-intel

Now, lets output domains related to botnets with a confidence level of 85 or greater formatted for Bro.

$ cif -q domain/botnet -c 85 -p bro >

Sample file output:

#fields indicator       indicator_type  meta.source     meta.desc       meta.url        meta.cif_impact meta.cif_severity       meta.cif_confidence     Intel::DOMAIN   CIF - need-to-know      palevo (public)       -       high    85   Intel::DOMAIN   CIF - need-to-know      palevo (public)     -       high    85     Intel::DOMAIN   CIF - need-to-know      palevo (public)       -       high    85 Intel::DOMAIN   CIF - need-to-know      palevo (public)   -       high    85

Create a list of machines known for scanning the internet:

$ cif -q infrastructure/scan -c 85 -p bro >

Sample file output:

#fields indicator       indicator_type  meta.source     meta.desc       meta.url        meta.cif_impact meta.cif_severity       meta.cif_confidence  Intel::ADDR     CIF - need-to-know      ssh (public)    -       medium  85  Intel::ADDR     CIF - need-to-know      ssh (public)    -       medium  85  Intel::ADDR     CIF - need-to-know      ssh (public)    -       medium  85

E-mailing Notices

This section presumes that Intel events are sent to the Notice Framework [8], described in the Intel section of this article.

Each time a Intel::Match event is generated, the intel data for that match is sent to the Notice Framework where a Notice is raised that has a type of Intel::Notice. To receive e-mail notifications upon a match add the following Notice type to emailed_types in local.bro or equivalent:

redef Notice::emailed_types += {

Suppression can be used to reduce the number of events generated for a specific Intel match. To limit each particular match to once per day add the following lines to local.bro or equivalent:

redef Notice::type_suppression_intervals += {
        [Intel::Notice] = 1day,

Log Queries

Bro-cut can be used to print fields in Bro logs. The following example will print a list of indicators only i.e. the host, hash, e-mail, etc. that triggered the match.

$ bro-cut seen.indicator < intel.log

To print a unique list of all ADDR types and the number of times they were seen try the following query. If you count be the number of fields 11 is seen.indicator_type and field 10 is seen.indicator:

$ awk '$11 == "Intel::ADDR" { print $10 }' intel.log | sort -t . -n -k 1,1 -k 2,2 -k 3,3 -k 4,4 | uniq -c

The next example illustrates an intel match found in the host field of the HTTP header.

1390425478.178039       CQzyg512Q8Mm2UrTc4   51220    80      -       -       -    Intel::DOMAIN   HTTP::IN_HOST_HEADER    malhosts

Since the above connection is using HTTP there are bound to be more logs related to the connection such as those produced by the HTTP analyzer. We can search all Bro's logs for the connection identifier, a 4-tuple flow hash, to find other logs related to that connection.

$ zgrep CQzyg512Q8Mm2UrTc4 *.log.gz
1390425478.076356 CQzyg512Q8Mm2UrTc4 51220    80      tcp     http    123.242140      397     981     RSTR    T       0       ShADadr 12      1302    12      2514    (empty) US      US      nids-31-2
1390425478.398364        FQSaaGSHQsLn11w8j CQzyg512Q8Mm2UrTc4      HTTP    0       SHA1,MD5        text/plain      -       0.000000        F       F       595     -       0       0       F       -       d6923c591dfa3cb616327a0bb44375b3        aa5438c500083ee69297d8c1a2ab4f82655c4632      -       -
1390425478.179990        CQzyg512Q8Mm2UrTc4 51220    80      1       GET    /valuewalk/tipranks.js     Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.76 Safari/537.36  0       595     200     OK      -       -       -       (empty) -       -       -       -       -       FQSaaGSHQsLn11w8j       text/plain
1390425478.178039        CQzyg512Q8Mm2UrTc4 51220    80      -       -       -    Intel::ADDR     Conn::IN_RESP   malips
1390425478.178039        CQzyg512Q8Mm2UrTc4 51220    80      -       -       -    Intel::DOMAIN   HTTP::IN_HOST_HEADER    malhosts

We found a number of events detailing the connection, these include the URL the user visited, the type of file that was transferred in the session, and another intel match from a different intel source. This is especially useful in cases where there are more than one HTTP request in a single TCP session.

Putting it all together

A powerful but simple solution is to write a daily cronjob that downloads and formats the latest version of each feed from which Bro continuously reads and then restarts Bro, if necessary. A restart is required if you want to purge entries that have been removed from the feeds, but not if you only want the new entries because Bro keeps the file open and will pick up any new additions.

If you come across any trouble be sure to check reporter.log.



Thursday, November 7, 2013

Bro 2.2

Bro 2.2 has arrived. You can download the source distribution on our download page; binary packages will follow soon. For an overview of the major new features in 2.2, please see the earlier posting on the beta version. Since that beta, we have applied a range of smaller bug fixes and cleanups, improved portability and regression testing, and extended the documentation further. We have also added a few missing pieces to the release notes; see NEWS for the final version.

Thanks to everybody who contributed to Bro 2.2, including in particular those of you who helped us test early versions during development.

The Bro Team