Each individual signature has the format
signature id { attribute-set }
id is an unique label for the signature. There are two types of attributes: conditions and actions. The conditions define when the signature matches, while the actions declare what to do in the case of a match. Conditions can be further divided into four types: header, content, dependency, and context. We will discuss these in more detail in the following subsections.
This is an example of a signature:
signature formmail-cve-1999-0172 { ip-proto == tcp dst-ip == 1.2.0.0/16 dst-port = 80 http /.*formmail.*\?.*recipient=[^&]*[;|]/ event "formmail shell command" }
Header conditions limit the applicability of the signature to a subset of traffic that contains matching packet headers. For TCP, this match is performed only for the first packet of a connection. For other protocols, it is done on each individual packet. There are pre-defined header conditions for some of the most used header fields:
comp is one of ==, !=, <, <=, >, >=. All lists are comma-separated values of the given type which are sequentially compared against the corresponding header field. If at least one of the comparisions evaluates to true, the whole header condition matches (exception: if comp is !=, the header condition only matches if all values differ). address is an dotted IP address optionally followed by a CIDR/mask to define a subnet instead of an individual address. protocol is either one of ip, tcp, udp and icmp, or an integer.
In addition to this pre-defined short-cuts, a general header condition can be defined either as
header proto[offset:size] comp value-list
or as
header proto[offset:size] & integer comp value-list
This compares the value found at the given position of the packet header with a list of values. offset defines the position of the value within the header of the protocol defined by proto (which can ip, tcp, udp oricmp. size is either 1, 2, or 4 and specifies the value to have a size of this many bytes. If the optinal & integer is given, the packet's value is first masked with the integer before it is compared to the value-list. comp is one of ==, !=, <, <=, >, >=. value-list is a list of comma-separated integers similar to those described above. The integers within the list may be followed by an additional /mask where mask is a value from 0 to 32. This correponds to the CIDR notation for netmasks and is translated into a corresponding bitmask which is applied to the packet's value prior to the comparision (similar to the optional & integer).
Putting all together, this is an example which is aequivalent to dst-ip == 1.2.3.4/16, 5.6.7.8/24:
header ip[16:4] == 1.2.3.4/16, 5.6.7.8/24
Content conditions are defined by regular expressions. We differentiate two kinds of content conditions: first, the expression may be declared with the payload statement, in which case it is matched against the raw payload of a connection (for reassembled TCP streams) or of a each packet. Alternatively, it may be prefixed with an analyzer-specific label, in which case the expression is matched against the data as extracted by the corresponding analyzer.
A payload condition has the form
payload /regular expression/
Currently, the following analyzer-specific content conditions are defined (note that the corresponding analyzer has to be activated by loading its policy script):
For example, http /(etc(passwd|shadow)/ matches any URI containing either etc/passwd or etc/shadow.
To define dependencies between different signatures, there are two conditions:
Context conditions pass the match decision on to various other components of Bro. They are only evaluated if all other conditions have already matched. The following context conditions are defined:
Actions define what to do if a signature matches. Currently, there is only one action defined: event string raises a signature_match event. The event handler has the following type:
event signature_match(state: signature_state, msg: string, data: string)
See Figure for a description of signature_state. The given string
is passed as msg, and data is the current part of the payload that
has eventually lead to the signature match (this may be empty for signatures without
content conditions).