Quick Index


|
|
Audit, A policy driven security checker
for
a heterogeneous Environment
Linda Bissum
ABSTRACT
Security audit programs can be of great help to the
system administrator in the work of ensuring an adequate
level of security. One common problem with existing
security audit programs, however, is that they implement
default policies embedded in their code. Such embedded
policies are not always in agreement with those of the real
world (e.g., when the program complains about
/usr/spool/uucppublic being world writable).
It was therefore set as a goal to design and implement a
security auditing program which did had no hard coded
policies embedded in the program code. The result was the
security audit program called Audit , which allows
policy decisions (such as whether users should be allowed
to have private .rhosts file in their home
directory) to be made at the local site - without requiring
any program modifications. This has been achieved by making
policy- and platform-dependent decisions in a specialized
audit control language which is used to write the control
file(s).
1. Introduction
Audit is a a program designed to assist the
system administrator in performing security audits which
check local security policies. Audit is also
designed for a heterogeneous environment, enabling new
platforms to be audited, without requiring any modification
to the audit program itself.
Audit is implemented in perl. The perl language
has the advantage of making Audit easily portable,
as most porting problems already have been resolved in the
perl interpreter. The parsing of the audit control file(s)
is implemented by recursive descent, chosen for its
simplicity and fast implementation. Audit performs
its security audit by checking files and their attributes
(file type, permissions, size, checksum, etc). However,
Audit knows about items like home directories and
startup files and can audit them in a relevant fashion. In
addition, Audit supports auditing of the content
of a file, through an interface which enables
Audit to call an external script or program to
check the files and/or their contents.
The alpha version of Audit has been running on
several platforms (BSD, SunOS & SVr4) for some time; a
beta version is expected to be available for distribution
at the time of the conference.
This paper discusses goals for design and
implementation, as well as showing practical examples of
control files implementing different policies. The paper
also discusses how implementation and installation can be
done in order to prevent tampering by intruders to the
greatest possible extent.
2. Purpose
One of the driving forces behind the development of
Audit was the fact that existing security auditing
programs contain embedded policies regarding what, when,
and how to audit. This complicates modification of the
security auditing program to check a system in accordance
with local policy and custom. In addition, this approach
obscures what is checked, a fact which can make the
security checker a double edged sword, because it can lull
the system administrator into a false sense of security.
While Audit cannot, and does not claim to, fix all
of the problems mentioned above, it is an experiment of
developing a highly configurable auditing program. Before
beginning development of the current incarnation of
Audit , the following goals where set forth:
- It should be possible to make changes to the security
audit (to reflect the security policy) without a need to
change any code in the auditing program.
- The audit program should have no default policies
embedded in the code.
- The audit program should be able to audit files
relative to users home directories.
- The audit program should be able to handle
exceptions
- The audit program should report errors in as secure a
manner as possible.
Many security violations in UNIX are caused by critical
files or directories having permissions flags set
incorrectly, while others are caused by faulty content of
configuration files. If these problems could be addressed
effectively, it should be possible to detect other security
problems, such as unauthorized modification of system
binaries.
Audit is primarily oriented towards auditing
file attributes for a large number of files. It can,
however, perform other kinds of checks, through call of
external scripts and programs, such as checking the content
of the password file. It was decided not to provide this
kind of audits as built-in test, partly because of the
difficulties of providing portable solutions, and partly
because of problems in providing a good simple audit
control language definitions. Instead, a generalized
interface to call specialized utilities is provided.
Example of such utilities (which are part of the
Audit distribution) are perl scripts for checking
the password and group file. External scripts also have the
advantage of extensibility.
3. Existing Practice
Several public distributable security audit program are
available. A brief overview of some of these are given
below:
-
Secure is a security checker written in Bourne
Shell. This shell script can be found in the old UNIX
System Security book by Wood and Kochan.
The main value of this script (in accordance with
its goal) is as a teaching device.
It is very System V rel. 2 oriented, and covers no
networking issues at all.
-
Setperm is also a shell script from the Wood
and Kochan book.
In addition, a similar version, written in C, can be
found on Xenix systems.
This utility can check owner, group, and permissions
of files.
It compares the actual values with a list and
reports any found differences.
-
Spy is an HP-UX specific security checker.
It is not publicly available; however, it was
presented at LISA III by Bruce Spence, and can be found
in the conference proceedings, with some implementation
details.
-
COPS , written by Dan Farmer, is the best
known of the publicly available security checkers.
Its greatest strength is its ability to check users'
configuration files (e.g., .cshrc) and, through its
built-in expert system, to check to see if a user has
been compromised through incorrect permissions on the
dot-files.
It greatest weakness is that many policy decisions
have been embedded in the code. It is also difficult to
change the audit to embed local requirements.
-
Crack (written by Alec David Muffett) is a
suite of Unix programs designed to quickly and
efficiently find easily guessable passwords in standard
crypt() encrypted Unix password files.
This program is not a audit program in the sense of
the other programs mentioned here, however it should be
part of any security sensitive system administrator
toolbox.
4. HeterogeneityAn important goal of
Audit was the capability to support multiple
platforms without modification to the audit program itself.
With the usage of audit control files, this need has been
eliminated. However, if the audit control files need to be
distributed to the hosts being checked (using some scheme
based on operating system and hardware platform), the
problems in doing so would diminish the value in the
heterogeneity on the program.
Unfortunately, there is currently no way to avoid the
differences between operating systems or vendors.
It has therefore been necessary to design Audit
so it can distinguish between information related to the
system currently being audited and information related to
other systems or hosts (which has no bearing in the current
audit).
The problem has been minimized through use of
conditional expressions in the audit control language and
through support of multiple audit control files.
The Audit control files can be distributed to
all hosts, independent of the underlying operation
system.
This can be done with a program such as
rdist(1) or by read-only NFS mounts of the
necessary directories.
Of course, if the control files are made available
through NFS mounts, great care must be taken that they
cannot be modified on the remote host.
As a minimum, the files must be located on a file system
mounted read-only on the audit master; it is insufficient
to relay on the NFS read-only mounts, as they can be
by-passed.
It is also possible to bypass the local read-only
mounts, but this requires access to the local host.
The only secure way of providing NFS mounts is to store
the control files on a disk where the read-only mode is
enforced by the hardware.
If the control files are distributed by
rdist(1) , it is wise to ensure they had not been
modified (this too can be done with rdist ), prior
to starting the audit.
In either case, it is a good idea to keep the audit
master host as secure as possible, i.e., by restricted
access, both across the network and physically.
In addition, it is necessary to verify both programs and
control files against copies kept on off-site media.
As for any audit program, it is important to remember
that if an intruder is able to get to the program and
modify it, the audit it performs is no longer useful.
5. Policy IssuesAs previously mentioned, the
current available security auditing programs do not lend
themselves very well to individual site policies.
One of the major goals of Audit was to attempt
to avoid such issues. Some of the ways this has influenced
the design of Audit are:
- If a given file is not be allowed on the system,
these audit programs has no way of perform the necessary
audit.
One good example of such policy decisions is to
decide whether users are allowed to keep their own
.rhosts file. As this file overrides the
content of the system-wide configuration in
/etc/hosts.equiv , the content of such files
can nullify the security policies implemented in the
system files.
Similar considerations can be made for the users
.forward file, which some sites disallow, to
ensure no mail is automatically forwarded out from the
site.
Audit has a built-in mechanism to allow the
system administrator to specify files which are
not allowed on the system, either by a full
path name or relative to the users' home
directories.
In a similar manner, a file can be required
to exist on the system (this is in fact the default) or
can specified as being optional.
- Often it is not necessary to specify exact permission
for a file. For example, it is common among system
administrators to state that a file needs a permission
mode of 755 or less, meaning that a permission mode of
751 or 511 is equally acceptable to a permissions of 755
(here assuming the file is a binary and not a shell
script). Therefore, Audit allows a permission
range to be specified wherever a single permission
normally would be required.
- Certain systems (a gateway, for example) will have
different (and likely more stringent) security
requirements than many other systems on the site. The
design of Audit therefore allows specifications
which state exceptions to the general rules.
6. Audit MethodologyIn UNIX, many security
problems are caused by files or directories with incorrect
permissions. Audit has been primarily been
designed to detect this kind of security problems.
Audit is therefore able to track a large number of
file attributes, such as file checksum, file size, inode
number and hard links, in addition to more traditional
audited file attributes, like owner, group and access
permissions. It provides an effective tool to detect
unauthorized system modifications, such as system binaries,
modified without authorization.
Audit allows, for any given file or directory,
the system administrator to check for any of the following
values:
Most of these values are obtained with the perl
stat() function call. Whether the block size
checks is supported is dependent on the UNIX system
version. Where perl stat() function does not
return a usable value, no check will be performed. If an
unexpected value is found, an error message will be
generated.
Most sites will have no need for auditing all these file
attributes. In fact, some of them will be so cumbersome to
use (such as inode numbers) that they will likely be
different between otherwise identical systems. However,
checking such values is useful when a in-depth security
audit is required. It was therefore decided to include all
file attributes (with the exception of time of last access,
which makes no sense to include), in order to meet the
criteria of no embedded policies in the code.
If file attributes such as inode number, time of last
modification, and time of last status change are verified,
in addition to the usual checksum, owner, group, and access
permissions, it becomes very difficult to make any
modification to such files without it being detected next
time the audit program is executed. On systems with
requirements of high security, the additional work required
creating the audit control files can be justified by the
added safety.
However, to avoid a requirement of all sites to audit
all of these items, Audit uses default values for
each file. The default is initially set to `no auditing' (
-no-audit ), but this default can be set to any
desired value, including a value called error ,
which alway will generate an error messages when
checked.
Values are assigned for each attribute on a file by file
basis, allowing different attributes to be set for
different files. If a file attribute for a given file is
changed, a warning messages will be generated unless the
old value is no-audit or error .
It is also very useful to be able to specify whether a
file is required to be on the system. In Audit it
is possible to specify a file as:
- require If the specified file is not found
on the system, Audit issuing a warning.
- allow Presence of the file is optional;
however, if found, it must adhere to all other required
specifications.
- deny The file must not be found on
the system.
The deny attribute is useful for enforcing
policies to not use certain files, such as .rhosts
, as well as a method to discover files placed on the
system by an intruder. Typical examples of names used by
system crackers to hide hide files, are ``.. ''
(dot-dot-space) and ``...'' (dot-dot-dot).
It is possible to reduce the member of entries in the
audit control files, by using regular expressions in the
file path names. If this is done, one entry can cover a
large number of files with the same attributes, such as
owner, group and access permissions. Using this method it
is not be possible to use checksums or other attributes
which differ between files.
Home Directory AuditingA large number of security
problems are represented by the dot-files in the users'
home directories. Such files can, in some cases, directly
harm the security of the system (.rhosts in specific), or
more indirectly by being writable by others.
It is possible to use the same method as described above
to audit such files, by use of regular expressions in the
path names. However, this method would be cumbersome and
error prone, especially as the directory character (``/'')
cannot be matched by any regular expression. Instead,
Audit supports auditing of files with path-names
relative to the users' home directory.
This allows Audit to audit a specific file in
all users' home directories, without the system
administrator having to specify the path to those homes
(this information will be taken directly from the password
file). The same file attributes can be audited, as with the
file audit described above.
File Content AuditingAudit is not capable
of performing file content auditing directly. However, such
auditing can still be achieved, by calling external
utilities, which currently exist for auditing the following
files:
- passwd This check provides a way to check
most properties of the password file, including
verification of existence of a password on all accounts.
However, it does not include checking of the quality of
the passwords. The quality of the passwords can be better
be ensured through use of a pro-active password checker,
such as passwd+ (Matthew Bishop, A Proactive Password
Checker ) or through use of password cracker, such
as Crack.
- group Audit of the group file. At this time,
the only verification is the existence of a non-password
(a string less than 13 characters) in the password
field.
- shadow Audit of the shadow file. Currently,
only the password field in the shadow file is checked and
it is checked only for existence of a password on all
accounts.
- .rhosts This script checks that the file
does not contain a plus sign and that all other entries
consists of a host name, followed by a user name (i.e.,
only a host name will be considered a security breach,
and reported).
Event AuditingAudit provides no
facilities for events checking. However, a separate program
which checks last login time of users is provided. It is
capable of flagging accounts which have not been used for a
long time and accounts where a login is not expected but
which have been used reasonably.
7. Audit Control LanguageThe audit process is
determined by the audit control language. The use of a
control language is inspired by setperm utility,
however, the audit control language for Audit is
much richer. This is necessary to achieve the required
functionality.
The following is an overview of this language.
A complete syntax specification of the Audit
control language can be found in appendix A.
The audit control language consists of two major parts,
the definition statements and the audit control statements.
Each statement can be preceded by a boolean conditional
clause. The statements will only be effective if the
conditional clause evaluates to true.
The following definition statements are available:
- default Defines alternate default value for
any file attribute.
- define Defines names for string
content.
- program Definition of an external
program.
- read Reads a control file.
- set Assigns values to variables
The audit statements specify which path names must be
audited:
- file Specify expected file attributes for a
file. The path name is relative to root (``/'').
- home Specify expected file attributes for a
file. The path name is relative to the users home
directory.
- request Request to execute a program. No
path name associated with the request. These statements
are all described in some detail below.
The Default StatementThe default
statement is used when it is necessary to define alternate
default value for one or more file attribute. The initial
default for all file attributes are no auditing (
no-audit ).
The default statement can also be used to
substitute the string values for no-audit and
error , if for example audit is used at a
site where a user name is error.
The Define StatementThe define statement
allows definition of named strings, very similar to the C
pre-processor's #define. However, at least in the current
implementation, expansion of defines is done by the lexical
scanner and not by a separate pre-processor.
Audit requires the name of the string to be in
all upper case. This is consistent with common practice in
C and enables a significant speed-up, as only all upper
case lexical symbols must be looked up in the table of
defined strings. An example of a defined string:
define WHEEL wheel,other
where the defined string then can be used as a shorthand
alter in the control file.
The Program StatementThe program
statement provides a way to define an external program,
which later will be called by Audit . Only
programs which are defined in this manner can be called.
program sum /usr/bin/sum;
The program statement provides the system
administrator with a method to specify which file attributes must
be checked prior to the use of the program. \f(CR
program arch /usr/bin/local/arch uid=bin gid=wheel,other;
It is not possible to use a program without first defining it
in this manner. This helps to ensure programs which are executed
from Audit have the expected file attributes.
Audit verifies a program's attributes each time
it is called. While this increases the execution time, it
also assures that the external program satisfies all the
criteria specified in the program statement, even
if called at a much later time in the auditing sequence. In
most cases it is sufficiently to execute a program once,
and assign it to a variable.
The checksum program is treated a bit differently, as it
is called repeatedly. In addition, it would create an
infinitive checking loop, if it was required to check its
own checksum. Therefore, the checksum program (whose
defined name is required to be sum ) is verified
as its expected file attribute values are defined. Later,
the ctime , mtime , and size
attributes are checked at random intervals, to ensure they
have not been altered since the start of the program.
The Read StatementTo avoid that all audit control
information would be required to be kept in a single file,
Audit provides a read command. This command will
cause the specified file to be read before continuing
processing the current file.
if ($OS=bsdi) read audit.bsdi
uid=root gid=wheel size=9673;
The read statement can be used recursively.
The Set StatementIt is possible to set variables,
which later can be used in, for example, conditional
clauses. A variable can either be set to a string \f(CR
if ( $Arch=386 && $Ostype=BSDI ) set Name bsdi/386;
or, more usefully, can be set to the return value of an
external program:
set Arch exec arch;
The latter example executes the program defined in a previous
program statement as arch and places the standard
output in the variable named Arch . It is then possible to
use this in later conditional clauses, such as:
if ( $Arch = sun3 ) file /somefile size=32456;
or in an exec clause, such as
file /etc/syslog.conf uid=root gid=wheel;
file /etc/syslog.conf exec chksyslog $Arch;
The File StatementThe file statement is used for
the main audit control specifications. Each path name which
should be checked require sa definition using this
statement. A full path name is required as there are no
default directory path used.
file /etc/passwd uid=root gid=wheel,other perm=600;
This statement causes the password file to be checked to
ensure it has the expected UID, GID and permissions set. Any
discrepancies will be reported by audit.
It is possible to audit all of the file attributes in
this manner. In addition, an external program can be called
to audit the content of the file. Assuming the file
/usr/audit/bin/pwchk is a script which will check the
password file for, e.g., missing passwords, the following
definition would ensure this check would be performed:
program /usr/audit/bin/pwchk uid=root gid=wheel,other;
file /etc/passwd uid=root gid=wheel,other perm=600;
file /etc/passwd exec pwchk;
Audit is completing the parsing of the audit control
file(s), before it is starting the audit. It is therefore possible
to split the audit definitions, without having the file checked
multiple times.
During the parsing of a file statement, the variable
$file is set to the full path name of the file.
This can be used to give the path-name as a parameter to an
external program.
It is possible to use regular expressions in the path
name to keep the audit control file small. Regular
expressions are discussed later.
The Home StatementThe home statement
works as the file statement, with the difference that the
path names specified are relative to the users' home
directory.
A statement like \f(CR
home \.cshrc perm=640,400;
will be expended to the equivalent of one file statement with
the full path-name for ~/.cshrc for each user found in the password
file.
To simplify the specification, two variables (in
addition to $file ) are automatically set by
Audit .
These are $uid , which will contain the name of
the current user, and $gid , which will contain
the name of the user's main group ID (the one used in the
password files fourth field). \f(CR
home \.cshrc uid=$uid gid=$gid perm640,400;
As the audit rules do not necessarily have to be the same for
all users, there are an except and a for clause,
which modifies the scope of the home statement.
The except clause enables the system
administrator to provide an exception list of users and
groups, for which the statement should not have any
effect:
home \.cshrc required except user=sue,paul
uid=$uid gid=$gid perm640,400;
In a similar manner, the for clause can be used to
target only specific users:
home .profile required for user=sue,paul
uid=$uid gid=$gid perm640,400;
The Request StatementThe request statement
provides an interface to call external programs without
their being associated with the audit of a specific file.
An example of the use of a request statement: \f(CR
request chkpwd;
Regular ExpressionsIn order to support
generalizations, regular expressions are allowed in path
names. This can, for example, be used to help keep the size
of the control file down in size.
For example, in the /usr/lib directory, instead of
listing all the library files individually, one entry in
the audit control file can be used to audit them all:
file /usr/lib/.*\\.a uid=bin gid=bin perm=444;
Such an entry will, of course, not allow the checking of
attributes which are different, such as size or checksum.
When the Audit parser encounters a regular
expression in the control file, it will expand it to a list
of full path names, which match the path-name and create an
entry for each path name in its internal table.
Any file attributes which has been assigned where the
path name has been an regular expression will be permitted
to be over-written by a new value.
However, a file attribute value which has been assigned
by a statement where the path-name did not contain any
regular expression, will not be overwritten later.
If this is attempted by a statement with a path name
which are a regular expression, that assignment will be
silently ignored.
However, if the second statement also had a full path
name, Audit would allow the assignment, but would
issue a warning.
This strategy gives the system administrator some
freedom from the sequence in which statement are written,
as: \f(CR
file /etc/.* uid=bin gid=bin;
file /etc/passwd uid=root gid=wheel,other;
be identical to:
file /etc/passwd uid=root gid=wheel,other;
file /etc/.* uid=bin gid=bin;
This can also be used to ensure that no file is added to a
directory. If all files in the directory are defined with explicit
path names and also explicitly set to required or
optional , an entry like:
file /usr/lib/.* denied
will flag any new file added to the directory. However, in
general, using the count file attribute is probably a
better way to achieve this:
file /usr/lib count=42;
The regular expressions used in the path names have the same
syntax as regular expression in perl (as they are passed to, and
evaluated by the perl interpreter). This, however, has some side
effects in how path names must be specified in the audit control
file.
The dot ('.') is special to regular expression and is
also commonly used in file names.
Because of this, any dot in a file name must be escaped
in order to ensure it is not matched against another
character.
Therefore, a file like the /etc/rc.local must
be specified as /etc/rc\.local , and the
.rhosts file as \.rhosts
The slash ('/') is another special character, both to
regular expressions and UNIX path names. This character is
special to the UNIX kernel and is treated likewise by
Audit . Therefore, no regular expression will be
allowed to stretch across directory boundaries. For
example, the path names /lib/.*\.a will match any
library file in /lib , but will not match any in
/usr/lib . This not only has simplified the
implementation of Audit , it also resembles the
traditional usage of regular expressions in the shell,
which seems desirable.
The above will work because a requirement set by a
regular expression cannot override a request set with an
explicit path name. Audit is keeping track of each
file attribute, whether the request specifying it was done
by a regular expression, or with a explicit path name. The
latter kind of requests will always be allowed to override
the first.
Accumulative Usage of StatementsAudit
uses an accumulative definition scheme. Any file attribute
for a given file which has not been previously defined, can
be defined at any time. Therefore, the statement:
file /vmunix required uid=root gid=wheel perm=755 ;
can be written as
file /vmunix required;
file /vmunix uid=root;
file /vmunix gid=wheel;
file /vmunix perm=755;
While this in itself is not very helpful, it makes a
difference as soon as system specific information is added. If the
kernel was to be checked for size and checksum as well as the
owner, group and permissions from above, the specification could
look like this:
file /.*unix required uid=root gid=other,wheel perm=755;
if ($OS=bsdi) file /vmunix sum="29875 496";
if ($OS=svr4) file /vmunix sum="05104 1435";
if ($OS=mach) file /unix sum="73846 657";
if ($OS=sunos) file /vmunix sum="32251 891";
Still, if a large number of such variants is required, it
will make the audit control file very large and difficult to
maintain. Audit therefore has a read command,
which directs the audit program to read the specified file before
continuing (this function is recursive).
It is therefore possible to split all audit control,
specific to a certain operating system, vendor, or even
host, onto a separate audit control file, which only will
be read if the relevant for the machine currently being
audited.
An example of the read command is shown below:
if ($OS=mach) read audit.mach;
if ($OS=bsdi) read audit.bsdi;
if ($OS=svr4) read audit.svr4;
if ($OS=sunos) read audit.sunos;
8. Error HandlingOne of the concerns in the design
of the Audit program, where how to report any
inconsistencies found during the audit. It is necessary to
choose a mechanism which is difficult to spoof (i.e.,
writing to a local file would be of less use than sending
the reports directly to a central location). It is also
necessary to ensure the amount of auditing information
which is sent to the system administrator is as minimal as
possible. It is a common problem with many existing audit
style programs that way too much information is sent to the
person who is supposed to review this information. If too
much output is generated to state that the situation is
essentially normal, then any possible information about an
abnormal situation is bound to disappear in the general
noise.
On the other hand, it is also necessary to send
information that the audit has been performed and went OK.
It was therefore early on decided to use syslog
for error reporting. It is possible to spoof this approach,
by modifying the syslog.conf file, but if this has
happened, the system is already penetrated and the audit is
not of much use. In addition, it is possible to use
programs such as rdist or fdist (Linda
Bissum and Paul M. Moriarty; Fdist: A Domain Based File
Distribution System for a Heterogeneous Environment ,
USENIX LISA V Proceedings, 1991) to ensure the file are
correct.
It is the intention to write a filtering program to
intercept incoming messages from Audit on the
central host and send information about such problems by
e-mail to interested parties (this program will be part of
the beta release).
9. Audit Control SamplesBelow is a number of small
audit control samples. Neither of these is in any form a
complete audit control file. Instead of showing such a
large file, it is rather the intention to highlight some of
the possible uses of the Audit program.
First a minimum audit control file:
file / count=16 perm=755;
file / uid=root gid=wheel perm=755;
file /tmp perm=755 uid=root gid=wheel perm=777;
file /usr/tmp perm=755 uid=root gid=wheel perm=777;
file /usr/tmp type=dir perm=777;
file /usr/spool/uucppublic
perm=755 uid=uucp gid=uucp perm=777;
file /etc/.* uid=root,bin perm=755,111;
file /etc count=53 uid=root gid=wheel perm=755;
file /etc/passwd perm=644;
file /etc/group perm=644;
file /etc/phones uid=bin gid=bin;
file /bin count=34 id=root perm=755;
file /bin/.* uid=root perm=755;
file /usr count=29 uid=root perm=755;
file /usr/bin count=216 uid=root perm=755;
file /usr/bin/.* uid=root perm=755,111;
This file is so simple, that its practical value is doubtful.
However, with the addition of an explicit list of all set user ID
and set group ID files it is becoming closer to something real.
Below is shown just a few such entries.
file /bin/ps uid=bin gid=kmem perm=4555;
file /bin/rpc uid=root gid=bin perm=4555;
file /bin/rsh uid=root gid=bin perm=4555;
The real definition will of cause need to contain a
definition for all SUID/SGID files, as they otherwise will be
flagged as a security breach.
Setting the default for some of the more interesting
file attributes to something other than `no check' can be
helpful to discover audit control errors. \f(CR
default uid=error gid=error perm=error;
Using these defaults, any file entered into the
Audit table, will be required to specify owner, group, and
permissions. Any other of the file attributes could be set in a
similar fashion.
In order to ensure a high quality audit, all files in
the important directories, such as /, /etc, /dev,
/bin , and /usr/bin all must be placed in the
the audit control file. However, such entries are straight
forward. Audit entries which are in regard to the users
home directory is much more interesting, and the area,
where big differences between sites are to be expected, as
such entries are subject to local security polices.
One such policy issue is whether the users are allowed
to have their private .rhosts file. A strong case
can be made of technical reasons why users should not be
allowed to have their own .rhosts file (with
exceptions of special cases, such as root). However it has
been my experience that, in the name of convenience, many
sites actually allow their users to create and use private
.rhosts files in spite of the security problems
this can create for the responsible system administrator.
Later the sites chose the a different strategy, allowing
the users to create .rhosts files but where the
content of those files is monitored. Audit has
been designed to be able to provide audit capabilities for
all of those strategies. However the third solution,
checking the content of the file, is very likely to be site
dependent. Audit therefore only provides the
necessary mechanism for that check, by calling an external
program to do the required auditing. Below is first a
possible audit specification entry which reports any
.rhosts file (with the exception of the users root
and operator:
home \e\.rhosts deny except user=root,backup:
home \e\.rhosts require for user=root,backup
uid=$uid gid=$gid perm=400,600;
On a site where the users were allowed to create the
.rhosts file, the audit entry could look like this:
home \e\.rhosts allow;
home \e\.rhosts type=file uid=$uid gid=$gid perm=400,600;
This would at least notify the system administrator of such
files with inadequate permissions or ownership.
Alternatively, the .rhosts file could be
allowed but would be required to be examined by an external
program, to ensure its content would not violate local
policy. The home statement for this would look
like:
home \.rhosts allow;
home \.rhosts uid=$uid gid=$gid perm=400,600;
home \.rhosts exec hostchk $file;
This statement would result in any .rhosts file
found in any users directory would be checked by the program
hostchk .
Normally Audit does not make any changes to the
the host it is auditing. This is, in most cases, a wise
strategy. However, there is nothing which prevents a system
administrator to create a shell script, setfile ,
with the following content:
#!/bin/sh
chown $1 $1
chgrp $2 $3
chmod $4 $1
and then making the following audit control statements:
program\ setfile=/usr/audit/bin/setfile\ uid=root\ gid=wheel;
home \e\.rhosts allow exec setfile $file $uid $gid 600;
This would set the desired UID, GID and permissions on all
rhosts files on the system. How well this would be
received by the user community is a question of local polices and
customs.
Another use is to ensure that specific users such as
uucp and ftp do not have a
.forward file, as this in some case can be used by
an intruder:
home \e.forward deny for user=uucp,ftp;
This will ensure the system administrator will be notified if
such files should be created. In a similar fashion Audit
can look for files with names typically used by a cracker:
home \.\.\b deny
home \.\.\. deny
This will monitor for the famous dot-dot-space and
dot-dot-dot files, however, only in the users home
directories.
Finally, some other examples of possible statements for
the users home directories are:
home \.forward allow;
home \.forward uid=$uid gid=$gid perm=400,600 exec;
home \.forward chkforward $file;
home \.cshrc require;
home \.cshrc uid=$uid gid=$gid perm=400,600;
home \.login require;
home \.login uid=$uid gid=$gid perm=400,600;
home \.profile require;
home \.profile uid=$uid gid=$gid perm=400,600;
home \.mailrc allow uid=$uid gid=$gid perm=400,600;
home \.newsrc allow uid=$uid gid=$gid perm=400,600;
home \.elm allow uid=$uid gid=$gid perm=500,700;
10. ImplementationThe most interesting aspects of
Audit is its usage, however a few points should be
made about its implementation.
The interpretation of the audit control file(s) is done
by a recursive descent parser. While this approach is
slower and is not very good at recovery after syntax
errors, compared to many other parsing strategies, it is
very fast to implement from the Bacchus\-Naur Form, and in
addition, its lack of complex data structures is easier
handle in perl.
All specifications from the audit control file(s) are
placed into one internal table. Any path name which
contains a regular expression (implicit path names) will
been expanded prior to being entered into the table.
For each file, there are two entries for each attribute.
The first is used to hold the value and the second is used
for showing whether the value has bee assigned an implicit
path name or one which had no regular expressions (explicit
path name) Any file attribute can be assigned new values as
long as implicit path name is used. When an explicit path
name has been used for a file attribute, any subsequent
assignment with implicit path names will be silently
ignored. If the path name is explicit, Audit will
generate a warning.
Any audit specification which is specified by the
home statement will be expanded to one file entry
for each user in the password file (unless modified by the
except or for clause).
These entries are placed in the same table, as the
entries specified by the file statement.
All such entries will be explicit, unless a regular
expression has been used in specifying the path name
relative to the users' home directories.
After all audit control files have been read and all
entries been placed into the central table, the audit will
start.
During this part of the process, Audit will,
for each file, compare the value of the file attributes in
the table with the ones kept by the actual file.
File attribute entries which has the value
no-audit will not be verified.
File attribute entries which has the value
error will always generate an error message.
An earlier version of Audit used find2perl to
scan all the file systems instead of just checking the file
entries contained in the table. Not only was this a
violation of of the goal of no default polices hard-coded
in the software (NFS mounted file systems was not checked),
it also made Audit take an unnecessary long time
to complete on a large file server. However, because of
this change it is no longer possible to scan the file
systems for certain files, such as device files outside of
the /dev directory.
All error reporting is done through syslog .
All calls to syslog are centralized though one
subroutine call, making it possible to replace only this
routine if another strategy for error reporting should be
required.
11. Future DevelopmentWhile Audit has
been used for some time, there are still a number of
improvements which must be implemented. Some of these are
currently being worked on and will be part of the beta
release. Other improvements would be nice, but are not
scheduled at this time.
- A very recent change was to use the internal file
table for for file lookup.
- Previous to that time, a find like scan of all the
mounted file systems (using perl2find) was used.
- This change gave a significant speed improvement, but
a side effect of this was that it was no longer are
possible to look for, e.g., devices files which are
placed outside the device directory.
It is therefore necessary to provide other means for
auditing this.
A new audit statement, scan , is planned for
this purpose.
It syntax has not yet been finalized; however, it is the
goal to combine the file attribute list from the
file and home statements, with
capabilities such as found in the find(1)
command.
It is also a goal that only one scan of the file systems
shall be done, independent of the number of scan
statements found in the audit control file.
12. ConclusionWhen this project was started
several years ago, it was based in the frustration of
Secure being incomplete. The goal was to build a
security audit program which was highly configurable. This
has been achieved at the cost of having a configuration
which can be complex. However, if the USENET distribution
of audit will contain audit control files for a
number of systems, this problem will have been reduced. In
my experience from using audit and its various
predecessors, it is worthwhile to take the time required to
configure this program.
13. AvailabilityThe final Audit will
eventually be posted to USENET. However, the beta release
will only be made available on a limited basis, preferable
to larger, heterogeneous sites.
AcknowledgmentsThanks Larry Wall for the creation
of Perl. Without Perl, this project would probably never
have been completed.
Thanks to Rob Kolstad for proof reading this paper.
Appendix ABacchus-Naur Form for Audit Control
Language
The complete syntax for the audit control language is
shown below.
audit-control ::= <sentence> [ <audit-control> ]
sentence ::= [ <cond> ] <command> ";"
Condition:
cond ::= "if" "(" <expr> [ && <expr> ] ")"
expr ::= <variable> "=" <reg-exp>
Command:
command ::= <specify> | <audit>
specify ::= <default> | <define> | <program> | <read> | <set>
audit ::= <check> | <file> | <home> | <request> | <scan>
Default:
default ::= "default" <default-list>
default-list ::= <set-default> | <attr-list>
set-default ::= <name> "=" <string>
name ::= "no-audit" | "error"
Define:
define ::= "define" <name> <value>
name ::= <upper-case-string>
value ::= <string> [<string> .. ]
Program:
program ::= "program" <path> [ <attr-list> ] [ <exec> ]
Read:
read ::= "read" <file> [ <attr-list> ]
Set:
set ::= "set" <varname> <value>
value ::= <string> | <exec>
File check:
file ::= "file" <path-name> [ <attr-list> ] [ <exec> ]
Home:
home ::= "home" <path-name> [<execpt>] [<file-attr>] [<exec>]
except ::= "execpt" <expt-list> [ <except-List> ... ]
expt-list := <uid-list> | <gid-list>
Exec:
exec ::= "exec" <program> <parm-list>
Attr-list:
attr-list ::= <fileattr> [<attr-list>]
Fileattr:
fileattr ::= <count> | <sum> | <uid-list> | <gid-list> |
<perm> | <atime> | <mtime> | <ctime> |
<links> | <size> | <inode> | <dev> |
<rdev> | <blksize> | <blocks> | <filetype>
count ::= "count" "=" <integer>
sum ::= "sum" "=" ( <string> | "none" )
uid ::= "uid" "=" <id-list>
gid ::= "gid" "=" <id-list>
perm ::= "perm" "=" <perm-value> ["," <perm-value>]
atime ::= "atime" "=" <file-date>
mtime ::= "mtime" "=" <file-date>
ctime ::= "ctime" "=" <file-date>
links ::= "links" "=" <integer>
dev ::= "dev" = <integer>
size ::= "rdev" = <integer>
size ::= "blksize" = <integer>
size ::= "blocks" = <integer>
size ::= "size" "=" <integer>
inode ::= "inode" "=" <integer>
filetype ::= "type" "=" <type>
UID-List:
uid-list ::= "uid" "=" <id-list>
GID-List:
gid-list ::= "gid" "=" <id-list>
ID-List:
id-list ::= <id> [ "," <id-list> ]
id ::= <string> | <integer>
File-date:
file-date ::= <integer> | <ascii-date>
ascii-date ::= <year> <month> <day> <hour> ":" <minutes> ":" <sec>
File-Type:
type ::= "file" | "dir" | "dev" | "bdev" | "cdev" |
"symlink" | "pipe" | "special"
ReferencesUNIX System Security by Wood,
Patrick H., and Stephen G. Kochan. Hayden Books,
1986
Bruce Spence, Spy: A UNIX File System Security
Monitor , USENIX LISA III Workshop Proceedings,
1989.
|