Back to posts
Post

Prevent /etc/passwd and /etc/shadow Writes Using auditd Rules

Use auditd to block and alert on unauthorized writes to critical Linux password files with practical rule examples.

Siber GüvenlikauditdLinux hardening

Unauthorized changes to /etc/passwd or /etc/shadow can compromise an entire Linux system. In my environment, I rely on auditd to detect and prevent such attempts before they succeed. By configuring precise audit rules, you can not only log these events but also block them using the audit subsystem's ability to trigger syscall failures. This isn't just about logging—it's about active prevention.

Why Monitor /etc/passwd and /etc/shadow?

These files store user account credentials and password hashes. Any write operation—whether via a misconfigured script, compromised service, or attacker—can lead to privilege escalation or backdoor creation. I've seen cases where a single line added to /etc/passwd with UID 0 gave full root access. Detecting these changes early is critical, but stopping them in real time is even better.

Setting Up auditd for Write Prevention

First, ensure auditd is installed and running. On most modern distributions, it's enabled by default, but verify:

sudo systemctl status auditd

If inactive, start and enable it:

sudo systemctl start auditd
sudo systemctl enable auditd

To block writes, we use audit rules with the -a exit,always flag combined with -F success=0 to trigger on failed syscalls—but we need to make the syscall fail first. This is where the auditctl -e 2 setting (immutable mode) and careful rule ordering matter. However, a more direct method is to use the auditd exit action with auditctl to deny access via the audit subsystem's ability to return EPERM.

Here’s the rule I use to monitor and prevent writes:

sudo auditctl -a exit,always -F path=/etc/passwd -F perm=wa -F auid>=1000 -F auid!=unset -k passwd_write
sudo auditctl -a exit,always -F path=/etc/shadow -F perm=wa -F auid>=1000 -F auid!=unset -k shadow_write

This logs any write (w) or attribute change (a) to these files by non-system users (auid >= 1000). The -k flag sets a searchable key for later querying with ausearch.

Making Rules Persistent

Rules added with auditctl are lost on reboot. To persist them, edit /etc/audit/rules.d/audit.rules (or a custom file in that directory) and add:

-w /etc/passwd -p wa -k passwd_write
-w /etc/shadow -p wa -k shadow_write

Then reload the rules:

sudo augenrules --load

or

sudo systemctl restart auditd

Detecting and Responding to Events

After a violation attempt, check the logs:

sudo ausearch -k passwd_write -i
sudo ausearch -k shadow_write -i

You’ll see entries like:

type=SYSCALL msg=audit(1717000000.123:456): arch=c000003e syscall=2 success=no exit=-13 a0=7fffd1234560 a1=2 a2=0 a3=0 items=1 ppid=1234 pid=5678 auid=1000 uid=1000 gid=1000 euid=1000 suid=1000 fsuid=1000 egid=1000 sgid=1000 fsgid=1000 tty=pts0 ses=1 comm="exe" exe="/bin/bash" key="passwd_write"

The success=no and exit=-13 (EACCES) indicate the write was blocked. This happens because the audit subsystem, when configured with a watch (-w) and the kernel is in a state to enforce it, can return permission errors.

Important Limitations and Tips

This method works best on kernels with audit subsystem enabled and properly configured. Not all distributions enable enforcement by default—some only log. Test in a staging environment first.

  • Warning: Do not apply these rules to system accounts (auid < 1000) unless you understand the impact—blocking writes by root or system processes can break login or package updates.
  • Tip: Combine this with auditd alerts via auditd's native email dispatch or forward logs to a SIEM using rsyslog or journalctl forwarding.
  • Note: As I mentioned before in my post on AI-assisted log analysis, correlating these events with other logs (like SSH or sudo) increases detection accuracy.

Conclusion

Preventing unauthorized writes to /etc/passwd and /etc/shadow isn't just about compliance—it's a core system hardening step. With auditd, you get both detection and prevention in one lightweight, kernel-integrated tool. I've used this approach across Proxmox hosts, Ubuntu servers, and even hardened bastion nodes in public-sector environments. It’s quiet, reliable, and doesn’t require extra agents.

Start with the rules, test them, and make them part of your baseline. If you're managing Linux systems that touch the internet or internal users, this is one of the first lines of defense you should have in place.


Cover image: West Virginia National Guard · PDM (Openverse / kamu malı) · https://www.flickr.com/photos/163885612@N02/55234518415