Filesystem Security: AIDE

Vincent Danen

February 25, 2011

AIDE (Advanced Intrustion Detection Environment) is a GPL replacement for the commercial Tripwire tool and does pretty much the same thing. Both tools monitor the local filesystem for changes by building an initial database to which subsequent checks are compared. Both use a variety of algorithms to ensure that files and directories that are changed are noticed. For a while, the MD5 checksum has been considered not as reliable as it could be (files can be changed and have the MD5's the same). But can you do that and defeat an MD5 check, a CRC32 check, a SHA1 check, a rmd160 check, and more? Likely not. You might be able to beat one, but can you beat the combination?

AIDE can use a combination of different algorithms to determine if a file has been changed. Each time it is run after that initial run, it is compared against the original database and all changes are reported.

Before running out and grabbing AIDE and installing it, be aware of two things. The first is that you should be installing and initializing your database on a pristine system, one that has not been connected to a network. If you connect to a network and possible get rooted before you run AIDE, you run the risk of creating your initial database with bad data. The chances of you finding out later may be much smaller if you rely on AIDE to alert you to changes.

Secondly, you should store a copy of your initial database on a read-only medium immediately after creating it (and, again, before connecting to a network). If someone manages to obtain root access on your system, they can tamper with your database to make it look like nothing has happened, effectively covering their tracks. If you have a sneaking suspicion of something and execute AIDE, it will give you the all ok if you're using a database on the compromised system; likely compromised by the attacker you're trying to detect. If you have the original database on a CD or some other read-only medium, you can mount that medium on your system and run AIDE in check mode, using the original, read-only, initial database. The chances of finding issues are dramatically increased, and you know you can trust the read-only medium to the extent that an attacker did not physically affect it.

AIDE is currently still in pre-release format, so the documentation is a little scarce and it can have some quirks. The current version as of this writing is version 0.9.

Compiling and Installing AIDE

Compiling AIDE is extremely straightforward. You will need the GNU versions of flex, bison, and make, and a C compiler like gcc. You may also want to build and install mhash prior to compiling AIDE to take advantage of a few more algorithms such as the haval checksum, gost checksum, and crc32 checksum. You can download mhash from mhash.sourceforge.net; some systems come with mhash or have packages readily available (via contribs, ports, etc.).

If you don't have a binary package available for AIDE, download it and compile it.

$ tar xvzf aide-0.9.tar.gz
$ cd aide-0.9
$ ./configure
$ make
# make install

You can configure some of AIDE's behaviour by modifying the =configure= call with some options. For instance, you can define a number of syslog options to use (ie. defining the facility, ident, and priority). You can also indicate whether or not AIDE should build with zlib support (which you will want if you wish AIDE to compress it's database file). Use ./configure --help to get the different configuration options you would like. You may wish to use something like:

$ ./configure --with-zlib --with-mhash --enable-mhash --with-config-file=/etc/aide.conf

This will enable zlib and mhash support, and will set the default configuration file to /etc/aide.conf. By default, AIDE installs into /usr/local.

Once you have AIDE compiled and installed, it's time to configure it.

Configuring AIDE

Before running AIDE for the first time, you will need to configure it. You should also configure it to keep an eye on the data that is important to you. System files and devices are a no-brainer, but if you have gigabytes of data in your /home directory, is it really necessary to perform such an intense integrity check on it? Depending on the data there, sure it might be. You may also want to really fine-tune AIDE to skip the bulk of the data there and simply keep an eye on the important things. Determining this before you commit to an initial database and bring the system up live would be a good thing.

Depending on how you configured AIDE, your configuration file might be /etc/aide.conf or something else. We'll assume your configuration file is /etc/aide.conf and that your database directory (where the database will be stored) is /usr/local/aide, and that the aide program itself is installed in /usr/local/bin.

Before proceeding, you may want to make a copy of your aide binary as well and copy it to a read-only medium. Having a pristine binary along with the pristine database just makes sense.

The first step is to modify your configuration file to reflect your system and your needs. Use your favourite editor to modify /etc/aide.conf. The following is an example aide.conf file:

aide.conf

@@define BINDIR /usr/local/bin
@@define CONFDIR /etc
@@define DBDIR /usr/local/aide
@@define LOGDIR /var/log

# the database
database=file:@@{DBDIR}/aide.db.gz
database_out=file:@@{DBDIR}/aide.db.new.gz
gzip_dbout=yes

# reporting options
report_url=stdout
report_url=file:@@{LOGDIR}/aide.log
verbose=20
warn_dead_symlinks=yes

# rule definitions
# the default config file lists the pre-defined rule definitions; these are
on top of those
GLOG=>
DEV=p+n+u+g
CONF=R+sha1
BIN=R+sha1
LOG=p+n+u+g
All=R+a+sha1+rmd160+tiger+crc32

# main configuration
/bin                   BIN
/lib                   BIN
/sbin                  BIN
/usr/bin               BIN
/usr/lib               BIN
/usr/sbin              BIN
/usr/local/bin         BIN
/usr/local/lib         BIN
/usr/local/sbin        BIN
!/usr/src
!/usr/local/src
/boot                  BIN
/boot/System.map$      BIN-m-c
/dev                   DEV
/etc                   CONF
/etc/mtab$             LOG
/var/log               GLOG
@@{CONFDIR}/aide.conf$ All
@@{BINDIR}/aide$       All
@@{DBDIR}/aide.db.gz$  All

This makes for a good start. You will want to fine-tune this according to your own needs, of course, but this covers the basics.

We first define a few macros, which we can then use later in the configuration file. Then we define some database specifics, such as the location of the existing database and the database to create. We also indicate we want the database files compressed with gzip (which is only available if you build AIDE with zlib).

Next we define some reporting options. We want the report printed to standard output and the log file /var/log/aide.log. We want to increase the verbosity to 20, which is a good number (the default is 5). Finally, we want to be warned about symlinks that point to non-existant files.

The next step is to define some rules. AIDE comes with a few pre-defined rules, and a rule is made up of different checks. The available checks for AIDE are:

Default Groups

Group Check
p permissions
i inode
n number of links
u user
g group
s size
b block count
m mtime
a atime
c ctime
S check for growing size
md5 md5 checksum
sha1 sha1 checksum
rmd160 rmd160 checksum
tiger tiger checksum
haval haval checksum (only if mhash enabled)
gost gost checksum (only if mhash enabled)
crc32 crc32 checksum (only if mhash enabled)
R p+i+n+u+g+s+m+c+md5
L p+i+n+u+g
E empty group
> growing logfile (p+u+g+i+n+S)

You can easily use the default groups, however you have the ability to define your own groups if you want to add a few more checks to certain things. You can also do it to make things easier for you to understand, as we have done above. The following new groups have been defined:

GLOG=>
DEV=p+n+u+g
CONF=R+sha1
BIN=R+sha1
LOG=p+n+u+g
All=R+a+sha1+rmd160+tiger+crc32

We've created GLOG as our growing logfile group. The DEV group is suitable for devices, checking permissions, number of links, user, and group entries. The LOG group is similar. The CONF group is defined to handle configuration files, checking everything in the R group and adding the sha1 checksum. The BIN group is similar, which will be used for checking things like binaries and libraries. Finally, we define All which applies every check; great for very sensitive information.

The Checks

Finally, the checks are defined. There are a few rules to remember with this list, which allows for a lot of flexibility.

  • Directories or files prefixed with ! are ignored (ie. in the above, we completely ignore /usr/src and /usr/local/src)
  • Directories prefixed with = are added alone; none of its children are added. However, AIDE will first do a depth-first search
  • Directories and files are always treated as a regular expression; ie. /usr/bin is identical to /usr/bin.*
  • Suffixing a directory or file with $ restricts the check to that directory or file alone

This may sound a little confusing, but it becomes easier to understand. Each check has three parts: The directive (! or =), a regular expression for the directory/file to check, and the rule to apply.

For instance:

@@{CONFDIR}/aide.conf$ All

defines the aide.conf file (the regular expression @@{CONFDIR}/aide.conf$) and the rule to apply (All). There is no directive here.

!/usr/src

The directive ! is used here to tell it not to match the regular expression /usr/src (which is, remember, really /usr/src.*).

There are a few things to remember. If you wish to check something like a directory alone, and one sub-directory with contents, you may be tempted to use something like:

=/foo R
/foo/bar R

However, this is the incorrect way to specify it. Here everything under /foo will be added because your rule is =/foo.* R, so the second rule is redundant. Instead of just /foo and the contents of /foo/bar, you're getting all of /foo. To write this rule properly, you would use:

=/foo$ R
/foo/bar R

When specifying a single file to check, always suffix it with $ (ie. /path/to/file$). This will prevent someone from creating a file /path/to/file_hack and avoiding detection (remember the regular expression .* is at the end of everything and applies to files and directories).

A moderate understanding of regular expressions will really help you develop a configuration that suites your system and needs.

Initializing the Database

Once you have your configuration file configured the way you want (or the way you think you want), it's time to execute AIDE for the first time to initialize the database. Remember, your system should still not be connected to a network to make sure the database you are creating is pristine and not tampered with. To create the database, execute:

# aide --init

Depending on your configuration and the size of your filesystem, this can take a while. When the initialization is complete, move it immediately to a read-only media to ensure it remains pristine. At this point, AIDE does not encrypt the database at all, so the entire database is a plain ASCII file which would allow anyone to read or modify the file (should they obtain access to be able to do so).

The next step is to run a check against the database, just to ensure that your configuration is written the way you want it to. This is also a great opportunity to modify and fine-tune your configuration to cover exactly what you want, and to omitt what you don't want included in the database.

To run the check, execute:

# aide --check

This will check the current state of the filesystem with the database you initially created. If there are any changes, they will show up in the report. Examine the output carefully. This will indicate to you if there have been any changes to the system. Also be aware of changes you have made to the system. If you have installed new software or upgraded packages, you will see the results of those changes in the report. If you have added or removed users, or made any other system changes (ie. changes to configuration files, etc.) those changes will be reflected in the report.

Updating the Database

Once you have your system live, with the initial database stored on CD-ROM or some other removable, read-only media, you may wish to update the database. In fact, you likely will have to as you track security updates and install new software, make changes to your configuration files, etc. You do not need to create a new database with --init each time you wish to do this. Once you've made changes to your system, you may wish to do this immediately. The new database will be written to the file specified by the database_out keyword in your aide.conf file. You will want to place this new database onto read-only media immediately, and replace your old database with it.

To update the database, execute:

# aide --update

If you wish to use a different configuration file (with different rules, perhaps different output files, etc.) you can specify a non-default configuration file with the --config=[file] option to aide. You can also change the verbosity level per-run (overriding that specified in the configuration file) by using --verbose=255 (or whatever verbosity level you wish to set). This is useful if you're debugging your configuration file.

Overall, AIDE is a very useful system to have in place. It offers a very reliable means to check system state, and while it isn't an active alert system to warn you of compromise, like a Network Intrusion Detection System like snort, it will let you know passively if something has happened to warrant investigation. It may be too late to prevent the attack, but if nothing else, you'll know that the attack has occured and will be able to do something about it.

Final Notes

A few things to be aware of. It looks as though AIDE 0.9, unlike 0.8, requires a newer vsnprintf in glibc, so you will need a more recent glibc in order to build it for Linux (I'm not sure exactly what version of glibc is required, although I am running it on Mandrakelinux 9.0 which comes with glibc 2.25).

Some operating systems, like Solaris 2.6 apparently, and Mac OS X 10.2 do not have this newer vsnprintf and configure will fail on the vsnprintf check. You can bypass this check by commenting out line 2524 in the configure file (the line reads exit 1). Unfortunately, there seems to be mixed results with this judging from the mailing list archive; in some cases AIDE will compile and dump core as soon as you run it, in others it fails to compile at all, and in others it looks like it might work. What most people seem to have done is stuck with AIDE 0.8 on these systems.

Another problem I encountered was attempting to build AIDE on OS X, aside from the vsnprintf issues. Compiling mhash from source works just fine, but for some reason the configure script for AIDE refuses to see the library (whether it's installed in /usr/local/lib or in /sw/lib (where the rest of the good stuff from fink resides)). It's indicated that, in these cases, calling configure like:

$ ./configure --with-extra-libs=-L/usr/local/lib \
--with-extra-includes=-I/usr/local/include

should work, but the mhash libraries still are not picked up during the test. I'm unsure if this is a quirk in the configure script or an issue with OS X's environment.

In short, there might be some issues getting AIDE to work for you, depending upon what operating system you are using. You may find that AIDE works flawlessly for you, and you may find yourself unable to even compile it. Dependant upon your results, you may wish to take a look at Tripwire instead. However, please do keep in mind that AIDE is still pre-release software so if you do come across any problems, feel free to bring it up with the developers on the mailing list.

Resources