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, 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.
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.
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 . 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 .
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 . On CentOS, I download the Bro full install with:
# wget https://www.bro.org/downloads/release/Bro-2.3.1-Linux-x86_64.rpm
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
share subdirectories. To fire up Bro immediately, I use
# /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
[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 subdirectory contains the executables that make up the Bro distribution as follows:
adtraceis responsible for tracking network addresses. It basically gives Bro the ability to trace source and destination Layer 2 (MAC) and Layer 3 (IP) addresses. It functions by reading the
.pcapfile and outputs the source Layer 2 address, the destination Layer 2 address, the source IP, and the destination IP.
bro-cutis responsible for formatting Bro's output into columns. It functions by reading Bro's logins and printing the specified columns. This allows simple reports to be run on the basis of field names, instead of having to count columns with Awk, for example.
broccoli-configis the configuration program for Broccoli (Bro Client COmmunications LIbrary). Broccoli lets developers create client sensors for Bro.
broctl, as seen earlier in the article, is an interactive shell used to start, stop, and manage Bro's engines, as well as support a help system (Listing 1). See also the "Interactive Shell" box.
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] >
captsatscollects statistics on the network interface and is useful for monitoring traffic loads. You can define the logging interval with the
-Iparameter and the number of intervals with the
-nparameter. For example, to run a report every three seconds for five iterations on eth0, you would use the command in Listing 4.
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).
ftwire2brois a command-line utility that takes Netflow files and converts them to Bro format. Another utility in the
nfcollector, captures Netflow data from a socket and converts it to Bro format.
rst, short for TCP reset, is used by Bro to terminate established TCP connections. One valuable use would be for configuring Bro to deal with a zero day attack in which the traffic simply needs to be shutdown. An example application would be to halt the replication of a worm for which virus software vendors have not yet provided a signature or the means for removal.
trace-summaryis another reporting tool that can be used for analysis against Bro's logs.
Configuration and Output Files
Another subdirectory worth understanding in
etc. This directory contains four configuration files:
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.
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.
nodes.cfg file is where you can add additional nodes or change interfaces.
/opt/bro/ directory, Bro also manages
/var/opt/bro/. This directory contains two subdirectories:
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
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 (
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.
As an example of Bro's abilities, I'll look at a specific incident. On October 30, the DHCP service on the network at 192.168.1.1 was "knocked over" via a distributed denial of service, and a rogue service was put in place at 192.168.1.2; 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* dhcp.04:00:00-05:00:00.log.gz dhcp.15:00:00-16:00:00.log.gz
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 192.168.1.27 (Listing 7). The field names used in this command,
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 192.168.1.2 192.168.1.27 86400.000000 2014-10-30T15:54:52-0500 192.168.1.1 192.168.1.14 86400.000000
ls known_services* known_services.03:00:00-04:00:00.log.gz known_services.07:00:00-08:00:00.log.gz
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 192.168.1.2 67 udp DHCP 2014-10-30T03:12:12-0500 192.168.1.2 80 tcp HTTP 2014-10-30T03:14:29-0500 192.168.1.2 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.