Thursday, October 17, 2013

OpenBSM auditd on OS X: these are the logs you are looking for

OpenBSM is an implementation of the now decades old Sun Basic Security Module (BSM) API and file format, written for OS X Panther (10.3) by McAfee Research under contract to Apple. The work was completed to provide OS X with security auditing, a core component required for Common Criteria evaluation, which is itself a necessary step for doing business with the US Federal Government and other governments around the world that respect the standard.

Robert Watson, one of the original authors, gives some background on the project in this interview, including the rationale for choosing BSM:
During the work for Apple, we identified Sun's BSM API and file format as the de facto industry standard for UNIX audit implementations -- it was extensively documented, the foundation of a previously evaluated system, and was extensible to new events and data types.
Apple released the code under a FreeBSD license, enabling inclusion in FreeBSD, currently maintained by Trusted BSD.

Before 10.6 the common criteria audit tools needed to be downloaded and installed separately, but have been installed by default since then. The functionality is a little-known goldmine for security purposes. Der Flounder has a good introduction to the configuration, but I'm going to cover some different aspects.

The /etc/security/audit_control file specifies what to log and retention/rotation policies:
# $P4: //depot/projects/trustedbsd/openbsm/etc/audit_control#8 $
expire-after:60d AND 1G
  • dir: where to write the logs
  • minfree: minimum % disk free until /etc/security/audit_warn starts getting called. You can customise/replace this script. The default is simply:
    logger -p security.warning "audit warning: $@"
  • flags: what user-attributable audit event classes are recorded for all users. You'll want to define a custom class (zz), more on that in a moment.
  • naflags: what non-user-attributable (system daemons etc.) event classes are recorded for all users. This config records the same events as specified by zz.
  • policy: cnt allows processes to still run if they aren't being audited (e.g. if the disk is full), argv records commandline arguments to execve. The other options are mostly either crazy sauce (halting the system if unable to audit), or not implemented.
  • filesz: rotation size threshold
  • expire-after: conditions for expiration of log files (removal)
  • everything else: here be undocumented dragons.
The /etc/security/audit_class file defines some default groups of events, which you can use in flags/naflags above to decide which events to record. I found I needed to create a custom class to log the right types of events. Here's the default file with a custom class added:
# $P4: //depot/projects/trustedbsd/openbsm/etc/audit_class#6 $
# $FreeBSD$
0x00000000:no:invalid class
0x00000001:fr:file read
0x00000002:fw:file write
0x00000004:fa:file attribute access
0x00000008:fm:file attribute modify
0x00000010:fc:file create
0x00000020:fd:file delete
0x00000040:cl:file close
0x00000400:na:non attributable
0x00002000:aa:authentication and authorization
0xffffffff:all:all flags set
Then you need to annotate the events you want to log with your custom class in /etc/security/audit_event. An example line to log execve (process execution) is below:
There is a huge menu of events to choose from, here are some examples: network socket connect/bind/accept, clock changes, auditctl, login/logout, mount, reboot, passwd, crontab modification, ssh, create/modify/update user/group, execve, fork, chmod, chown and many more.

The final piece of configuration is /etc/security/audit_user, which allows for per-user customisation that is combined with the global settings. This allows you to, for example, treat root differently to other users. The format is
and the default, below, only contains an customisation for root. alwaysaudit is 'lo' which records login/logout, password changes etc. while neveraudit is 'no' which is no exclusions.
# $P4: //depot/projects/trustedbsd/openbsm/etc/audit_user#3 $
# $FreeBSD: head/contrib/openbsm/etc/audit_user 157137 2006-03-26 01:44:35Z rwatson $
The auditd LaunchDaemon (/System/Library/LaunchDaemons/ which runs /usr/sbin/auditd) is responsible for handling the logfiles, rotation etc. There is a commandline utility /usr/sbin/audit which can be used to start/stop/reconfigure the daemon. "audit -s" is supposed to cause a re-sync of configuration, but I found a reboot was often the only really reliable way of making sure new config was applied.

You can get a live feed of the events being logged using praudit, which is very handy for debugging and checking configuration:
sudo praudit -l /dev/auditpipe
This is also the tool to use to get a textual representation of the binary auditlog files which are in the format of starttime.endtime:
praudit -l /var/audit/20130921124047.20130924235958
There is a GUI app available in the app store for visualising the binary log files, I haven't used it, but it looks reasonable for inspecting small amounts of logs. I wanted to apply existing large-scale log analysis capabilities, which would have been easy had the logs been sent to Apple SysLog (ASL) in plaintext. Sadly they aren't, so if you want to use them off the host you're going to need to either use praudit to convert them to text and ship them, or pump them into ASL yourself, or ship the binary log and convert it to text on the server-side. Running praudit over a set of logs is quite CPU intensive.

auditreduce allows you to read binary audit files and output filtered binary files, but its capabilities are very limited. You can't filter by IP for example (although the functionality was obviously planned since it is partially implemented, it will take a -o sock="" value, but the filter doesn't get applied). This produces events related to any file under /etc:
auditreduce -o file="/etc" /var/audit/20131018010044.20131023043346 | praudit -l
An event output by praudit will look like this (the one I grabbed happened to be an auditd log rotation):
# auditreduce -m AUE_EXECVE /var/audit/20131023061325.20131023062325 | praudit -l
header,159,11,execve(2),0,Tue Oct 22 23:23:25 2013, + 131 msec,exec arg,/usr/sbin/audit,-n,path,/usr/sbin/audit,path,/usr/sbin/audit,attribute,100755,root,wheel,16777220,2190270,0,subject,-1,root,wheel,root,wheel,50716,100000,0,,return,success,0,trailer,159,
Since that is basically gibberish, you can use the praudit xml output to get a better idea of what each value means:
# auditreduce -m AUE_EXECVE /var/audit/20131023061325.20131023062325 | praudit -x
<record version="11" event="execve(2)" modifier="0" time="Tue Oct 22 23:23:25 2013" msec=" + 131 msec" >
<attribute mode="100755" uid="root" gid="wheel" fsid="16777220" nodeid="2190270" device="0" />
<subject audit-uid="-1" uid="root" gid="wheel" ruid="root" rgid="wheel" pid="50716" sid="100000" tid="0" />
<return errval="success" retval="0" />

1 comment:

Unknown said...

Hey thanks for the post. Wondering if you had any thoughts on this ... I'm taking a look at processing these audit logs. I'm using FSEvent to try and determine when the files are written to and rotated rather than polling etc.

This seems to work for some operations, e.g. when a rotation occurs I see this:

Change 130103152 in /private/var/audit/20150104125557.not_terminated, flags 82176
Change 130103155 in /private/var/audit/20150104100226.not_terminated, flags 67584
Change 130103156 in /private/var/audit/20150104100226.20150104125557, flags 67584
Change 130103162 in /private/var/audit/current, flags 262912

which corresponds to deletions / creations etc., but I can't see the current / not_terminated log being written to as audit events are written there. This post kind of reports similar things, but I don't think it explains it in this case as I see some events (those above). In particular I'm keen to see the kFSEventStreamEventFlagItemModified event, which I don't seem to be getting (I do get it if I create and modify a file in the directory), e.g.:

Change 130122917 in /private/var/audit/, flags 88320

Any thoughts? :)

I think I'll just have to poll otherwise ...