Tracing Unauthorized Shadow File Access Using Auditd Event Log Forensics
Theory
Why This Matters
/etc/shadow stores hashed passwords for all local Linux accounts. An attacker who reads this file obtains hashes for every user, including root, which can be cracked offline or used directly in pass-the-hash attacks against services accepting these credentials. An attacker who writes to it can replace any password hash with a known value, gaining instant access. Because /etc/shadow is typically readable only by root, any non-root process accessing it represents a definitive privilege violation — and because auditd can watch this file at the kernel level, the access is logged even if the attacker clears shell history and other artefacts.
Core Concept
/etc/shadow (and its group equivalent /etc/gshadow) contains one line per user account, with fields including username, hashed password (in $algo$salt$hash format), and password aging data. Default permissions are 640 root shadow or 000 root root depending on distribution. Only shadow-group processes (passwd, sudo, login) and root should access it.
auditd file watch rules (-w /etc/shadow -p rwa -k shadow_access) trigger an audit record for every read (r), write (w), or attribute change (a) on the file. The audit record includes: the calling process's UID, EUID, AUID (audit UID — the original logged-in user), PID, PPID, and the operation type.
Suspicious access patterns:
- Any process with EUID != 0 and not in the shadow group reading /etc/shadow
- Write access by any process other than /usr/bin/passwd, chpasswd, or similar legitimate tools
- Access from a shell spawned by a web server process (apache, nginx, www-data parent chain)
- Access immediately following a SUID binary execution (SUID escalation → shadow read)
Technical Deep-Dive
# Audit rule: watch /etc/shadow and /etc/gshadow for read/write/attr
# /etc/audit/rules.d/shadow.rules:
# -w /etc/shadow -p rwa -k shadow_access
# -w /etc/gshadow -p rwa -k shadow_access
# -w /etc/passwd -p wa -k passwd_change
# Reload: augenrules --load
# Search audit log for shadow access events
ausearch -k shadow_access --interpret | grep -E "(type=PATH|type=SYSCALL)"
# Show process details for shadow access
ausearch -k shadow_access --interpret -i
| awk '/type=SYSCALL/{print}' | head -20
# Parse ausearch output to extract key fields
ausearch -k shadow_access --interpret --format csv
| awk -F, '''{print $1, $6, $7, $10, $11}'''
| head -20
# Fields: timestamp, uid, auid, exe, key
# Detect web server processes reading shadow
ausearch -k shadow_access --interpret
| grep -E "(apache|nginx|www-data|httpd|php)" | head -10
# Parse raw auditd log for shadow access events
import re, sys
SYSCALL_RE = re.compile(
r'type=SYSCALL.*?pid=(d+).*?uid=(d+).*?euid=(d+).*?auid=(d+).*?exe="([^"]+)"'
)
PATH_RE = re.compile(r'type=PATH.*?name="([^"]+)"')
events = []
current = {}
for line in open("/var/log/audit/audit.log"):
if "shadow" in line.lower() or current:
if "type=SYSCALL" in line:
m = SYSCALL_RE.search(line)
if m:
current = {
"pid": m.group(1), "uid": m.group(2),
"euid": m.group(3), "auid": m.group(4),
"exe": m.group(5)
}
elif "type=PATH" in line and current:
m = PATH_RE.search(line)
if m and "shadow" in m.group(1):
current["file"] = m.group(1)
events.append(dict(current))
current = {}
for ev in events:
if ev.get("euid") not in ("0",):
print(f"SUSPICIOUS: {ev}")
Analytical Methodology
- Verify that auditd shadow watch rules are present on the host:
auditctl -l | grep shadow. If rules are not loaded, there will be no auditd evidence — but filesystem metadata (ctime of /etc/shadow) can still confirm access. - Run
ausearch -k shadow_access --interpret. Review all hits. For each, identify: calling process executable path, UID, EUID, and AUID. - Legitimate accesses:
passwd,chpasswd,useradd,usermod,sshd(with UsePAM), andsudo(when changing passwords). Flag everything else. - Identify the process tree: use the PID from the auditd record to reconstruct the parent chain. A shadow read from
python3whose parent isapache2confirms web shell to shadow escalation. - Determine the operation type: read (information disclosure) vs write (credential replacement). A write is more serious — check whether any account's password hash changed by comparing /etc/shadow to a backup or by looking for subsequent successful logins from unexpected accounts.
- If a read is confirmed, assess whether offline cracking is likely. MD5crypt (
$1$) and SHA-512crypt ($6$) hashes can be cracked with hashcat. Report the exposed accounts and recommend immediate password rotation. - Check for SELinux or AppArmor denials that preceded the successful access. An attacker may have disabled or bypassed MAC policy as a precursor step.
- Correlate with network logs: was there an outbound connection from the compromised host immediately after the shadow read? This suggests hash exfiltration.
Common Analytical Errors
- Assuming absence of auditd rules means no access occurred: Even without auditd, /etc/shadow ctime reflects the last inode change. If ctime is newer than expected, access or modification occurred. Cross-reference with backup hashes.
- Ignoring AUID vs UID: AUID is the audit UID assigned at login and carried across su/sudo transitions. It identifies the original human user even if the process has changed UID to root. A shadow read with AUID != 0 means a non-root user escalated to access shadow.
- Missing procfs evidence on live systems: On a live host,
/proc/<pid>/exe,/proc/<pid>/cmdline, and/proc/<pid>/statusexpose the running process that accessed shadow. Check immediately if the host is still live. - Not checking /etc/shadow for modifications: An attacker who writes to shadow may add a new root-equivalent account with a known password. Always diff /etc/shadow against the most recent backup after a suspected write event.
NICE Framework Alignment
| Code | Work Role Knowledge / Skill / Task | Relevance |
|---|---|---|
| K0046 | Knowledge of intrusion detection methodologies | File integrity monitoring of /etc/shadow is a Linux detection control baseline requirement |
| K0145 | Knowledge of security event correlation tools | auditd event correlation with process tree analysis is a SIEM-adjacent Linux forensics technique |
| K0187 | Knowledge of file type abuse by adversaries | /etc/shadow is a plain-text system file whose format enables password hash extraction for offline cracking |
| S0047 | Skill in preserving evidence integrity | Collecting /etc/shadow with checksums and preserving auditd logs before incident response activities |
| T0049 | Decrypt seized data / analyze forensic artifacts | Cracking extracted SHA-512crypt or MD5crypt hashes from /etc/shadow using hashcat or John |
Further Reading
- Linux man page: shadow(5) — /etc/shadow field definitions and hash format
- auditd documentation: audit.rules(7) — watch rule syntax and field interpretation
- Hashcat documentation: hash modes 1800 (sha512crypt) and 500 (md5crypt)
- NSA/CISA Linux Hardening Guide — /etc/shadow permission and auditing recommendations
- MITRE ATT&CK T1003.008: /etc/passwd and /etc/shadow — OS Credential Dumping sub-technique
Challenge Lab
Reinforce your learning with a hands-on generated challenge based on this card's competency.