Audit - hpaluch/hpaluch.github.io GitHub Wiki

Audit basics

Here are few very basic examples on Linux Audit. I used these pages as start:

Tested OS: Debian 12 and Fedora 42

[!WARNING] This stuff is experimental - wrong audit rules may overload your machine and/or fill-up disk! Use these examples on disposable VM!

Note: all commands below have to be run as root.

Playing with existing rules

NOTE: Under Fedora ensure that following package is installed:

# creates /etc/audit/rules.d/audit.rules:
dnf install audit-rules

One easy way to get overview is to use aureport command:

  • to see Login report (-l), interpret (decode) values (-i) from last boot (-ts boot):
    $ aureport -l -i -ts boot
    
    Login Report
    ============================================
    # date time auid host term exe success event
    ============================================
    1. 04/22/2025 16:50:45 lxi 192.168.122.1 /dev/pts/0 /usr/sbin/sshd yes 368
    2. 04/22/2025 17:01:45 (invalid user) 192.168.122.1 sshd /usr/sbin/sshd no 441
    
  • to see only failed logins - add --failed
    $ aureport -l -i -ts boot --failed
    
    Login Report
    ============================================
    # date time auid host term exe success event
    ============================================
    1. 04/22/2025 17:01:45 (invalid user) 192.168.122.1 sshd /usr/sbin/sshd no 441
    
  • to see authentication reports (but seeing only failed):
    $ aureport -au -i -ts boot
    
    Authentication Report
    ============================================
    # date time acct host term exe success event
    ============================================
    1. 04/22/2025 17:01:46 hacker 192.168.122.1 ssh /usr/sbin/sshd no 444
    

Define own audit rules

  • please invoke man audir.rules for details.
  • WARNING! Under Fedora all audit of all syscalls is disabled by default. To enable below syscall rules (those with -S syscall_name) you need to comment out this line in /etc/audit/rules.d/audit.rules
    # must comment out:
    -a task,never
    
  • rules tip: on Fedora you can find example rules under /usr/share/audit-rules/

To setup own rules:

  • create file /etc/audit/rules.d/zz_custom.rules with content:
    # audit all connect(2) calls with exception of Unix socket family
    -a always,exit -F arch=b64 -S connect  -F saddr_fam!=1 -k hp_sock1
    -a always,exit -F arch=b32 -S connect  -F saddr_fam!=1 -k hp_sock1
    # watch (w)rite and (a)ttribute changes
    # partially based on: https://documentation.suse.com/en-us/sles/15-SP6/html/SLES-all/cha-audit-comp.html
    # watch /etc/ directory write access or attr modification:
    # old format: -w /etc -p wa -k hp_etc3
    -a always,exit -F arch=b64 -F path=/etc -F perm=wa -F key=hp_etc3
    -a always,exit -F arch=b32 -F path=/etc -F perm=wa -F key=hp_etc3
    # old format: -w /etc/passwd -k hp_passwd3 -p wxa
    -a always,exit -F arch=b64 -F path=/etc/passwd -F perm=wxa -F key=hp_passwd3
    -a always,exit -F arch=b32 -F path=/etc/passwd -F perm=wxa -F key=hp_passwd3
    # old format: -w /etc/group -k hp_group3 -p wxa
    -a always,exit -F arch=b64 -F path=/etc/group -F perm=wxa -F key=hp_group3
    -a always,exit -F arch=b32 -F path=/etc/group -F perm=wxa -F key=hp_group3
    # old format: -w /etc/shadow -k hp_shadow3 -p wxa
    -a always,exit -F arch=b64 -F path=/etc/shadow -F perm=wxa -F key=hp_shadow3
    -a always,exit -F arch=b32 -F path=/etc/shadow -F perm=wxa -F key=hp_shadow3
    
  • regenerate and reload main configuration file /etc/audit/audit.rules from rules.d/*:
    $ augenrules --load
    $ auditctl -l  # dump current rules
    

To see connect kernel syscalls you can try filter like this:

  • where are these new params -m message type syscall, -sc syscall name is connect
    $ ausearch -ts boot -m syscall -sc connect -i
    
    # example of IPv6 socket (saddr_fam=inet6)
    ----
    type=PROCTITLE msg=audit(04/22/2025 16:50:42.360:111) : proctitle=(sshd)
    type=SOCKADDR msg=audit(04/22/2025 16:50:42.360:111) : saddr={ saddr_fam=inet6 laddr=:: lport=22 }
    
    type=SYSCALL msg=audit(04/22/2025 16:50:42.360:111) : arch=x86_64 syscall=connect \
      success=yes exit=0 a0=0x3 a1=0x556c17b17260 a2=0x1c a3=0x7ffd0dc45710 items=0 \
      ppid=1 pid=540 auid=unset uid=root gid=root euid=root suid=root fsuid=root  \
      egid=root sgid=root fsgid=root tty=(none) ses=unset \
       comm=sshd exe=/usr/sbin/sshd subj=unconfined key=(null)
    
    # example of Unix (local file) socket:
    type=PROCTITLE msg=audit(04/22/2025 16:50:42.364:116) : proctitle=(sshd)
    type=PATH msg=audit(04/22/2025 16:50:42.364:116) : item=0 name=/var/run/nscd/socket \
      nametype=UNKNOWN cap_fp=none cap_fi=none cap_fe=0 cap_fver=0 cap_frootid=0
    type=CWD msg=audit(04/22/2025 16:50:42.364:116) : cwd=/
    type=SOCKADDR msg=audit(04/22/2025 16:50:42.364:116) : saddr={ saddr_fam=local path=/var/run/nscd/socket }
    type=SYSCALL msg=audit(04/22/2025 16:50:42.364:116) : arch=x86_64 \
      syscall=connect success=no exit=ENOENT(No such file or directory) a0=0x3 \
      a1=0x7ffd0dc45e40 a2=0x6e a3=0xffffffff items=1 ppid=1 pid=540 auid=unset \
      uid=root gid=root euid=root suid=root fsuid=root egid=root sgid=root \
      fsgid=root tty=(none) ses=unset comm=sshd exe=/usr/sbin/sshd subj=unconfined key=(null)
    
  • or you can filter by key adding -k hp_sock (key can be also substring as in this case)

We can also nicely filter rules with our keys (defined with -k key_name keywords in /etc/audit/rules.d/zz_custom.rules:

# show keys containing  "hp_"
ausearch -ts boot -i -k hp_
----
type=PROCTITLE msg=audit(04/22/2025 16:50:45.384:317) : \
  proctitle=rm -f /etc/resolv.conf.dhclient-new.827
  type=PATH msg=audit(04/22/2025 16:50:45.384:317) : item=1 \
  name=/etc/resolv.conf.dhclient-new.827 inode=262172 dev=fe:01 \
  mode=file,644 ouid=root ogid=root rdev=00:00 nametype=DELETE \
  cap_fp=none cap_fi=none cap_fe=0 cap_fver=0 cap_frootid=0
type=PATH msg=audit(04/22/2025 16:50:45.384:317) : item=0 \
  name=/etc/ inode=261121 dev=fe:01 mode=dir,755 ouid=root \
  ogid=root rdev=00:00 nametype=PARENT cap_fp=none cap_fi=none cap_fe=0 cap_fver=0 cap_frootid=0
type=CWD msg=audit(04/22/2025 16:50:45.384:317) : cwd=/
type=SYSCALL msg=audit(04/22/2025 16:50:45.384:317) : arch=x86_64 \
  syscall=unlinkat success=yes exit=0 a0=AT_FDCWD a1=0x5585c78bf380 \
  a2=0x0 a3=0x7f4e52c37f80 items=2 ppid=827 pid=838 auid=unset uid=root \
  gid=root euid=root suid=root fsuid=root egid=root sgid=root fsgid=root \
  tty=(none) ses=unset comm=rm exe=/usr/bin/rm subj=unconfined key=hp_etc3

Hmm, really nice - I forgot that DHCP client has to update /etc/resolv.conf...

Note: mysterious a0=... a1=... are simply arguments to kernel syscalls.

There is even nice output by key from aureport:

$ aureport -ts boot -i -k

Key Report
===============================================
# date time key success exe auid event
===============================================
1. 04/22/2025 16:50:42 hp_etc3 yes /usr/sbin/auditctl unset 22
2. 04/22/2025 16:50:42 hp_passwd3 yes /usr/sbin/auditctl unset 23
3. 04/22/2025 16:50:42 hp_group3 yes /usr/sbin/auditctl unset 24
4. 04/22/2025 16:50:42 hp_shadow3 yes /usr/sbin/auditctl unset 25
5. 04/22/2025 16:50:42 hp_etc3 no /usr/lib/systemd/systemd-user-sessions unset 106
6. 04/22/2025 16:50:45 hp_etc3 yes /usr/bin/dash unset 305
7. 04/22/2025 16:50:45 hp_etc3 yes /usr/bin/rm unset 306
8. 04/22/2025 16:50:45 hp_etc3 yes /usr/bin/dash unset 307
9. 04/22/2025 16:50:45 hp_etc3 yes /usr/bin/dash unset 308
10. 04/22/2025 16:50:45 hp_etc3 yes /usr/bin/dash unset 309
11. 04/22/2025 16:50:45 hp_etc3 yes /usr/bin/chown unset 314
...

Limitations: I don't know how to print also path that was accessed.

To quickly see, how many syscall were audited try:

$ aureport -s -ts boot -i --summary

Syscall Summary Report
==========================
total  syscall
==========================
45  sendto
40  openat
39  unlink
16  bpf
16  close
13  connect
10  setxattr
8  chmod
6  sendmsg
5  fchown
5  rename
5  fchmod
4  write
3  fchmodat

Interesting - report of calls by command filtered to just curl using regular grep with word (-w) filter:

$ aureport -ts boot --comm -i | grep -w curl

91. 04/25/2025 19:39:03 curl pts1 91.213.160.188 aa 188
92. 04/25/2025 19:39:03 curl pts1 2001:67c:68::76 aa 189
...

Auditing privileged operations

I was thinking how to audit privileged operations for non-privileged invoker:

  • running su to become root
  • running sudo to become root
  • running suid program that will execute as root

I found exactly these rules in /usr/share/audit/sample-rules/30-pci-dss-v31.rules:

# from /usr/share/audit-rules/30-ospp-v42-1-create-failed.rules
### 10.2.5.b All elevation of privileges is logged
-a always,exit -F arch=b64 -S setuid -F a0=0 -F exe=/usr/bin/su -F key=10.2.5.b-elevated-privs-session
-a always,exit -F arch=b32 -S setuid -F a0=0 -F exe=/usr/bin/su -F key=10.2.5.b-elevated-privs-session
-a always,exit -F arch=b64 -S setresuid -F a0=0 -F exe=/usr/bin/sudo -F key=10.2.5.b-elevated-privs-session
-a always,exit -F arch=b32 -S setresuid -F a0=0 -F exe=/usr/bin/sudo -F key=10.2.5.b-elevated-privs-session
-a always,exit -F arch=b64 -S execve -C uid!=euid -F euid=0 -F key=10.2.5.b-elevated-privs-setuid
-a always,exit -F arch=b32 -S execve -C uid!=euid -F euid=0 -F key=10.2.5.b-elevated-privs-setuid

They do what I want - just load them.

Using json

Failed with mmaudit module - although it is included with rsyslog it is broken you can find exact error using:

  • terse error: rsyslog -N 1 -f /etc/rsyslog.conf).
  • detailed error: rsyslog -d -N 1 -f /etc/rsyslog.conf).
modules.c: Requested to load module 'mmaudit'
modules.c: loading module '/usr/lib64/rsyslog/mmaudit.so'
modules.c: module mmaudit of type 1 being loaded (keepType=0).
mmaudit.c: entry point 'setModCnf' not present in module
mmaudit.c: entry point 'getModCnfName' not present in module
mmaudit.c: entry point 'beginCnfLoad' not present in module
mmaudit.c: entry point 'doHUP' not present in module
mmaudit.c: entry point 'doHUPWrkr' not present in module
mmaudit.c: entry point 'SetShutdownImmdtPtr' not present in module
mmaudit.c: entry point 'beginTransaction' not present in module
mmaudit.c: entry point 'commitTransaction' not present in module
mmaudit.c: entry point 'endTransaction' not present in module
mmaudit.c: entry point 'newActInst' not present in module

Alternative is using mmfield - testing:

# /etc/rsyslog.d/mm_audit.conf - redirect audit to /var/log/test.json
# Bugs: some fields are still text-based (inside message etc).
# tested on Fedora 42, requires:  dnf install rsyslog-mmfields
# based on https://www.rsyslog.com/doc/configuration/modules/mmfields.html
module(load="mmfields")
template(name="ftpl"
         type="string"
         string="%$!%\n")
if ( $programname == 'audit' ) then {
	action(type="mmfields")
	action(type="omfile"
	       file="/var/log/test.json"
	       template="ftpl")

}

There is also long discussion on https://stackoverflow.com/questions/74982676/how-to-convert-auditd-logs-to-json-format-efficiently-using-rsyslog-modules (not yet tested)