Description
Some administrative commands are not setuid or setgid, so CB-UBU-AUDIT-026 does not cover them,
yet their use matters in an investigation. This control adds one auditd rule per command in
{{ commands }}, key privileged, in /etc/audit/rules.d/60-cirsec-admin-cmds.rules. Each
rule records every run of the program by a user who logged in. By default:
fdisk: changes to disk partitions;apparmor_parser: loading, replacing or removing AppArmor profiles;useradd: account creation;ssh-agent: an agent that holds private keys for the session;unix_update: the PAM helper that changes local passwords.
Each command is looked up in /usr/sbin, /usr/bin, /sbin and /bin, and its real path is
used. Commands that are not installed are skipped, and so are setuid or setgid ones, which
CB-UBU-AUDIT-026 already audits (ssh-agent is setgid on Ubuntu 20.04 and 22.04).
ssh-agent is started at each graphical login on desktops, which adds one record per session.
Rationale
Repartitioning a disk, unloading an AppArmor profile, creating a back-door account or reusing a forwarded SSH agent are steps of an intrusion that leave no other trace. Recording each run, with the identity of the person who logged in, keeps them attributable.
Impact
Few records: these commands are rarely run. Once the audit configuration is locked (CB-UBU-AUDIT-029), a changed rule only loads at the next reboot.
Setting
| Location | /etc/audit/rules.d/60-cirsec-admin-cmds.rules |
| Default | No audit rules |
| Recommended | Rules loaded (auditctl -l) and present in /etc/audit/rules.d/60-cirsec-admin-cmds.rules |
Parameters
| Parameter | Core | Server | Server hardened | Desktop | Desktop hardened | Bounds |
|---|---|---|---|---|---|---|
commandslist. Names of the administrative commands to audit, looked up in /usr/sbin, /usr/bin, /sbin and /bin. | fdisk, apparmor_parser, useradd, ssh-agent, unix_update | fdisk, apparmor_parser, useradd, ssh-agent, unix_update | fdisk, apparmor_parser, useradd, ssh-agent, unix_update | fdisk, apparmor_parser, useradd, ssh-agent, unix_update | fdisk, apparmor_parser, useradd, ssh-agent, unix_update |
The value used is your override (tailoring file), else the profile's, else the one of the profile it extends, else the default. Bounds limit what an override may set.
Audit
- For each command, find its real path with
readlink -f /usr/sbin/<command>(or/usr/bin/<command>), and skip it ifstat -c %Ashows ans(CB-UBU-AUDIT-026 covers it). - Run
auditctl -las root. It must list, for each remaining command:-a always,exit -S all -F path=<real path> -F perm=x -F auid>=1000 -F auid!=-1 -F key=privileged - Run
grep -h . /etc/audit/rules.d/*.rules. The same rules must be present, so they load at boot.
Automated: every check must pass. Scanners report each check by its id.
rules
Rules loaded in the kernel and present in /etc/audit/rules.d.
script: |
command -v auditctl >/dev/null 2>&1 || { echo "auditctl not found: auditd is not installed"; exit 1; }
want() {
for c in $CB_COMMANDS; do
for d in /usr/sbin /usr/bin /sbin /bin; do
[ -f "$d/$c" ] && { readlink -f "$d/$c"; break; }
done
done | sort -u | while IFS= read -r p; do
# setuid and setgid programs are audited by CB-UBU-AUDIT-026
[ -u "$p" ] || [ -g "$p" ] || echo "-a always,exit -S all -F path=$p -F perm=x -F auid>=1000 -F auid!=-1 -F key=privileged"
done
}
loaded=$(auditctl -l 2>&1) || { echo "$loaded"; exit 3; }
disk=$(cat /etc/audit/rules.d/*.rules 2>/dev/null)
n=0 rc=0
while IFS= read -r r; do
[ -n "$r" ] || continue
n=$((n + 1))
printf '%s\n' "$loaded" | grep -Fxq -- "$r" || { echo "not loaded: $r"; rc=1; }
printf '%s\n' "$disk" | grep -Fxq -- "$r" || { echo "not in /etc/audit/rules.d: $r"; rc=1; }
done <<EOF
$(want)
EOF
[ "$rc" = 1 ] || echo "$n rules loaded and present in /etc/audit/rules.d"
exit "$rc"
Remediation
- Write the expected rules to
/etc/audit/rules.d/60-cirsec-admin-cmds.rules(mode 0640). - Run
augenrules --load. Ifauditctl -sshowsenabled 2, the configuration is locked: reboot to load the new rules.
| Restart | none |
| Disruption | none |
Rollback
Delete /etc/audit/rules.d/60-cirsec-admin-cmds.rules and run augenrules --load (or reboot if the configuration is locked).
rules-file
command -v augenrules >/dev/null 2>&1 || { echo "auditd is not installed" >&2; exit 1; }
want() {
for c in $CB_COMMANDS; do
for d in /usr/sbin /usr/bin /sbin /bin; do
[ -f "$d/$c" ] && { readlink -f "$d/$c"; break; }
done
done | sort -u | while IFS= read -r p; do
# setuid and setgid programs are audited by CB-UBU-AUDIT-026
[ -u "$p" ] || [ -g "$p" ] || echo "-a always,exit -S all -F path=$p -F perm=x -F auid>=1000 -F auid!=-1 -F key=privileged"
done
}
f=/etc/audit/rules.d/60-cirsec-admin-cmds.rules
t=$(mktemp)
{ echo '# Written by CIRSEC Baselines CB-UBU-AUDIT-036'; want; } >"$t"
if ! cmp -s "$t" "$f"; then
cb_backup "$f"
cat "$t" >"$f"
fi
rm -f "$t"
chmod 640 "$f"
if auditctl -s | grep -q '^enabled 2'; then
echo "audit rules are locked (-e 2): reboot to load $f"
else
augenrules --load >/dev/null
fi
Handwritten code reads parameters from CB_<NAME> environment variables. Each release turns these fixes into remediate.sh and an Ansible role per profile: dry run by default, a fix runs only when its check fails.
References
- audit.rules(7), Ubuntu manual pages Canonical, vendor-doc, accessed 2026-10-19
- auditctl(8), Ubuntu manual pages Canonical, vendor-doc, accessed 2026-10-19
- ANSSI-BP-028 v2.0 - Recommandations de configuration d'un système GNU/Linux (R73) ANSSI, guide, accessed 2026-10-19
Mappings
| Framework | ID | Relation |
|---|---|---|
| ANSSI-BP-028 - Recommandations de configuration d'un système GNU/Linux2.0 | R73 | partial |
| NIST SP 800-53 Rev. 55.1.1 | AU-12 | related |
| NIST SP 800-53 Rev. 55.1.1 | AC-6(9) | related |
How this control relates to the other framework's: equivalent, stricter, looser, partial or related.
Threats mitigated
Related controls
- requires
CB-UBU-AUDIT-011Install and run the audit daemon - related
CB-UBU-AUDIT-026Audit every use of setuid and setgid programs - related
CB-UBU-AUDIT-029Lock the audit configuration and load every valid rule
People and lifecycle
| Authors |
|
| Verified | 2026-10-19 by Sn0wAlice on 20.04, Proxmox VM, Ubuntu 20.04 cloud image, kernel 5.4.0-216-generic. Fails after auditd install; 4 rules written (ssh-agent setgid, left to AUDIT-026), loaded and locked; passes after reboot. |
| Verified | 2026-10-19 by Sn0wAlice on 22.04, Proxmox VM, Ubuntu 22.04 cloud image, kernel 5.15.0-198-generic. Fails after auditd install; 4 rules written (ssh-agent setgid, left to AUDIT-026), loaded and locked; passes after reboot. |
| Verified | 2026-10-19 by Sn0wAlice on 24.04, Proxmox VM, Ubuntu 24.04 cloud image, kernel 6.8.0-147-generic. Fails after auditd install; 4 rules written (ssh-agent setgid, left to AUDIT-026), loaded and locked; passes after reboot. |
| Verified | 2026-10-19 by Sn0wAlice on 26.04, Proxmox VM, Ubuntu 26.04 cloud image, kernel 7.0.0-38-generic. Fails after auditd install; 4 rules written (ssh-agent setgid, left to AUDIT-026), loaded and locked; passes after reboot. |
| Introduced in | v0.1.0 |
| Created, updated | 2026-10-19, 2026-10-19 |
| Translations | fr |