Customized File Monitoring with Auditd


In the previous article on auditd, I showed how to use aureport to check stuff monitored by the auditd daemon. And, I showed how you could, for example, check whether a user had experienced trouble logging in, which could be interpreted as a malicious attempt to access a system.

As I said before, aureport is part of a larger toolset that comes with auditd. Using auditd to monitor some preset events is already quite useful, but where it comes into its own is when you customize it to monitor whatever you want.

Customized Monitoring Rules

To push your rules into auditd on the fly you use auditctl. But, before you insert any of your own rules, let’s check to see if any defaults are already in place. Become root (or use sudo) and try this:

auditctl -l
-a never,task

The -l option lists all current active rules and, if you see the -a never,task line shown above, none of the rules following it will log anything. This rule, which is often a default in new auditd installations, is telling the daemon to append (-a) a rule to the task list (as in the list of tasks the kernel is running — don’t worry about this just yet), which will stop auditd from ever recording anything.

Because we’re not specifying which task, auditd assumes the rule applies to all of them. In plain English, this would read: “Never record anything from any of the tasks the kernel is running.” And, because auditd gives precedence from top to bottom (i.e., the first rule takes precedence over the ones following it in case of a conflict), this means nothing will be recorded despite what any of the other rules say.

You don’t want that, so the first thing to do is get rid of this rule. To delete all rules from a running auditd daemon, you can use:

auditctl -D

If you already have more than one rule and don’t want to zap them all, you can also selectively delete only this rule with

auditctl -d never,task

Now the coast is clear, so I’ll show how to build your own first rule. The typical use for auditd is to have it monitor files or directories. For example: As a regular user, create a directory in your /home directory, say…

mkdir test_dir

Now become root and set up a watch on the directory you just made:

auditctl -w /home/[your_user_name]/test_dir/ -k test_watch

The -w option tells auditd to watch the test_dir/ directory for any changes. The -k option tells auditd to append the string test_watch (called a key) to the log entries it creates. The key can be anything you want, although it is a good idea to make it something memorable and related to what the rule does. As you will see, this will be useful to filter out unrelated records when you revise auditd‘s logs later on.

Now, as a regular user, do some stuff in test_dir/ — make some subdirectories, create or copy some files, remove some files, or list the contents.

When you’re done, take a look at what auditd logged with

ausearch -k test_watch

See the use of -k test_watch here? Even if you have a dozen more rules logging different things, by using a key string, you can tell ausearch to only list what you’re interested in (Figure 1).

Figure 1: Output of ausearch command.

Even with this filter, the amount of information ausearch throws at you is a bit overwhelming. However, you will also notice that the information is very structured. The output is actually made up of three records per event.

Each record contains some keyword/value pairs separated by a “=” sign; some of the values are strings, others are lists enclosed in parenthesis, and so on. You can read up on what each snippet of information means in the official manual, but the important thing to take away is that the structured nature of ausearch‘s output makes processing it using scripts relatively easy. In fact, aureport, the tool I showed in the previous article, does a very good job of sorting things out.

To prove it, let’s pipe our ausearch output through aureport and see what’s what:

ausearch -k test_watch | aureport -f -i

File Report 
# date time file syscall success exe auid event 
1. 05/06/16 13:04:54 sub_dir mkdir yes /usr/bin/mkdir paul 193 
2. 05/06/16 13:04:54 /home/paul/test_dir/sub_dir getxattr no /usr/bin/baloo_file paul 194 
3. 05/06/16 13:04:54 /home/paul/test_dir/sub_dir getxattr no /usr/bin/baloo_file paul 195 
4. 05/06/16 13:04:54 /home/paul/test_dir/sub_dir getxattr no /usr/bin/baloo_file paul 196 
5. 05/06/16 13:05:06 /home/paul/test_dir/testfile.txt getxattr no /usr/bin/baloo_file paul 198 

This is starting to make sense! You can check who is doing what to which file and when.

One thing you can see in the listing above is that, because I am using the Plasma desktop, Baloo, KDE’s indexing service, is cluttering the list with irrelevant results. That’s because every time you create or destroy a file, Baloo has to come along and index the fact. This makes parsing what is going on and checking whether the user is up to no good, annoyingly hard. So, let’s filter Baloo’s actions out with a strategically placed grep:

ausearch -k test_watch | aureport -f -i | grep -v baloo

File Report 
# date time file syscall success exe auid event 
1. 05/06/16 13:04:54 sub_dir mkdir yes /usr/bin/mkdir paul 193 
9. 05/06/16 13:05:06 testfile.txt open yes /usr/bin/touch paul 197 
17. 05/06/16 13:05:29 ./be03316b71184fefba5cfbf59c21e6d5.jpg open yes /usr/bin/cp paul 210 
18. 05/06/16 13:05:29 ./big_city.jpg open yes /usr/bin/cp paul 211 
19. 05/06/16 13:05:29 ./blendertracking.jpg open yes /usr/bin/cp paul 212 
20. 05/06/16 13:05:29 ./Cover27_Draft01.jpg open yes /usr/bin/cp paul 213
37. 05/06/16 13:05:50 blendertracking.jpg unlinkat yes /usr/bin/rm paul 330 
38. 05/06/16 13:05:50 be03316b71184fefba5cfbf59c21e6d5.jpg unlinkat yes /usr/bin/rm paul 328

That’s much better. You can now clearly see what the users have been up to. You can follow how they create some directories and files and copy others from elsewhere. You can also check what files are being removed, and so on.

When you have no more use for it, you can remove the above watch with

auditctl -W /home/[your_user]/test_dir/ -k test_watch

One File at a Time

Monitoring whole directories makes for a lot of logged data. Sometimes it is better to just monitor strategic individual files to make sure no one is tampering with them. A classic example is to use

auditctl -w /etc/passwd -p wa -k passwd_watch

to make sure nobody is messing with your passwd file.

The -p parameter tells auditd which permissions to monitor. The available permissions are:

  • r to monitor for read accesses to a file or a directory,

  • w to monitor for write accesses,

  • x to monitor for execute accesses,

  • and a to check for changes of the file’s or directory’s attributes.

Because there are legitimate reasons for an application to read from /etc/passwd, you’re not going to monitor for that to avoid false positives. It is also a bit silly to monitor for the execution of a non-executable file; hence, we tell auditd to only monitor for changes to passwd‘s content (i.e., writes) and its attributes.

If you don’t specify what permissions to monitor, auditd will assume it has to monitor all of them. That’s why, when you were monitoring the test_dir/ directory in the first examples, even a simple ls command triggered auditd.

Permanent Rules

To make your rules permanent, you can include them into /etc/audit/audit.rules or create a new rules file in the /etc/audit/rules.d/ directory. If you have been experimenting with rules using auditctl and you are happy with your current set up, you could do:

echo "-D" > /etc/audit/rules.d/my.rules
auditctl -l >> /etc/audit/rules.d/my.rules

to dump your current rules into a rules file called my.rules and save yourself some typing. If you’ve been following this tutorial and used the example rules you saw above, my.rules would end up looking like this:

-w /home/[your_user]/test_dir/ -k test_watch
-w /etc/passwd -p wa -k passwd_watch

To avoid interference and conflicts, move any pre-existing rules files in /etc/audit/ and /etc/audit/rules.d to backups:

mv /etc/audit/audit.rules /etc/audit/audit.rules.bak
mv /etc/audit/rules.d/audit.rules /etc/audit/rules.d/audit.rules.bak

Then, restart the daemon with

systemctl restart auditd.service

to have auditd pick up your rules straight away.

Now, every time your system is rebooted, auditd will start monitoring whatever you told it to.

There’s More

I had time to cover only a small portion of auditd’s capabilities here. But, as you can see, auditd is very powerful, and it can be used monitor much more than just files and directories, with an insane level of detail. I plan to visit the more advanced topics in a future article.