{
  "id": "CB-UBU-AUDIT-036",
  "standard": "ubuntu",
  "version": "0.1.0",
  "url": "https://baselines.cirsec.org/b/ubuntu/v0.1.0/CB-UBU-AUDIT-036",
  "json": "https://baselines.cirsec.org/b/ubuntu/v0.1.0/CB-UBU-AUDIT-036.json",
  "yaml": "https://baselines.cirsec.org/b/ubuntu/v0.1.0/CB-UBU-AUDIT-036.yml",
  "profiles_effective": [
    "server-hardened",
    "desktop-hardened"
  ],
  "license": "Text CC BY 4.0, code Apache-2.0",
  "attribution": "CIRSEC Baselines, https://baselines.cirsec.org",
  "control": {
    "id": "CB-UBU-AUDIT-036",
    "title": "Audit administrative commands that are not setuid",
    "finding": {
      "title": "Use of administrative commands is not recorded",
      "description": "Commands that partition disks, load AppArmor profiles, create accounts or hold SSH keys run without a record of who used them."
    },
    "status": "active",
    "profiles": [
      "server-hardened",
      "desktop-hardened"
    ],
    "risk": {
      "severity": "medium"
    },
    "assessment": "automated",
    "tags": [
      "auditd",
      "privileged"
    ],
    "description": "Some administrative commands are not setuid or setgid, so CB-UBU-AUDIT-026 does not cover them,\nyet their use matters in an investigation. This control adds one auditd rule per command in\n`{{ commands }}`, key `privileged`, in `/etc/audit/rules.d/60-cirsec-admin-cmds.rules`. Each\nrule records every run of the program by a user who logged in. By default:\n\n- `fdisk`: changes to disk partitions;\n- `apparmor_parser`: loading, replacing or removing AppArmor profiles;\n- `useradd`: account creation;\n- `ssh-agent`: an agent that holds private keys for the session;\n- `unix_update`: the PAM helper that changes local passwords.\n\nEach command is looked up in `/usr/sbin`, `/usr/bin`, `/sbin` and `/bin`, and its real path is\nused. Commands that are not installed are skipped, and so are setuid or setgid ones, which\nCB-UBU-AUDIT-026 already audits (`ssh-agent` is setgid on Ubuntu 20.04 and 22.04).\n",
    "rationale": "Repartitioning a disk, unloading an AppArmor profile, creating a back-door account or reusing a\nforwarded SSH agent are steps of an intrusion that leave no other trace. Recording each run,\nwith the identity of the person who logged in, keeps them attributable.\n",
    "impact": "Few records: these commands are rarely run. Once the audit configuration is locked\n(CB-UBU-AUDIT-029), a changed rule only loads at the next reboot.\n",
    "notes": "`ssh-agent` is started at each graphical login on desktops, which adds one record per session.\n",
    "setting": {
      "location": "/etc/audit/rules.d/60-cirsec-admin-cmds.rules",
      "default_value": "No audit rules",
      "recommended_value": "Rules loaded (auditctl -l) and present in /etc/audit/rules.d/60-cirsec-admin-cmds.rules"
    },
    "parameters": [
      {
        "name": "commands",
        "type": "list",
        "description": "Names of the administrative commands to audit, looked up in /usr/sbin, /usr/bin, /sbin and /bin.",
        "default": [
          "fdisk",
          "apparmor_parser",
          "useradd",
          "ssh-agent",
          "unix_update"
        ]
      }
    ],
    "audit": {
      "manual": "1. For each command, find its real path with `readlink -f /usr/sbin/<command>` (or\n   `/usr/bin/<command>`), and skip it if `stat -c %A` shows an `s` (CB-UBU-AUDIT-026 covers it).\n2. Run `auditctl -l` as root. It must list, for each remaining command:\n   ```\n   -a always,exit -S all -F path=<real path> -F perm=x -F auid>=1000 -F auid!=-1 -F key=privileged\n   ```\n3. Run `grep -h . /etc/audit/rules.d/*.rules`. The same rules must be present, so they load at boot.\n",
      "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; }\nwant() {\nfor c in $CB_COMMANDS; do\n  for d in /usr/sbin /usr/bin /sbin /bin; do\n    [ -f \"$d/$c\" ] && { readlink -f \"$d/$c\"; break; }\n  done\ndone | sort -u | while IFS= read -r p; do\n  # setuid and setgid programs are audited by CB-UBU-AUDIT-026\n  [ -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\"\ndone\n}\nloaded=$(auditctl -l 2>&1) || { echo \"$loaded\"; exit 3; }\ndisk=$(cat /etc/audit/rules.d/*.rules 2>/dev/null)\nn=0 rc=0\nwhile IFS= read -r r; do\n  [ -n \"$r\" ] || continue\n  n=$((n + 1))\n  printf '%s\\n' \"$loaded\" | grep -Fxq -- \"$r\" || { echo \"not loaded: $r\"; rc=1; }\n  printf '%s\\n' \"$disk\" | grep -Fxq -- \"$r\" || { echo \"not in /etc/audit/rules.d: $r\"; rc=1; }\ndone <<EOF\n$(want)\nEOF\n[ \"$rc\" = 1 ] || echo \"$n rules loaded and present in /etc/audit/rules.d\"\nexit \"$rc\"\n"
          }
        }
      ]
    },
    "remediation": {
      "manual": "1. Write the expected rules to `/etc/audit/rules.d/60-cirsec-admin-cmds.rules` (mode 0640).\n2. Run `augenrules --load`. If `auditctl -s` shows `enabled 2`, the configuration is locked:\n   reboot to load the new rules.\n",
      "effects": {
        "restart": "none",
        "disruption": "none",
        "lockout_risk": false
      },
      "rollback": "Delete `/etc/audit/rules.d/60-cirsec-admin-cmds.rules` and run `augenrules --load` (or reboot if the configuration is locked).\n",
      "scripts": [
        {
          "id": "rules-file",
          "engine": "shell",
          "content": "command -v augenrules >/dev/null 2>&1 || { echo \"auditd is not installed\" >&2; exit 1; }\nwant() {\nfor c in $CB_COMMANDS; do\n  for d in /usr/sbin /usr/bin /sbin /bin; do\n    [ -f \"$d/$c\" ] && { readlink -f \"$d/$c\"; break; }\n  done\ndone | sort -u | while IFS= read -r p; do\n  # setuid and setgid programs are audited by CB-UBU-AUDIT-026\n  [ -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\"\ndone\n}\nf=/etc/audit/rules.d/60-cirsec-admin-cmds.rules\nt=$(mktemp)\n{ echo '# Written by CIRSEC Baselines CB-UBU-AUDIT-036'; want; } >\"$t\"\nif ! cmp -s \"$t\" \"$f\"; then\n  cb_backup \"$f\"\n  cat \"$t\" >\"$f\"\nfi\nrm -f \"$t\"\nchmod 640 \"$f\"\nif auditctl -s | grep -q '^enabled 2'; then\n  echo \"audit rules are locked (-e 2): reboot to load $f\"\nelse\n  augenrules --load >/dev/null\nfi\n"
        }
      ]
    },
    "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": "nist-800-53r5",
        "framework_version": "5.1.1",
        "id": "AC-6(9)",
        "relation": "related"
      }
    ],
    "threats": [
      {
        "framework": "mitre-attack",
        "id": "T1136.001"
      },
      {
        "framework": "mitre-attack",
        "id": "T1562.001"
      },
      {
        "framework": "mitre-attack",
        "id": "T1563.001"
      }
    ],
    "related_controls": [
      {
        "id": "CB-UBU-AUDIT-011",
        "type": "requires"
      },
      {
        "id": "CB-UBU-AUDIT-026",
        "type": "related"
      },
      {
        "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; 4 rules written (ssh-agent setgid, left to AUDIT-026), loaded and locked; passes after reboot."
      },
      {
        "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; 4 rules written (ssh-agent setgid, left to AUDIT-026), loaded and locked; passes after reboot."
      },
      {
        "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; 4 rules written (ssh-agent setgid, left to AUDIT-026), loaded and locked; passes after reboot."
      },
      {
        "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; 4 rules written (ssh-agent setgid, left to AUDIT-026), loaded and locked; passes after reboot."
      }
    ],
    "introduced_in": "0.1.0",
    "created": "2026-10-19",
    "updated": "2026-10-19"
  }
}