Debian GNU/Linux · Logging & auditing

Audit changes to sudo rights and commands run as another user

When it fails: Changes to administrator rights and use of other identities are not recorded. Without these records, nobody can tell who granted sudo rights or who acted under another account.

CB-DEB-AUDIT-016mediumactiveautomatedautomated fixprofile server-hardenedprofile desktop-hardened

As released in v0.1.0 beta · pre-release. Current state.

Description

Three groups of auditd rules, written to /etc/audit/rules.d/60-cirsec-scope.rules:

  • writes and attribute changes on /etc/sudoers and /etc/sudoers.d/ (key scope);
  • every program started with an effective user different from the real user, by a user who logged in (execve with uid!=euid, 64 and 32-bit calls, key user_emulation), which covers sudo, su and other setuid programs;
  • writes to the sudo log file {{ sudo_log_file }} (key sudo_log_file).

For each system call the kernel keeps the key of the first matching rule. Running sudo or su is usually recorded with the key privileged (CB-DEB-AUDIT-026), whose rules load first; user_emulation catches the other cases.

Rationale

Granting oneself sudo rights is a classic persistence and privilege escalation step. Recording each change to the sudo policy, each command run under another identity and each attempt to edit the sudo log keeps administrative actions attributable to the person who logged in.

Impact

Busy systems where users run many setuid programs produce more audit records.

Setting

Location/etc/audit/rules.d/60-cirsec-scope.rules
DefaultNo audit rules
RecommendedRules loaded (auditctl -l) and present in /etc/audit/rules.d/60-cirsec-scope.rules

Parameters

ParameterCoreServerServer hardenedDesktopDesktop hardenedBounds
sudo_log_filestring. Path of the sudo log file to watch (the logfile option of sudoers, see CB-DEB-AUTH-005)./var/log/sudo.log/var/log/sudo.log/var/log/sudo.log/var/log/sudo.log/var/log/sudo.log

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

  1. Run auditctl -l as root. It must list the rules shown below (keys scope, sudo_log_file, user_emulation).
  2. Run grep -h . /etc/audit/rules.d/*.rules. The same rules must be present, so they load at boot.

Expected rules, as auditctl -l prints them:

-w /etc/sudoers -p wa -k scope
-w /etc/sudoers.d -p wa -k scope
-a always,exit -F arch=b64 -S execve -C uid!=euid -F auid!=-1 -F key=user_emulation
-a always,exit -F arch=b32 -S execve -C uid!=euid -F auid!=-1 -F key=user_emulation

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() {
  cat <<'RULES'
  -w /etc/sudoers -p wa -k scope
  -w /etc/sudoers.d -p wa -k scope
  -a always,exit -F arch=b64 -S execve -C uid!=euid -F auid!=-1 -F key=user_emulation
  -a always,exit -F arch=b32 -S execve -C uid!=euid -F auid!=-1 -F key=user_emulation
  RULES
  printf -- '-w %s -p wa -k sudo_log_file\n' "$CB_SUDO_LOG_FILE"
  }
  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

  1. Write the expected rules to /etc/audit/rules.d/60-cirsec-scope.rules (mode 0640).
  2. Run augenrules --load. If auditctl -s shows enabled 2, the configuration is locked: reboot to load the new rules.
Restartnone
Disruptionnone

Rollback

Delete /etc/audit/rules.d/60-cirsec-scope.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() {
cat <<'RULES'
-w /etc/sudoers -p wa -k scope
-w /etc/sudoers.d -p wa -k scope
-a always,exit -F arch=b64 -S execve -C uid!=euid -F auid!=-1 -F key=user_emulation
-a always,exit -F arch=b32 -S execve -C uid!=euid -F auid!=-1 -F key=user_emulation
RULES
printf -- '-w %s -p wa -k sudo_log_file\n' "$CB_SUDO_LOG_FILE"
}
f=/etc/audit/rules.d/60-cirsec-scope.rules
t=$(mktemp)
{ echo '# Written by CIRSEC Baselines CB-DEB-AUDIT-016'; 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

Mappings

FrameworkIDRelationNote
ANSSI-BP-028 - Recommandations de configuration d'un système GNU/Linux2.0R33partialR33 asks for accountability of administration actions; this control records them.
ANSSI-BP-028 - Recommandations de configuration d'un système GNU/Linux2.0R73partial
NIST SP 800-53 Rev. 55.1.1AU-12related
NIST SP 800-53 Rev. 55.1.1AC-6(9)related

How this control relates to the other framework's: equivalent, stricter, looser, partial or related.

Threats mitigated

  • requires CB-DEB-AUDIT-011 Install and run the audit daemon
  • related CB-DEB-AUDIT-029 Lock the audit configuration and load every valid rule
  • related CB-DEB-AUTH-005 Configure sudo to use a pseudo-terminal, a log file and a short credential cache

People and lifecycle

Authors
Verified2026-10-18 by Sn0wAlice on 12, Proxmox VM, Debian 12 genericcloud image, kernel 6.1.0-54-cloud-amd64, auditd 1:3.0.9-1, BIOS boot. Rules fail on fresh install; fix writes /etc/audit/rules.d/60-cirsec-scope.rules and loads it; rules match auditctl -l, kept after reboot; second run idempotent.
Verified2026-10-18 by Sn0wAlice on 13, Proxmox VM, Debian 13 genericcloud image, kernel 6.12.113+deb13-cloud-amd64, auditd 1:4.0.2-2+deb13u1, BIOS boot. Rules fail on fresh install; fix writes /etc/audit/rules.d/60-cirsec-scope.rules and loads it; rules match auditctl -l, kept after reboot; second run idempotent.
Introduced inv0.1.0
Created, updated2026-10-18, 2026-10-18
Translationsfr