# yaml-language-server: $schema=../../../../schema/control.schema.json id: CB-UBU-AUDIT-020 title: Audit changes to file permissions, owners and extended attributes finding: title: Changes to file permissions and ownership are not recorded description: A user can open up access to sensitive files or hide a setuid program without a record. status: active profiles: [server-hardened, desktop-hardened] risk: severity: low assessment: automated tags: [auditd, permissions] description: | auditd rules in `/etc/audit/rules.d/60-cirsec-perm.rules`, for actions of users who logged in: - mode changes (`chmod`, `fchmod`, `fchmodat`, and `fchmodat2` where the kernel and auditd know it); - owner changes (`chown`, `fchown`, `lchown`, `fchownat`); - extended attribute changes (`setxattr`, `removexattr` and their variants), which also hold ACLs; - runs of `chcon`, `setfacl` and `chacl` (key `perm_chng`). Every system call rule exists for 64-bit and 32-bit programs (key `perm_mod`). rationale: | Permission changes are how a user makes a private file readable, a script writable by others or a binary setuid. Recording them makes such changes visible and attributable. impact: | Users who change many permissions (builds, package managers run by users, rsync) produce many records. Actions of system services (no login session) are not recorded. notes: | `chcon` belongs to coreutils; `setfacl` and `chacl` come with the `acl` package, often absent. A rule on a program that is not installed is accepted and applies once it is installed. On Ubuntu 26.04, `/usr/bin/chcon` is a symbolic link to the uutils multi-call binary, shared by all coreutils commands. The `chcon` rule loads but does not match its runs, and a rule on the real binary would record every `ls` or `cat`. What `chcon` changes (the `security.*` extended attributes) is still recorded by the `setxattr` rules of this control. setting: location: /etc/audit/rules.d/60-cirsec-perm.rules default_value: No audit rules recommended_value: "Rules loaded (auditctl -l) and present in /etc/audit/rules.d/60-cirsec-perm.rules" audit: manual: | 1. Run `auditctl -l` as root. It must list the rules shown below (keys `perm_chng`, `perm_mod`). 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: ``` -a always,exit -F arch=b64 -S chmod,fchmod,fchmodat -F auid>=1000 -F auid!=-1 -F key=perm_mod -a always,exit -F arch=b32 -S chmod,fchmod,fchmodat -F auid>=1000 -F auid!=-1 -F key=perm_mod -a always,exit -F arch=b64 -S chown,fchown,lchown,fchownat -F auid>=1000 -F auid!=-1 -F key=perm_mod -a always,exit -F arch=b32 -S lchown,fchown,chown,fchownat -F auid>=1000 -F auid!=-1 -F key=perm_mod -a always,exit -F arch=b64 -S setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F auid>=1000 -F auid!=-1 -F key=perm_mod -a always,exit -F arch=b32 -S setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F auid>=1000 -F auid!=-1 -F key=perm_mod -a always,exit -S all -F path=/usr/bin/chcon -F perm=x -F auid>=1000 -F auid!=-1 -F key=perm_chng -a always,exit -S all -F path=/usr/bin/setfacl -F perm=x -F auid>=1000 -F auid!=-1 -F key=perm_chng -a always,exit -S all -F path=/usr/bin/chacl -F perm=x -F auid>=1000 -F auid!=-1 -F key=perm_chng ``` checks: - id: rules engine: shell description: Rules loaded in the kernel and present in /etc/audit/rules.d. spec: script: | command -v auditctl >/dev/null 2>&1 || { echo "auditctl not found: auditd is not installed"; exit 1; } want() { cat <<'RULES' -a always,exit -F arch=b64 -S chmod,fchmod,fchmodat -F auid>=1000 -F auid!=-1 -F key=perm_mod -a always,exit -F arch=b32 -S chmod,fchmod,fchmodat -F auid>=1000 -F auid!=-1 -F key=perm_mod -a always,exit -F arch=b64 -S chown,fchown,lchown,fchownat -F auid>=1000 -F auid!=-1 -F key=perm_mod -a always,exit -F arch=b32 -S lchown,fchown,chown,fchownat -F auid>=1000 -F auid!=-1 -F key=perm_mod -a always,exit -F arch=b64 -S setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F auid>=1000 -F auid!=-1 -F key=perm_mod -a always,exit -F arch=b32 -S setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F auid>=1000 -F auid!=-1 -F key=perm_mod -a always,exit -S all -F path=/usr/bin/chcon -F perm=x -F auid>=1000 -F auid!=-1 -F key=perm_chng -a always,exit -S all -F path=/usr/bin/setfacl -F perm=x -F auid>=1000 -F auid!=-1 -F key=perm_chng -a always,exit -S all -F path=/usr/bin/chacl -F perm=x -F auid>=1000 -F auid!=-1 -F key=perm_chng RULES # fchmodat2 exists from Linux 6.6; older auditd versions do not know it if ausyscall x86_64 fchmodat2 >/dev/null 2>&1; then echo '-a always,exit -F arch=b64 -S fchmodat2 -F auid>=1000 -F auid!=-1 -F key=perm_mod' echo '-a always,exit -F arch=b32 -S fchmodat2 -F auid>=1000 -F auid!=-1 -F key=perm_mod' fi } 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 </dev/null 2>&1 || { echo "auditd is not installed" >&2; exit 1; } want() { cat <<'RULES' -a always,exit -F arch=b64 -S chmod,fchmod,fchmodat -F auid>=1000 -F auid!=-1 -F key=perm_mod -a always,exit -F arch=b32 -S chmod,fchmod,fchmodat -F auid>=1000 -F auid!=-1 -F key=perm_mod -a always,exit -F arch=b64 -S chown,fchown,lchown,fchownat -F auid>=1000 -F auid!=-1 -F key=perm_mod -a always,exit -F arch=b32 -S lchown,fchown,chown,fchownat -F auid>=1000 -F auid!=-1 -F key=perm_mod -a always,exit -F arch=b64 -S setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F auid>=1000 -F auid!=-1 -F key=perm_mod -a always,exit -F arch=b32 -S setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F auid>=1000 -F auid!=-1 -F key=perm_mod -a always,exit -S all -F path=/usr/bin/chcon -F perm=x -F auid>=1000 -F auid!=-1 -F key=perm_chng -a always,exit -S all -F path=/usr/bin/setfacl -F perm=x -F auid>=1000 -F auid!=-1 -F key=perm_chng -a always,exit -S all -F path=/usr/bin/chacl -F perm=x -F auid>=1000 -F auid!=-1 -F key=perm_chng RULES # fchmodat2 exists from Linux 6.6; older auditd versions do not know it if ausyscall x86_64 fchmodat2 >/dev/null 2>&1; then echo '-a always,exit -F arch=b64 -S fchmodat2 -F auid>=1000 -F auid!=-1 -F key=perm_mod' echo '-a always,exit -F arch=b32 -S fchmodat2 -F auid>=1000 -F auid!=-1 -F key=perm_mod' fi } f=/etc/audit/rules.d/60-cirsec-perm.rules t=$(mktemp) { echo '# Written by CIRSEC Baselines CB-UBU-AUDIT-020'; 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 references: - title: audit.rules(7), Ubuntu manual pages url: https://manpages.ubuntu.com/manpages/noble/man7/audit.rules.7.html publisher: Canonical kind: vendor-doc accessed: 2026-10-19 - title: auditctl(8), Ubuntu manual pages url: https://manpages.ubuntu.com/manpages/noble/man8/auditctl.8.html publisher: Canonical kind: vendor-doc accessed: 2026-10-19 - title: ANSSI-BP-028 v2.0 - Recommandations de configuration d'un système GNU/Linux (R73) url: https://messervices.cyber.gouv.fr/documents-guides/fr_np_linux_configuration-v2.0.pdf publisher: ANSSI kind: guide accessed: 2026-10-19 mappings: - framework: anssi-linux framework_version: "2.0" id: "R73" relation: partial - framework: nist-800-53r5 framework_version: "5.1.1" id: "AU-12" relation: related - framework: cis-ubuntu-2004 framework_version: "3.0.0" id: "6.3.3.9" relation: equivalent - framework: cis-ubuntu-2004 framework_version: "3.0.0" id: "6.3.3.15" relation: equivalent - framework: cis-ubuntu-2004 framework_version: "3.0.0" id: "6.3.3.16" relation: equivalent - framework: cis-ubuntu-2004 framework_version: "3.0.0" id: "6.3.3.17" relation: equivalent - framework: cis-ubuntu-2204 framework_version: "3.0.0" id: "6.2.3.9" relation: equivalent - framework: cis-ubuntu-2204 framework_version: "3.0.0" id: "6.2.3.15" relation: equivalent - framework: cis-ubuntu-2204 framework_version: "3.0.0" id: "6.2.3.16" relation: equivalent - framework: cis-ubuntu-2204 framework_version: "3.0.0" id: "6.2.3.17" relation: equivalent - framework: cis-ubuntu-2404 framework_version: "2.0.0" id: "6.2.3.18" relation: equivalent - framework: cis-ubuntu-2404 framework_version: "2.0.0" id: "6.2.3.24" relation: equivalent - framework: cis-ubuntu-2404 framework_version: "2.0.0" id: "6.2.3.25" relation: equivalent - framework: cis-ubuntu-2404 framework_version: "2.0.0" id: "6.2.3.26" relation: equivalent - framework: cis-ubuntu-2604 framework_version: "1.0.0" id: "6.2.3.18" relation: equivalent - framework: cis-ubuntu-2604 framework_version: "1.0.0" id: "6.2.3.19" relation: equivalent - framework: cis-ubuntu-2604 framework_version: "1.0.0" id: "6.2.3.20" relation: equivalent - framework: cis-ubuntu-2604 framework_version: "1.0.0" id: "6.2.3.27" relation: equivalent - framework: cis-ubuntu-2604 framework_version: "1.0.0" id: "6.2.3.28" relation: equivalent - framework: cis-ubuntu-2604 framework_version: "1.0.0" id: "6.2.3.29" relation: equivalent threats: - framework: mitre-attack id: T1222.002 related_controls: - id: CB-UBU-AUDIT-011 type: requires - id: CB-UBU-AUDIT-029 type: related authors: - name: Alice github: Sn0wAlice verified: - date: 2026-10-19 by: Sn0wAlice versions: ["20.04"] environment: Proxmox VM, Ubuntu 20.04 cloud image, kernel 5.4.0-216-generic notes: "Fails after auditd install; rules written and loaded (augenrules), all present in auditctl -l with auditd 2.8.5; passes after reboot with enabled 2." - date: 2026-10-19 by: Sn0wAlice versions: ["22.04"] environment: Proxmox VM, Ubuntu 22.04 cloud image, kernel 5.15.0-198-generic notes: "Fails after auditd install; rules written and loaded (augenrules), all present in auditctl -l with auditd 3.0.7; passes after reboot with enabled 2." - date: 2026-10-19 by: Sn0wAlice versions: ["24.04"] environment: Proxmox VM, Ubuntu 24.04 cloud image, kernel 6.8.0-147-generic notes: "Fails after auditd install; rules written and loaded (augenrules), all present in auditctl -l with auditd 3.1.2; passes after reboot with enabled 2. auditd 3.1.2 does not know fchmodat2 (rules not generated)." - date: 2026-10-19 by: Sn0wAlice versions: ["26.04"] environment: Proxmox VM, Ubuntu 26.04 cloud image, kernel 7.0.0-38-generic notes: "Fails after auditd install; rules written and loaded (augenrules), all present in auditctl -l with auditd 4.1.2; passes after reboot with enabled 2. fchmodat2 rules added; chcon rule loads but /usr/bin/chcon is a uutils symlink." introduced_in: 0.1.0 created: 2026-10-19 updated: 2026-10-19