Bro has an event engine that raises events when it sees something happen on the network (those things could be DNS requests, UDP packets, a specific email subject, or a file MD5). It's up to the brogrammer to define events that should be raised and what should happen (aka Bro policies) when those events are raised. Bro programmers sit at the policy script interpreter layer, waiting for events to be raised by the core event engine.
Bro reads raw data off the wire or from a pcap file (by default using libpcap), similar to tcpdump or Snort. The packets Bro reads are reassembled into streams. Bro has many events that are raised from the network streams it reassembles. A simple example is the new_connection event. The Bro core (where the event engine is located) raises this event and it 'occurs' within scriptland whenever Bro sees a new connection happen. Bro also raises events about itself. For example, Bro raises an event right as it begins running and right before it terminates. Bro has many more events which will be covered in a later post.
In addition to Bro's event engine, Bro has a scripting layer that allows brogrammers to define what happens when an event is triggered. For now, imagine Bro's event engine only has the three example events I mentioned above (new_connection when a new network connection occurs, bro_init when Bro first begins running, and bro_done just before Bro terminates).
With only these three events a brogrammer could instruct Bro to
- print a nice welcoming message when Bro starts, perhaps "Sup bro, sup?"
- print a different message, perhaps "Yo bro, a new connection happened", whenever a new connection happens on the wire
- print a closing message when Bro is told to terminate, perhaps "I'm going down, bro"
/usr/local/bro/bin/bro -i eth0 broverview.bro
Terminate the Bro process (with ctrl+c) and inspect the output that is printed to STDOUT. You should see the messages defined in bro_init and bro_done, but Bro might not have printed the message from the new_connection event. If it didn't, that's because Bro didn't see any new connections while it ran. Try running the script and generating a new connection across the interface.
Read through the broverview.bro script. Syntactically, Brolang, or the Bro scripting language, looks similar to many other C based languages. Brolang inherits semi-colon delimited lines, curly brace code blocks, and other semantics fromthe C++ core it is built on top of.
You might have noticed that the event handlers in the broverview.bro script aren't executed in the order they appear in the script. This is because they don't execute unless Bro see the event on the wire and 'handles' them. This non-sequential execution of events is where the event-driven programming reference I made at the beginning of this post comes into play. Don't worry if you don't understand all the particulars of the script just yet.
Our example is very simple and somewhat useless, but it shows how a brogrammer can specify actions (in Bro vernacular, 'policies') for Bro to take
when an event occurs. Bro is capable of doing much more than just printing to STDOUT. In useful Bro scripts, nothing is printed to STDOUT. Instead, things are logged to files or alerts, like emails, are generated.
Bro can send you an email, raise an alert, execute a system call, or just about anything else you can script. This is where Bro's power shines through - in extending and customizing event handling.
You might have noticed that Bro, by default, generates logs in the directory
you execute Bro in. This is because, by default, Bro is configure with policy scripts that tell it to log information. For example, when an HTTP request and response are seen and completed (events are raised for HTTP seen on the wire), Bro writes some information about the HTTP connection to disk. Try running Bro on an interface while browsing to this blog and see what log files get written to disk. Open the log files and try to determine what the fields in the file are.
The events Bro raises are neutral. The Bro event engine's job is to let scriptland know when something happened. It is up to the brogrammer to determine if the event is good, bad, actionable or uninteresting. Thus Bro isn't really an IDS, but a network investigation platform. You could certainly build an IDS from Bro's scriptland but you could also build Conway's game of life. The core of Bro simply passes summaries of the network up to scriptland for a brogrammer to script against. If I don't care about SMTP traffic, I can tell Bro (in scriptland) not to do anything when the Bro core reassembles SMTP traffic. If I do care about SSL traffic, I can write a script to extract all SSL certificates Bro sees. In fact, that's what the ICSI Certificate Notary does.
Hopefully now you understand how Bro inspects live/stored traffic, generates and passes events to scriptland based on the traffic, which are handled by user defined scripts or policies.
If you still have questions, feel free to ask in the comment section. A complete summary of the Bro project can be found here. I recommend having the Bro cheat sheet on hand through out the rest of these posts.