Sagan rule options and definitions:


{alert|drop}

alert tcp $EXTERNAL_NET any -> $HOME_NET 22

The first statement of a rule contains either "alert" or "drop". This is only used when the "external" output plugin is used. This informs the external routine to "drop" or "alert". Technically, it has no affect to the overall function of Sagan.

{any|tcp|udp|icmp}

alert tcp $EXTERNAL_NET any -> $HOME_NET

If the log data contains protocol information that can be normalized, this option will act as a filter for the rule. For example, let's says Sagan is analyzing logs from a firewall. The logs contain protocol (TCP, UDP, ICMP) and port information. If the normalized log message contains the term "udp" but the Sagn rule specifies "tcp", the log message is discarded. However, if the term "tcp" is present and normalized, Sagan will continue to parse the data using the rule logic.

Versions of Sagan 1.1.6 or earlier used this field to specify the protocol. This is no longer the case. To specify a default protocol, see "default_proto".

In most cases, you'll likely want to set this to "any".

{source}

alert tcp $EXTERNAL_NET any -> $HOME_NET any

Only applies a rule if the normalized source honored by $EXTERNAL_NET. For example, if $EXTERNAL_NET is set to "10.0.0.0/8" and the normalized source is "192.168.1.1", the rule wll not trigger. Multiple values can be applied to $EXTERNAL_NET. For example "var EXTERNAL_NET [10.0.0.0/8, 192.168.0.0/16]" is value. The use of "!" (not) is also valid. For example, "var EXTERNAL_NET [!10.0.0/8]" is valid.

The default value of $EXTERNAL_NET is "any" (any/all sources will match).

{source port}

alert tcp $EXTERNAL_NET any -> $HOME_NET 22

If the "source port" can be extracted and normalized from the log data, this option will act as a filter for the rule. Source port can be an integer or a variable (for example "$SOURCE_PORT").

Sagan version 1.1.6 and earlier used this rule option to specify the source port. This is no longer the case. To specify a source port, see "default_src_port" rule option.

In most cases, you'll want this set to "any".

{destination}

alert tcp $EXTERNAL_NET any -> $HOME_NET 22

Only applies a rule if the normalized destination honored by $HOME_NET. For example, if $HOME_NET is set to "10.0.0.0/8" and the normalized destination is "192.168.1.1", the rule wll not trigger. Multiple values can be applied to $HOME_NET. For example "var HOME_NET [10.0.0.0/8, 192.168.0.0/16]" is value. The use of "!" (not) is also valid. For example, "var EXTERNAL_NET [!10.0.0/8]" is valid.

The default value of $HOME_NET is "any" (any/all sources will match)

{destination port}

alert tcp $EXTERNAL_NET any -> $HOME_NET 22

If the destination port can be extracted and normalized from the log data, this option will act as a filter for the rule. The destination port can be an integer or variable (for example, "$SSH_PORT").

Sagan version 1.1.6 and earlier used this option to specify the destination port. This is no longer the case. To specify a default destination port, see "default_src_port" rule option.

In most cases, you'll want this set to "any".

after: track {by_src|by_dst}, count {number of event}, seconds {number of seconds}

"after" is used to trigger an alert "after" a numbers of events have happened within a specific amount of time. "after" tracks by the source or destination IP address of the event. The example would track events by the source IP address. If the event is triggered more than 10 times within 300 seconds (5 minutes), an alert is triggered.

after: track by_src, count 10, seconds 300;

alert_time: days {days}, hours {hours};

"alert_time" allows a rule to only trigger on certain days and/or certain hours. For example, let's assume that Windows RDP (Remote Desktop Protocol) is normal between the hours of 0800 (8 AM) to 1800 (6 PM). However, RDP sessions outside of that timeframe would be consider suspicious. This allows you to build a rule that will trigger outside of the "normal RDP" times.

Days are represented via digits 0 - 6. 0 = Sunday, 1 Monday, 2 Tuesday, 3 Wednesday, 4 Thursday, 5 Friday, 6 = Saturday.

Hours are represented by the 24 hours clock.

alert_time: days 0123456, hours 0800-1800;

The example above would cause a rule to trigger every day of the week between the hours of 0800 (8:00 AM) to 1800 (6:00 PM). One caveat is with "between" days. For example, if you wanted to create an alert_time rule that stretches from Monday 2300 (11 PM) to Tuesday 0700 (7 AM). The format would be:

alert_time: days 1, hours 2300-0800;

You do not need to include Tuesday (2) in the "days" option. Since the times stretch between two days, Sagan will automatically take this into consideration and makes the adjustments. If you were to include "days 12", this would cause Sagan to alert on Monday-Tueday between 2300 - 0800 and Tuesday-Wednesday 2300-0800.

alert_time can also be used with sagan.yaml variables. For example, if you have "SAGAN_DAYS: 12345" and "SAGAN_HOURS: 0800-1300" in your sagan.yaml (see "aetas-groups" in your sagan.yaml), you could then create a rule like this:

alert_time: days $SAGAN_DAYS, hours $SAGAN_HOURS;

bro-intel: {src_ipaddr},{dst_ipaddr},{both_ipaddr},{all_ipaddr},{file_hash},{url},{software},{email},{user_name},{file_name},{cert_hash}

This options allows Sagan to look malicious IP addresses, file hashes, URLs, software, email, user names, file hashes and certificate hash from Bro Intellegence feeds.

In order for the processors to be used, it must be enabled in your sagan.yaml file.

The following is a simple example within a Sagan rule:

bro-intel: src_ipaddr;

This informs Sagan to look up the parsed source address from the Bro Intel::ADDR data. The parsed source address is extracted via liblognorm or parse_src_ip.

Multiple options can be used. For example:

bro-intel: both_ipaddr, domain, url;

This instructs Sagan to look up the parsed source and destination from the Bro Intel::ADDR data. It also looks up the Intel::DOMAIN and Intel::URL. If any of the "bro-intel" lookups return with a positive hit, the bro-intel option is triggered. Consider the following example:

content: “thisisatest”; bro-intel: src_ipaddr;

If a log messages contains the term “thisisatest” but the parsed source IP address is not found in the Bro Intellegence feeds, the rule will not trigger. If the log message “thisisatest” is found and the src_ipaddr is found, the rule will trigger.

Sagan "bro-intel" option Bro Intel Type Description
src_ipaddr Intel::ADDR Look up the parsed source address
dst_ipaddr Intel::ADDR Look up the parsed destination address
all_ipaddr Intel::ADDR Search all IP address in a log message and look them up
both_ipaddr Intel::ADDR Look up the parsed source & destination address
file_hash Intel::FILE_HASH Search message content for malcious file hash
url Intel::URL Search message content for malicious URL
software Intel::SOFTWARE Search message content for malicious software
email Intel::EMAIL Search message content for malicious email
user_name Intel::USER_NAME Search message content for malicious user names
file_nasm Intel::FILE_NAME Search message content for malicious file names
cert_has Intel::CERT_HASH Search message content for malicious certificate hashes

classtype: {classification}

This links the rule to a classification. Classification can be used to determined priority level. For example:

classtype: exploit-attempt;

A "exploit-attempt" classification is a priority 1 (highest) level event. For a complete list of classification types, see http://github.com/beave/sagan-rules/blob/master/classification.config

content: "{search}"

content is a simple means of determining if the {search} string is in a event/syslog message. For example:

content: "authentication failure";

Will search a log message for the term "authentication failure". content can also be used as part of a NOT statement. For example:

content:!"frank";

This means the the message does NOT contain the term "frank". Tired together, we can make statements like:

content: "authentication failure"; content:!"frank";

If the term "authentication failure" is found and does NOT contain the term "frank", then rule will trigger. Otherwise, the event is ignored.

content: "User Agent|3a| Testing";

This tells content to search for "User Agent: Testing". The |3a| is a hex encoded option for a ":". You can use multiple hex encoded options. For example, "|3a 3b 3c|". Hex values can also be broken up. For example, "This |3a| is a testing with |3b| in it".

country_code: track {by_src|by_dst}, {is|isnot} {ISO3166 Country Codes}

Used to track events from specific countrys.

country_code: track by_src, isnot US;

The example above means, "track by the source address of the event. If the GeoIP 2 location is not from the Unitied States, trigger the rule".

country_code: track by_dst, is [CN,RU,HK];

The example above means, "track by the destination address of the event. If the GeoIP 2 locaiton is going to China, Russia or Hong Honk, trigger the rule".

Country codes are based on ISO3166. See http://dev.maxmind.com/geoip/legacy/codes/iso3166/ for the full listing.

Typically, country codes are tried to the sagan.yaml variable $HOME_COUNTRY (See "geoip-groups" in the sagan.yaml). For example:

country_code: track by_src, isnot $HOME_COUNTRY;

Note: This requires GeoIP2 support to be compiled into Sagan
default_proto: {tcp/udp/icmp}

The default_proto sets the default protocol in the event normalization fails. For example, OpenSSH uses the TCP protocol. However, OpenSSH log messages do not specify the protocol in use. By using the rule option default_proto, Sagan will assign the protocol specified by the rule writer when triggered. This option can be overridden by parse_proto or liblognorm (if used).

Valid values are icmp, tcp and udp or defined variables (ie - "$PROTOCOL"). Defaults to the Sagan YAML "default-proto".

default_dst_port: {port number}

The default_dst_port sets the default port number in the event normalization fails. For example, OpenSSH typically uses port 22. However, OpenSSH log message do not spcify the port being used. By using the rule option default_dst_port, Sagan will assign the port specified by the rule writer when triggered. This option can be overriden by liblognorm.

Valid values are integers (1-63556) or defined variables (ie - "$SSH_PORT"). Defaults to the Sagan YAML "default-port".

default_src_port: {port number}

The default_src_port works sets the default port number in the event normalization fails. For example, if a log message does not contain the source port, this value is used instead. This can be overridden by liblognorm.

Valid values are integers (1-63556) or defined variables (ie - "$SOURCE_PORT). Defaults to the Sagan YAML "default-port".

Note: This requires GeoIP support to be compiled into Sagan
depth: {depth value}

The depth keyword allows the rule writer to specify how far into a log line Sagan should search for the specified pattern from a given offset.

For example:

content: "bob"; depth: 10;

This would start searching at the begining of the log line (default offset: 0) and search only 10 bytes deep for the term "bob".

Example with offset and depth used together:

content: "bob"; offset: 5; depth: 10;

Sagan will start searching for the term "bob" when it gets to 5 bytes into the log line (see offset). It will only search for "bob" after the offset for 10 bytes.

This function is identical to Snort's "depth" rule option. For more information see: http://blog.joelesler.net/2010/03/offset-depth-distance-and-within.html

distance: {distance value}

The distance keyword allows the rule writer to specify how far into a log line Sagan should ignore before starting to search for the specified pattern relative to the end of the previous pattern match.

For example:

content:"GET"; depth:3; content:"downloads"; distance:10;

This will cause Sagan to look for the word "GET" within the first 3 bytes ( depth) of the log line. The next content will start looking for the term "downloads" 10 bytes away from the previous depth. The above would match on the term "GET /content/downloads" but not "GET /download". The " /content/" (10 bytes) is skipped over in the distance.

This function is identical to Snort's "distance" rule option. For more information see: http://blog.joelesler.net/2010/03/offset-depth-distance-and-within.html

email: {email address}

If present in a rule, Sagan will e-mail the event to the email address supplied.

email: bob@example.org

Note: This requires Sagan to be compiled with libesmtp support.
facility: {sylog facility}

Searches only messages from a specified facility.

facility: daemon;

xbits: set, {xbit name}, {expire time}

This option is used in conjunction with xbits: unset, isset, isnotset. This allows Sagan to "track" through multiple log events to trigger an alert. For example, let say you want to detect when "anti-virus" has been disabled but is not related to a system reboot. Using the xbit set you can turn on a xbit when a system is being rebooted. Our xbit set would look like this:

xbits: set, windows_reboot, 30;

We are "setting" a xbit named "windows_reboot" for 30 seconds. This means that thw "windows_reboot" xbit will "expire" in 30 seconds. The xbit set automatically records the source and destination of the message that triggered the event. It is important to point out, the source and destination address is what Sagan has normalized through parse_src_ip, parse_dst_ip or liblognorm.

xbits: {unset|isset|isnotset},{by_src|by_dst|both|reverse|none},{xbit name}

This option works in conjunction with the xbit set option. In the xbit set example above, we are trying to detect when a systems "anti-virus" has been disabled and is not related to a system reboot. If Sagan detects a system reboot, it will set xbit "windows_reboot". Another rule can us the presence, or lack thereof, to trigger an event. For example:

xbits: isnotset, by_src, windows_reboot;

This means, if the "windows_reboot" xbit is not set (ie - it did not see any systems rebooting), trigger an event. The by_src tells Sagan that the trigger ( isnotset) is to be tracked by the "source" IP address. by_src, by_dst, both and none are valid options.

More examples:

xbits: isset, both, myxbit;

If the xbit "myxbit" isset, then trigger an event/alert. Track by the source of the log message.

xbits: isnotset, both, myxbit;

If the xbit "myxbit" isnotset, then trigger an event/alert. Track by both the source and desination of the message.

xbits: unset, both, myxbit;

This unset removes an xbit from memory. In this example, unset is removing a xbit "myxbit" if the source and destination math (both).

Example of xbit use can be found in the rules https://wiki.quadrantsec.com/twiki/bin/view/Main/5001880 and https://wiki.quadrantsec.com/twiki/bin/view/Main/5001881 . The first rule (5001880) "sets" a xbit is a Microsoft Windows account is "created". The second rule (5001881) alerts an account is "enabled", but the xbit has not (isnotset) set. In this example, it's normal for a users account to be "created and then enabled". However, there might be an anomaly if an account goes from a "disabled" and then "enabled" state without being "created".

xbits: noalert;

This informs Sagan to preform a xbit operation, such as set or unset, but do not generate an alert. This is useful when used in conjunction with the set and unset xbit options.

fwsam: {src|dst}, {number} {second|minute|hour|day|week|month|year}

This informs Sagan that if the rule is successfully trigged, the source or destination IP address should be automatically firewalled via the "Snortsam" facility.

fwsam: src, 1 day;

This would firewall the offending source for 1 day. For more information about Snortsam, see: http://www.snortsam.net

level: {syslog level};

Seaches only message from a specified syslog level.

level: notice;

level: "{level}"

meta_content: "string %sagan% string",$VAR;

This option allows you to create a content like rule option that functions with variable content. For example, let's say you want to trigger on the strings "Usernname: bob", "Username: frank" and "Username: mary". Without meta_content, this example would reguire three seperate rules with content options. The meta_content allow you make one rule option with multiple variables. For example:

meta_content: "Username|3a| %sagan%", $USERS;

Note: The |3a| is the hexidecimal representation of a ':' .

The %sagan% variable is populated with the values in $USERS. To populate the $USER variable, the sagan.conf would have the following variable declaration:

var USERS [bob, frank, mary]

If Sagan detects "Username: bob", "Username: frank" or "Username: mary", an event will be triggered.

Like content the ! can be applied. The ! is a "not" operator. For example:

meta_content:!"Username|3a| %sagan%", $USERS;

This will only trigger an event if the content is not "Username: bob", "Username: frank" or "Username: mary". That is, the content must not have any of the values.

The %sagan% portion of meta_content is used to specify "where" to put the $USERS defined variable. For example:

meta_content: "Username|3a| %sagan% is correct", $USERS;

Will look for "Username: bob is correct", "Username: frank is correct" and "Username: mary is correct".

meta_depth: {depth value}

Functions the same as depth for content but for meta_content. The meta_depth keyword allows the rule writer to specify how far into a log line Sagan should search for the specified patterns from a given offset.

For example, if $VAR is set to "mary, frank, bob":

meta_content: "%sagan%", $VAR; meta_depth: 10;

This would start searching at the begining of the log line (default meta_ offset: 0) and search only 10 bytes deep for the term "mary", "frank" or "bob".

Example with offset and depth used together:

meta_content: "bob"; meta_offset: 5; meta_depth: 10;

Sagan will start searching for the term "mary", "frank" or "bob" when it gets to 5 bytes into the log line (see meta_offset). It will only search for "mary", "frank" or "bob" after the offset for 10 bytes.

This function is identical to Snort's "depth" rule option. For more information see: http://blog.joelesler.net/2010/03/offset-depth-distance-and-within.html

meta_distance: {distance value}

Functions the same as distance for content but for meta_content. The meta_distance keyword allows the rule writer to specify how far into a log line Sagan should ignore before starting to search for the specified patterns relative to the end of the previous pattern match.

For example, if $VAR1 is set to "GET" and "POST" and $VAR2 is set to "download" and "upload":

meta_content:"%sagan%", $VAR1; meta_depth: 4; meta_content:"%sagan%", $VAR2; meta_distance:10;

This will cause Sagan to look for the word "GET" or "POST" within the first 4 bytes (meta_depth) of the log line. The next meta_content will start looking for the term "download" or "upload" 10 bytes away from the previous meta_depth. The above would match on the term "GET /content/downloads" but not "GET /download". The " /content/" (10 bytes) is skipped over in the distance.

This function is identical to Snort's "distance" rule option. For more information see: http://blog.joelesler.net/2010/03/offset-depth-distance-and-within.html

meta_offset: {offset value};

Functions the same as offset for content but for meta_content. The meta_offset keyword allows the rule writer to specify where to start searching for a patterns within a log line. This is used in conjunction with content.

For example, $VAR is set to "mary", "frank" and "bob".

meta_content: "%sagan%", $VAR; meta_offset: 5;

This informs meta_content to start searching for the term "mary", "frank" or "bob" after it is 5 bytes into the log line.

This function is identical to Snort's "offset" rule option. For more information see: http://blog.joelesler.net/2010/03/offset-depth-distance-and-within.html

meta_nocase;

This makes the previous meta_content option case insensitive.

meta_content: "Username: ", $USERS; meta_nocase;

If $USERS is populated with "bob", "frank" and "mary", meta_content will ignore the case. That is, "Username: mary" and "Username: MARY" will be detected. Without the meta_nocase, meta_content is case sensitive.

meta_within: {within value}

Functions the same as within for content but for meta_content. The within keyword is a meta_content modifier that makes sure that at most N bytes are between patterns matches using the meta_content keyword.

For example, $VAR1 is set to "GET" and "POST", while $VAR2 is set to "downloads" and "uploads";

meta_content:"%sagan", $VAR1; meta_depth:4; meta_content:"%sagan%", $VAR2; meta_distance:10; meta_within:9;

The first meta_content would ony match on the world "GET" or "POST" if it is contain within the first 4 bytes of the log line. The second meta_content looks for the term "downloads" or "uploads" if it is a meta_distance of 10 bytes away from the meta_depth. From the meta_distance, only the first 9 bytes are examined for the term "downloads" or "uploads" (which is 9 bytes).

This function is identical to Snort's "within" rule option. For more information see: http://blog.joelesler.net/2010/03/offset-depth-distance-and-within.html

-- ChampClark - 2014-08-15 - Added new meta_content options, offset, within, depth and distance.

msg: "human readable message"

The "human readable" message or description of the signature.

msg: "Invalid Password";

nocase

Used after and in conjuction with the "content" option. This forces the previous content to search for the {search} string reguardless of case.

content: "sagan"; nocase;

This would search for the term "sagan" reguardless of it's case (ie - Sagan, SAGAN, etc).

normalize;

Informs Sagan to "normalize" the syslog message using the LibLogNorm library and Sagan "rulebase" data.

Note: This requires that Sagan be built this LibLogNorm. Sagan versions older thanat 1.1.0 required a normalization type. As of Sagan 1.1.0, this is no longer the case.
offset: {offset value};

The offset keyword allows the rule writer to specify where to start searching for a pattern within a log line. This is used in conjunction with content.

For example:

content: "bob"; offset: 5;

This informs content to start searching for the term "bob" after it is 5 bytes into the log line.

This function is identical to Snort's "offset" rule option. For more information see: http://blog.joelesler.net/2010/03/offset-depth-distance-and-within.html

parse_dst_ip: {destination position}

Uses Sagan's dynamic IP parsing to locate the "destination" address within a syslog message.

parse_dst_ip: 2;

The second IP address found within the syslog message will be used as the destination address. This is useful when LibLogNorm fails, is to difficult use or the syslog message is dynamic.

parse_port

Attempts to determine the "source port" used from the contents of a syslog message. For example, Bind/DNS messages look something like; "client 32.97.110.50#22865". The "22865" is the source port. Sagan will attempt to extract and normalize this information.

parse_port;

parse_proto

Attempts to determine the protocol in the syslog message. If the syslog message contains terms in the "protocol.map" (for example, ICMP, UDP, TCP, etc), Sagan assigns the protocol to the assigned value. See fields assigned as "message" in the protocol.map.

parse_proto;

parse_proto_program

Attempts to determine the protocol by the program generating the message. Values are assigned from the "protocol.map" (program fields). For example, if the program is "sshd" and the parse_proto_program option is used, TCP is assigned.

parse_proto_program;

parse_src_ip: {source position}

Uses Sagan's dynamic IP parsing to locate the "source" address within a syslog message.

parse_src_ip: 1;

The first IP address found within the syslog message will be used as the source address. This is useful when LibLogNorm fails, is to difficult use or the syslog message is dynamic.

pcre: "{regular expression}"

"Perl Compatible Regular Expressions" (pcre) let Sagan search syslog messages using "regular expressions". While regular expressions are powerful, they do require slightly more CPU to use. When possible, use the "content" option.

pcre: "/broken system|breaking system/i";

Looks for the term "broken system" or "breaking system" reguardless of the strings case.

pri: {priority}

Sets the prority of a alert/signature.

pri: 1;

If "pri:" is set, it will over ride the "classtype:" priority.

program: {program name|another program name}

Search only message that are from the {program}. For example:

program: sshd;

This will search the syslog message when it is from "sshd". This option can be used with multiple OR's. For example:

program: sshd|openssh;

This will search the syslog message when the program that generated it is "sshd" OR "openssh".

reference: {reference name}, {reference url}

Sets a reference for the signature/alert. These can be pointers to documentation that will provide more information reguarding the alert.

reference: url, www.quadrantsec.com;

If the signature/alert is triggered, the reference will be "http://www.quadrantsec.com".

reference: nessus, 1000;

Will refer to the Nessus site looking up the ID "1000". For more references, see https://github.com/beave/sagan-rules/blob/master/reference.config

rev: {revision number}

Revision number of the rule. Increment this when a rule is changed.

rev: 5;

Revision number 5 of the rule.

sid: {id number}

"sid" is the signature ID. This has to be unique per signature.

sid: 5001021;

Sagan signatures start at 5000000. To view the "last used" signature, see https://github.com/beave/sagan-rules/blob/master/.last_used_sid

tag: {syslog tag}

Informs Sagan to only search syslog message with the specified tag.

tag: 2d;

threshold: type {limit|threshold}, track {by_src|by_dst}, count {number of event}, seconds {number of seconds}

This allows Sagan to threshold alerts based on the volume of alerts over a specified amount of time.

threshold: type limit, track by_src, count 5, seconds 300;

Sagan will limit the amount of alerts via the source IP address if the count exceeds 5 within a 300 second (5 minute) period.

within: {within value}

The within keyword is a content modifier that makes sure that at most N bytes are between pattern matches using the content keyword.

For example:

content:"GET"; depth:3; content:"downloads"; distance:10; within:9;

The first content would ony match on the world "GET" if it is contain within the first 3 bytes of the log line. The second content look for the term "downloads" if it is a distance of 10 bytes away from the depth. From the distance, only the first 9 bytes are examined for the term "downloads" (which is 9 bytes).

This function is identical to Snort's "within" rule option. For more information see: http://blog.joelesler.net/2010/03/offset-depth-distance-and-within.html

-- ChampClark - 2014-08-15 - Added new meta_content options, offset, within, depth and distance.

Edit | Attach | Watch | Print version | History: r24 < r23 < r22 < r21 < r20 | Backlinks | Raw View | Raw edit | More topic actions
Topic revision: r24 - 2017-06-07 - ChampClark
 
This site is powered by the TWiki collaboration platform Powered by PerlCopyright © 2008-2017 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TWiki? Send feedback