Tools Bro IDS Lead image: Lead Image © Aleksey Mnogosmyslov,
Lead Image © Aleksey Mnogosmyslov,

Network analysis with the Bro Network Security Monitor

Got Your Back

The Bro network analysis framework provides network security monitoring as well as more general network traffic analysis. By Ronald McCarty

The Bro Network Security Monitor (Bro) is a network-based analysis framework. Bro's powerful analysis engine makes it adept at high-performance network monitoring, protocol analysis, and real-time application layer state information. This makes Bro a very good intrusion detection system (IDS) and network analysis framework. For this reason, analysis around IDS is one of the most popular uses for Bro.

What are some examples of analysis around IDS? Often, investigations concerning intrusions are not just about the identification of the event, which can often be accomplished with signatures, but about identification of the details of events to help information security professionals zone in on specific problems and solutions. Because logs can be compromised during an event, logging outside a compromised system is important. For example, while DHCP services are being compromised, protocol-level analysis can be key to understanding the event.

Bro was originally developed in 1994 by Vern Paxson and was named in reference to George Orwell's Big Brother from his novel Nineteen Eighty-Four. Unix history buffs and computer science majors may recognize Paxson as the original author of flex, the fast lexical analyzer. In this article, I cover the architecture, installation, and use of Bro. Finally, I look at a DHCP compromise example.

Bro Architecture

Bro, like many network tools with a Unix or Linux heritage, uses the libpcap package as part of its architecture. With libpcap support, Bro can run on various networks; the typical Bro architecture is shown in Figure 1.

Bro network architecture.
Figure 1: Bro network architecture.

Besides the portability gained by using libpcap, Bro can also be a passive network tool, which means it can act as a network tap or use a monitoring port on a switch without itself being a node with an assigned IP address on the monitored network. For the purposes of this article, I will not cover the specifics of the network tap; however, the basic step for carrying out the Bro configuration is to point Bro at the network interface that is being used for the network tap.

Once Bro receives an IP packet, its application architecture comes into play. Bro's event engine is responsible for accepting packets and converting them to events. The events are then forwarded to the policy script interpreter, which then creates outputs. Bro's application architecture can be represented as shown in Figure 2. Bro's outputs are further classified as actions, alerts, and logs, which I review shortly.

Bro application architecture.
Figure 2: Bro application architecture.


Like most Linux solutions, Bro doesn't recreate the wheel for all of its functionality. It uses several pre-existing libraries. The capability to collect and parse Ethernet and IP traffic comes from libpcap [1]. Bro controls it with BroControl, which requires Bash and Python, as well as the BIND 8 and libz libraries. The latest dependencies and high-level instructions for Bro can be referenced at the Bro website [2].

The installation instructions I cover here are based on a CentOS 6.5 Linux distribution. (Note: At the time of publication, CentOS 7 still has a missing dependency for the Python libraries.) The latest Bro packages are included in source and binary form [3]. On CentOS, I download the Bro full install with:

# wget

Next, I install the Bro RPM package with:

# rpm -ivh Bro-2.3.1-Linux-x86_64.rpm

After the installation completes, Bro can be found in the /opt/bro/ directory, which contains the bin, etc, include, lib, and share subdirectories. To fire up Bro immediately, I use broctl:

# /opt/bro/bin/broctl
warning: cannot read '/var/opt/bro/spool/broctl.dat' \
  (this is ok on first run)
Welcome to BroControl 1.3
Type "help" for help.
[BroControl] >

As the message states, I can ignore the "cannot read" warning message during the first run.

Installing the Policy

At this point, I can install the standard Bro policies by executing the install command at the BroControl prompt:

[BroControl] > install
creating policy directories ... done.
installing site policies ... done.
generating standalone-layout.bro ... done.
generating local-networks.bro ... done.
generating broctl-config.bro ... done.
updating nodes ... done.

Now that a policy has been installed, the next step is to tell BroControl to start up a Bro instance with the start command:

[BroControl] > start
starting bro ...
[BroControl] >

Whenever Bro starts up, it starts its daemon to listen to all the traffic defined in its /opt/bro/etc/node.cfg file. This is eth0 by default. If I were setting up a host on another interface, then I would edit node.cfg to point to the appropriate interface.


With the standard install on CentOS, Bro will be installed in /opt/bro/, which contains the following subdirectories: bin, etc, include, lib, and share.

The bin subdirectory contains the executables that make up the Bro distribution as follows:

Listing 1: Bro Help System

[BroControl] > help
BroControl Version 1.3
  capstats [<nodes>] [<secs>]      - Report interface statistics with capstats
  check [<nodes>]                  - Check configuration before installing it
  cleanup [--all] [<nodes>]        - Delete working dirs (flush state) on nodes
  config                           - Print broctl configuration
  cron [--no-watch]                - Perform jobs intended to run from cron
  cron enable|disable|?            - Enable/disable "cron" jobs
  df [<nodes>]                     - Print nodes' current disk usage
  diag [<nodes>]                   - Output diagnostics for nodes
  exec <shell cmd>                 - Execute shell command on all hosts
  exit                             - Exit shell
  install                          - Update broctl installation/configuration
  netstats [<nodes>]               - Print nodes' current packet counters
  nodes                            - Print node configuration
  peerstatus [<nodes>]             - Print status of nodes' remote connections
  print <id> [<nodes>]             - Print values of script variable at nodes
  process <trace> [<op>] [-- <sc>] - Run Bro (with options and scripts) on trace
  quit                             - Exit shell
  restart [--clean] [<nodes>]      - Stop and then restart processing
  scripts [-c] [<nodes>]           - List the Bro scripts the nodes will load
  start [<nodes>]                  - Start processing
  status [<nodes>]                 - Summarize node status
  stop [<nodes>]                   - Stop processing
  top [<nodes>]                    - Show Bro processes ala top
  update [<nodes>]                 - Update configuration of nodes on the fly
Commands provided by plugins:
  ps.bro [<nodes>]                 - Show Bro processes on nodes' systems

Listing 2: ps.bro

[BroControl] > ps.bro
       USER       PID  PPID %CPU %MEM    VSZ   RSS TT       S  STARTED       TIME COMMAND
>>> localhost
   (+) root     11766 11757 34.8  6.4 862984 96872 ?        S   Oct 19 7-00:03:58 bro
   (+) root     11792 11766 11.4  3.3 150888 51400 ?        S   Oct 19 2-07:05:05 bro

Listing 3: netstats

[BroControl] > netstats
        bro: 1415509669.641986 recvd=431 dropped=0 link=431
[BroControl] > restart
stopping ...
stopping bro ...
starting ...
starting bro ...
[BroControl] > netstats
        bro: 1415509677.525993 recvd=35 dropped=0 link=35
[BroControl] >

Listing 4: capstats

/opt/bro/bin/capstats -I 3 -n 5 -i eth0
1415510235.518025 pkts=2 kpps=0.0 kbytes=0 mbps=0.0 nic_pkts=2  nic_drops=0 u=0 t=0 i=0 o=0 nonip=2
1415510238.518111 pkts=8 kpps=0.0 kbytes=1 mbps=0.0 nic_pkts=10 nic_drops=0 u=5 t=2 i=0 o=0 nonip=1
1415510241.519354 pkts=6 kpps=0.0 kbytes=0 mbps=0.0 nic_pkts=16 nic_drops=0 u=2 t=2 i=0 o=0 nonip=2
1415510244.519597 pkts=6 kpps=0.0 kbytes=0 mbps=0.0 nic_pkts=22 nic_drops=0 u=2 t=2 i=0 o=0 nonip=2
1415510247.520546 pkts=7 kpps=0.0 kbytes=1 mbps=0.0 nic_pkts=29 nic_drops=0 u=3 t=2 i=0 o=0 nonip=2

The capstats report shows (left to right) the relative time stamp, the number of packets (pkts) seen by capstats during a particular interval, the number of packets per second (kppsx1000), the kilobytes seen during the interval (kbytes), megabits per second (mbps), libpcap's reported packets (nic_pkts), the number of packets reported by libpcap as dropped (nic_drops), the number of packets via UDP, TCP, ICMP, and other protocols (u, t, i, o), and the number of non-IP packets (nonip).

Configuration and Output Files

Another subdirectory worth understanding in /opt/bro/ is etc. This directory contains four configuration files: broccoli.conf, broctl.cfg, networls.cfg, and nodes.cfg.

Unless you are developing applications that interact with Bro, the broccoli.conf file can be ignored. The broctl.cfg file isn't typically needed on an RPM-installed version of Bro; however, you might need it if you have to restructure disk volumes at some point in time.

The networks.cfg file defines networks and typically contains the private address space as default. You can add additional networks for Bro to search when using descriptions of networks in reports.

The nodes.cfg file is where you can add additional nodes or change interfaces.

Besides the /opt/bro/ directory, Bro also manages /var/opt/bro/. This directory contains two subdirectories: logs and spool.

The logs directory comprises archived logs containing historical data (all logs previous to today); however, it also contains the current log linked to the current directory. The subdirectories in logs are in the format YYYY-MM-DD and, as mentioned, the current directory (Listing 5).

Listing 5: var/opt/bro/logs Subdirectories

ls -l /var/opt/bro/logs/
total 244
drwxr-xr-x. 2 root root  4096 Oct 20 00:00 2014-10-19
drwxr-xr-x. 2 root root 12288 Oct 21 00:00 2014-10-20
drwxr-xr-x. 2 root root 12288 Oct 22 00:00 2014-10-21
drwxr-xr-x. 2 root root 12288 Oct 23 00:00 2014-10-22
drwxr-xr-x. 2 root root 12288 Oct 24 00:00 2014-10-23
drwxr-xr-x. 2 root root 12288 Oct 25 00:00 2014-10-24
drwxr-xr-x. 2 root root 12288 Nov  5 00:00 2014-11-04
drwxr-xr-x. 2 root root 12288 Nov  6 00:00 2014-11-05
drwxr-xr-x. 2 root root 12288 Nov  7 00:00 2014-11-06
drwxr-xr-x. 2 root root 12288 Nov  8 00:00 2014-11-07
drwxr-xr-x. 2 root root 12288 Nov  8 23:07 2014-11-08
lrwxrwxrwx. 1 root root    22 Oct 19 21:22 current -> /var/opt/bro/spool/bro

The spool subdirectory not only contains the working directory but also is used for scratch space by Bro (tmp subdirectory), as well as the broctl database (broctl.dat).

Now that Bro is up and running, I can take a look at one of the output types that Bro supports. Luckily, Bro uses intuitive names. For example, the log for October 19 is shown in Listing 6.

Listing 6: Bro Log for One Day

[root@centos6-5 2014-10-19]# ls -l /var/opt/bro/logs/2014-10-19/
total 268
-rw-r--r--. 1 root root   2360 Oct 19 22:00 communication.21:34:11-22:00:00.log.gz
-rw-r--r--. 1 root root   4787 Oct 19 23:00 communication.22:00:00-23:00:00.log.gz
-rw-r--r--. 1 root root   4787 Oct 20 00:00 communication.23:00:00-00:00:00.log.gz
-rw-r--r--. 1 root root  15157 Oct 19 22:00 conn.21:34:39-22:00:00.log.gz
-rw-r--r--. 1 root root  33060 Oct 19 23:00 conn.22:00:00-23:00:00.log.gz
-rw-r--r--. 1 root root    875 Oct 19 23:00 files.22:05:05-23:00:00.log.gz
-rw-r--r--. 1 root root    626 Oct 19 23:00 http.22:05:05-23:00:00.log.gz
-rw-r--r--. 1 root root    174 Oct 19 22:00 known_hosts.21:54:41-22:00:00.log.gz
-rw-r--r--. 1 root root    233 Oct 19 22:00 known_services.21:54:41-22:00:00.log.gz
-rw-r--r--. 1 root root   2006 Oct 19 22:00 loaded_scripts.21:34:11-22:00:00.log.gz
-rw-r--r--. 1 root root    434 Oct 20 00:00 notice.23:02:17-00:00:00.log.gz
-rw-r--r--. 1 root root    197 Oct 19 22:00 packet_filter.21:34:11-22:00:00.log.gz
-rw-r--r--. 1 root root    393 Oct 19 22:00 reporter.21:34:21-22:00:00.log.gz
-rw-r--r--. 1 root root    270 Oct 19 22:00 software.21:54:41-22:00:00.log.gz
-rw-r--r--. 1 root root    336 Oct 19 22:00 ssh.21:55:11-22:00:00.log.gz
-rw-r--r--. 1 root root    400 Oct 20 00:00 ssh.23:00:00-00:00:00.log.gz
-rw-r--r--. 1 root root   1268 Oct 19 22:00 weird.21:34:12-22:00:00.log.gz
-rw-r--r--. 1 root root   2477 Oct 19 23:00 weird.22:00:00-23:00:00.log.gz
-rw-r--r--. 1 root root   2992 Oct 20 00:00 weird.23:00:00-00:00:00.log.gz

Bro has identified all the protocols it analyzed on October 19 and named them according to the protocol. For example, HTTP and SSH protocols clearly stand out. Bro also provided additional logs, such as the known_hosts, connections logs (conn), and others.

DHCP Compromise

As an example of Bro's abilities, I'll look at a specific incident. On October 30, the DHCP service on the network at was "knocked over" via a distributed denial of service, and a rogue service was put in place at; however, the server team was unaware of when addresses were assigned by the rogue DHCP server. Bro can show when the first assignment was made:

ls dh*

Two logs concerning DHCP exist: one from 4:00am and one from 3:00pm. With the bro-cut command, I can determine that the earliest assignment by the rogue server was at 4:04am and assigned the address (Listing 7). The field names used in this command, id_resp_h and assigned_ip, are found in the first few lines of all Bro logs. By using Bro's known services logs,

Listing 7: bro-cut

zcat dhcp.* | /opt/bro/bin/bro-cut -d ts id.resp_h assigned_ip lease_time
2014-10-30T04:04:04-0500   86400.000000
2014-10-30T15:54:52-0500   86400.000000
ls known_services*

I can confirm that Bro picked up on a new service in the time frame of interest, so I can check the known_services log before the address assignment identified in the previous command (Listing 8).

Listing 8: known_services Log of Interest

zcat known_services.03\:00\:00-04\:00\:00.log.gz | /opt/bro/bin/bro-cut -d
2014-10-30T03:00:29-0500    67 udp   DHCP
2014-10-30T03:12:12-0500    80 tcp   HTTP
2014-10-30T03:14:29-0500    53 tcp   HTTP

According to Listing 8, the DHCP was first recognized on the network at 3:00am, much earlier than existing logs could have provided. However, notice that it picked up on two additional services: two web servers – one running on the well-known port 80 and another on port 53. These steps, then, could be used to track down traffic to the server, checking and validating the HTTP logs to which Bro connects.


Bro is an excellent tool that helps in the analysis of network intrusion detection. It is easily deployed and very useful in both identifying issues and supporting detection and cleanup operations after incidents.