/*- * Copyright (c) 2007 Aaron L. Meihm * Copyright (c) 2007 Christian S.J. Peron * All rights reserved. * * $Id: bsmtrace.c,v 1.19 2007/10/09 02:22:15 csjp Exp $ * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ Introduction BSMtrace is a utility that processes audit trails, or real-time audit feeds provided by audit pipes. It loads a set of finite state machines or sequences from the supplied configuration file and watches the audit streams for instances of these sequences. For more information, the example bsmtrace.conf file should be reviewed. The underlying premise behind bsmtrace is that the user can specify sequences of events that are common after or during system compromise. These might include things like: - A subject having 50 failed, then one successful login over the course of a week. Something you might expect to find during an SSH brute force. - User "nobody" creating files outside of /usr/local/www - User "nobody" executing administrative utilities, or utilities like id(1) to determine which level of privilege has been acquired - Detect the execution of common shellcode where certain sequences don't normally appear, for example, the typical execution pattern of bind when it services a DNS request might be: [1] recvmsg(2) [2] sendmsg(2) [1] recvmsg(2) [2] sendmsg(2) . . . When the return address of the stack is over-written during a buffer overflow attack, the execution pattern of the process will change, resulting in the execution of system calls outside it's regular sequence: [1] recvmsg o buffer overflow is exploited, and now the execution pattern might look something like this: [2] socket [3] bind [4] listen [5] accept [6] dup2 [7] exec - Users or groups of users executing utilities, looking at (or attempting) files they shouldn't be. Because bsmtrace acquires it's information from the audit stream, we can be reasonably certain that we can trust the data. Unlike syslog, the BSM audit framework targets Commmon Criteria (CC) requirements, to help ensure that the audit trail is robust, protected and maintains high levels of integrity. bsmtrace also allows the administrator to setup "triggers" or scripts to execute during one or more state transitions, allow them to execute user defined scripts in the event that a certain series of actions have occured. COMMAND LINE OPTIONS -a Specify an audit trail to process -f Specify a signature file or policy -F Run in the foreground -p Specify PID file -v Print bsmtrace version EXAMPLE bsmtrace -f /etc/security/policy.cnf BSMTrace Configuration Contents * 1 Defining Sets * 1.1 Defining Subject Sets * 1.2 Defining Event Sets * 1.3 Defining Object Sets * 1.4 Defining Log Channel Sets * 2 Defining Logging Channels * 3 Sequence Structure * 4 Sequence Options * 5 Defining States * 6 State Options * 7 Example Sequences * 7.1 Definitions used for examples * 7.2 Attempts to execute firewall programs by users not listed as firewall admins * 7.3 Execution of any program outside of predefined trusted directories * 7.4 Creation of a symlink in a world-writable directory * 7.5 Several login failures followed by a success * 7.6 Calling a system call in the exec family after binding to a socket * 7.7 Any failed attempt to write to a file * 7.8 Multiple attempts to read a config file Defining Sets There are two different kinds of sets that can be defined in the bsmtrace configuration file: anonymous and named. Anonymous sets are used in the definition of sequences, but must be fully re-declared if you intend to use it multiple times as it is not assigned an identifier that would let you reference it later, hence 'anonymous'. The syntax for declaring an anonymous set is: { element [, element, ...]; }. An example of an anonymous set would be: { alm, csjp, mak; } Named sets can be used anywhere anonymous sets can by referencing their name. The syntax for declaring a named set is: define set $name { element [, element, ...]; };. An example of a named set would be: define set $daemons { bind, postfix, postmaster, www; }; Defining Subject Sets Subject sets can contain one of five different types of elements: AUIDs, RUIDs, EUIDs, RGIDs, and EGIDs. All of these are examples of either user identifiers or groups identifiers. Only one of these types may appear inside a given set definition, and must be properly declared in the type field of the definition. Defining Event Sets Event sets can contain one of two types of elements: Audit Events or Audit Classes. Audit events and the audit class to which they belong are listed in /etc/security/audit_event. Audit classes are defined in /etc/security/audit_class. More information on audit events and classes are available in the article explaining setting up the audit system. Defining Object Sets Object sets can currently only contain one type of element: Paths. Paths are simply the pathnames to objects in the filesystem. Defining Log Channel Sets Log channel sets can only contain one type of element: Log Channels. Log channels must be declared first before their names may be included in a log channel set. See the next section for an explanation of how to define a log channel. Defining Logging Channels Log channels provide an additional way to record matched sequences. They allow three kinds of logging to occur: 1. BSM, which outputs raw BSM records to a file. 2. Path, which outputs translated BSM records to a file. 3. Syslog, which communicates with the syslog daemon. The path option can be used by both BSM and Path types, while the priority option can only be used for the syslog type. The syntax for defining a log channel is: log-channel $name { [path string;] [priority string;] }; Sequence Structure Sequences are finite state machines (FSMs) that are contained inside of bsmtrace. These FSMs are composed of one or more states which are matched against events generated by the audit framework. Sequences have a number of options which bind them to processes, users, or sessions. These options are listed in the next section. Sequences, unlike other constructs, must always have a name associated with them. The syntax of a sequence definition is: sequence name.of.sequence { subject [not] set_of_subjects; [log set_of_logchannels;] [priority integer;] [scope scope_of_sequence_matching;] [serial integer;] [timeout integer scale;] state0; ... stateN; }; Sequence Options bsmtrace supports a number of options that can be specified on a per sequence basis. These options control attributes like timeouts, priority levels, and other operating features. These options are outlined in the table below: +----------------------------------------------------------------------+ | Option | Required | Description | |----------+----------+------------------------------------------------| | log | NO | Specify an anonymous or named set of logging | | | | channels. | |----------+----------+------------------------------------------------| | priority | NO | If a sequence is detected, specify which | | | | priority it should be alerted with. | |----------+----------+------------------------------------------------| | | | Specify a scope. The options are global, | | | | process, and session. | | scope | NO | | | | | NOTE: This option has not been implemented | | | | yet. | |----------+----------+------------------------------------------------| | serial | NO | Specify a serial number for this sequence. | |----------+----------+------------------------------------------------| | subject | YES | Specify an anonymous or named set of subjects. | | | | This can optionally be any. | |----------+----------+------------------------------------------------| | | | Specify a timeout before the sequence expires. | | timeout | NO | This option only really makes sense for | | | | sequences which have multiple states. | +----------------------------------------------------------------------+ Defining States States are the fundamental unit of FSMs. bsmtrace creates an FSM for a process/user/session as soon as the first state of an FSM is matched, and then proceeds to monitor that process/user/session for events that can match the next state in a chain. When a state is matched, it executes any triggers it may have. States have a number of options which control their matching behavior. These options are listed in the next section. The syntax of a state definition is: state { event set_of_events; [multiplier integer;] [object set_of_objects;] status success_of_event;] [trigger shell_command;] }; State Options Inside of a state definition, there are a number of options that can be used. They are: +----------------------------------------------------------------------+ | Option | Required | Description | |------------+----------+----------------------------------------------| | | | Set of events that this state can match. | | event | YES | | | | | The keyword 'any' can be used here in place | | | | of a set. | |------------+----------+----------------------------------------------| | | | Functionally, this creates multiple copies | | multiplier | NO | in the sequence, each of which must be | | | | matched to move on to the next state. | |------------+----------+----------------------------------------------| | | | Set of objects that this state can match. | | object | NO | | | | | The keyword 'any' can be used here in place | | | | of a set. | |------------+----------+----------------------------------------------| | | | Matches a state against an audit event based | | | | on whether the system call that generated | | status | YES | the event succeeded. | | | | | | | | Valid options are: any, failure, and | | | | success. | |------------+----------+----------------------------------------------| | trigger | NO | Specifies a shell command to be executed | | | | when a state is matched. | +----------------------------------------------------------------------+ Example Sequences Definitions used for examples log-channel $syslog { priority user.notice; }; define set $my_log_channels { $syslog; }; define set $fwadmins { alm, csjp; }; define set $execution { AUE_EXEC, AUE_EXECVE; }; define set $login { AUE_openssh, AUE_login, AUE_su; }; define set $trusteddirs { /bin, /sbin, /usr/bin, /usr/sbin, /usr/local/bin, /usr/X11R6/bin, /usr/local/sbin, /usr/games; }; define set $opendirs { /tmp, /var/tmp; }; define set $fwtools { /sbin/ipfw, /sbin/pfctl, /sbin/ipf; }; Attempts to execute firewall programs by users not listed as firewall admins sequence firewall.change.attempt { subject not $fwadmins; state { event $execution; object $fwtools; status any; }; }; Execution of any program outside of predefined trusted directories sequence non.trusted.exec { subject any; state { event $execution; object not $trusteddirs; trigger "/usr/bin/logger non.trusted.exec: $subject executed $object"; status success; }; }; Creation of a symlink in a world-writable directory sequence mktemp.race { subject any; state { event { AUE_SYMLINK; }; object $opendirs; status success; }; }; Several login failures followed by a success sequence login.brute.force { subject any; timeout 60 seconds; priority 100; state { event $login; status failure; multiplier 3; }; state { event $login; status success; }; }; Calling a system call in the exec family after binding to a socket sequence httpd.exec { subject { nobody; }; state { event { AUE_SOCKET; }; status success; }; state { event { AUE_BIND; }; status success; }; state { event $execution; status any; }; }; Any failed attempt to write to a file sequence failed.file.write { subject { csjp; }; log { $syslog; }; state { event { fw; }; status failure; }; }; Multiple attempts to read a config file sequence five.config.file.read { subject { csjp; }; serial 2343445445; timeout 60 seconds; scope global; log { $syslog; }; priority 100; state { event { fr; }; status any; object { /etc; }; trigger "/usr/bin/logger config file read"; multiplier 5; }; };