Files

101 lines
5.0 KiB
Plaintext

# DIRTYFAIL — auditd detection rules
#
# Drop into /etc/audit/rules.d/, then reload:
#
# sudo install -m 0640 99-dirtyfail.rules /etc/audit/rules.d/
# sudo augenrules --load
# sudo systemctl restart auditd
#
# These rules generate audit events for the syscalls the DIRTYFAIL
# exploit chain uses. They are intentionally noisy on systems that
# legitimately use rootless containers, IPsec, or AFS — review the
# Tuning section before enabling on a production host.
#
# Search recorded events:
#
# sudo ausearch -k dirtyfail-xfrm
# sudo ausearch -k dirtyfail-rxkey
# sudo ausearch -k dirtyfail-userns
#
# Rules MUST stay on single lines — auditctl(8) does not honor
# backslash-newline continuations in rule files.
#
# Tested on: Debian 13, Ubuntu 24.04/26.04, AlmaLinux 10, Fedora 44.
## ----------------------------------------------------------------- ##
## 1. XFRM netlink registration from a non-root account
##
## socket(AF_NETLINK, SOCK_RAW, NETLINK_XFRM) is an extremely strong
## signal: legitimate use is "ip xfrm" (root) or `swanctl`/charon (root)
## or networkd (root). An unprivileged account creating this socket
## is the precondition for ESP v4/v6/GCM exploitation.
##
## socket() args: a0=family(16=AF_NETLINK) a2=protocol(6=NETLINK_XFRM)
## auid filter: ignore kernel/system processes (auid=4294967295)
## match interactive logins (auid >= 1000)
## ----------------------------------------------------------------- ##
-a always,exit -F arch=b64 -S socket -F a0=16 -F a2=6 -F auid>=1000 -F auid!=4294967295 -k dirtyfail-xfrm
-a always,exit -F arch=b32 -S socket -F a0=16 -F a2=6 -F auid>=1000 -F auid!=4294967295 -k dirtyfail-xfrm
## ----------------------------------------------------------------- ##
## 2. add_key("rxrpc", ...) — RxRPC session-key registration
##
## The rxkad-handshake forgery requires registering a rxrpc-typed key
## via add_key(2). On most servers this should never happen from an
## unprivileged uid; AFS clients that legitimately use this run as
## root or a service account.
## ----------------------------------------------------------------- ##
-a always,exit -F arch=b64 -S add_key -F auid>=1000 -F auid!=4294967295 -k dirtyfail-rxkey
-a always,exit -F arch=b32 -S add_key -F auid>=1000 -F auid!=4294967295 -k dirtyfail-rxkey
## ----------------------------------------------------------------- ##
## 3. unshare(CLONE_NEWUSER) from interactive accounts
##
## CLONE_NEWUSER == 0x10000000. Every DIRTYFAIL exploit mode does this
## once. WARNING: this fires on every legitimate `unshare -U`, every
## podman/buildah container start, every chrome/firefox sandbox spawn.
## Filter to executions you don't expect, or treat as low-fidelity noise
## that pairs well with the dirtyfail-xfrm key for high-fidelity alerts.
## ----------------------------------------------------------------- ##
-a always,exit -F arch=b64 -S unshare -F a0&268435456 -F auid>=1000 -F auid!=4294967295 -k dirtyfail-userns
-a always,exit -F arch=b32 -S unshare -F a0&268435456 -F auid>=1000 -F auid!=4294967295 -k dirtyfail-userns
## ----------------------------------------------------------------- ##
## 4. AF_ALG socket creation — Copy Fail / GCM precondition
##
## socket(AF_ALG, ...). a0=38 (PF_ALG). Legitimate uses: cryptsetup,
## kernel-side TLS offload, some QEMU paths. Suspicious from a shell
## account.
## ----------------------------------------------------------------- ##
-a always,exit -F arch=b64 -S socket -F a0=38 -F auid>=1000 -F auid!=4294967295 -k dirtyfail-afalg
-a always,exit -F arch=b32 -S socket -F a0=38 -F auid>=1000 -F auid!=4294967295 -k dirtyfail-afalg
## ----------------------------------------------------------------- ##
## 5. Directly watch /etc/passwd and /etc/shadow for in-place modifications
##
## A successful exploit modifies the page-cache copy (which is what
## PAM reads), but these watches fire when /usr/bin/passwd, vipw, or
## anything else opens these files for writing. Useful as a baseline
## change-detection rule independent of DIRTYFAIL.
## ----------------------------------------------------------------- ##
-w /etc/passwd -p wa -k dirtyfail-passwd-write
-w /etc/shadow -p wa -k dirtyfail-shadow-write
## ----------------------------------------------------------------- ##
## Tuning notes
##
## - On servers running rootless containers, dirtyfail-userns will be
## high-volume noise. Either drop rule 3, or filter on `comm!=podman`
## etc. for your specific runtime.
## - On IPsec gateways, dirtyfail-xfrm fires for every legitimate SA
## install. Drop the rule or filter `comm` to your VPN daemon.
## - Pair dirtyfail-userns + dirtyfail-xfrm with a SIEM correlation
## rule: "same auid emits both within 5 seconds" → high-confidence
## exploit-attempt alert.
##
## Note: the AppArmor `change_onexec` rule that an earlier draft
## included is omitted — auditctl won't reliably match writes to
## /proc/self/attr/exec via -F path because the path is per-pid.
## Use the userns + xfrm pair instead for the bypass-detection signal.
## ----------------------------------------------------------------- ##