Linux File Permission Hardening in Practice: chmod, umask, and SUID Risk Hunt
World-writable files and extra SUID binaries are common local-privesc entry points. Full Linux permission hardening: tighten default umask, clean world-writable files, hunt and strip SUID/SGID, chattr-lock critical auth files, least-privilege web dirs. Commands are copy-paste ready, with per-item verification and common misconfig checks.
Applicable Scenarios
Linux file-permission hardening is the most basic and most ignored server baseline. Use this when: a web host shares site dirs with a low-privilege process; ops used chmod 777 and any user can tamper; leftover SUID binaries may be local privesc paths; multi-user hosts must restrict who reads sensitive configs. Nginx, MySQL, or custom services—on-disk permissions decide how far an attacker goes after a low-privilege foothold.
Prerequisites
- A reachable Linux server. This article uses CentOS 7+/Ubuntu 20+
- root or sudo
- Confirm special permission needs before running (e.g. web dirs the runtime user must write)
- Rehearse on a test box. Record permission changes before production.
How It Works
Linux keeps three permission sets per file: owner (u), group (g), other (o), mapped to read (r=4), write (w=2), execute (x=1). Hardening is least privilege: the service account reaches only what it must; everything else is tightened. Two special bits matter: SUID (4000) lets the executor inherit the file owner's identity—on the wrong binary it is a privesc path. Sticky bit (1000) on shared dirs like /tmp stops users deleting each other's files. umask sets the default for new files and stops permission sprawl at the source.
Procedure
Step 1: Tighten default umask globally
Edit `/etc/profile` and `/etc/bashrc` (Ubuntu: `/etc/profile` and `/etc/bash.bashrc`). Set umask 027: new files group-readable, other has nothing:
# Current umask
umask
# Set at the end of /etc/profile
echo "umask 027" >> /etc/profile
echo "umask 027" >> /etc/bashrc
# Re-login to apply, then verify:
umask
Step 2: Clean dangerous world-writable files
World-writable files can be tampered by any account. Common implant locations:
# Find world-writable files and dirs (exclude tmp system dirs)
find / -xdev -type f -perm -0002 2>/dev/null
find / -xdev -type d -perm -0002 2>/dev/null
# Confirm each, then tighten
chmod o-w /path/to/suspicious_file
# Shared dirs that must stay writable need the sticky bit
chmod 1777 /tmp
Step 3: Hunt and strip extra SUID/SGID binaries
# List SUID binaries disk-wide
find / -xdev -perm -4000 -type f 2>/dev/null
# List SGID binaries
find / -xdev -perm -2000 -type f 2>/dev/null
Match against the business list. Strip special bits from programs you do not need. On a typical server these usually do not need SUID:
chmod u-s /usr/bin/chage
chmod u-s /usr/bin/gpasswd
chmod u-s /usr/bin/wall
# Note: keep SUID on /usr/bin/passwd and /usr/bin/sudo. Removing them breaks password changes and privilege elevation
Step 4: Harden critical config files
# SSH key and auth file perms (wrong perms break login or allow tampering)
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
# Lock core auth and scheduler files against tampering
chattr +i /etc/passwd /etc/shadow /etc/crontab
# Unlock before editing crontab
# chattr -i /etc/passwd
Step 5: Normalize web directory permissions
Site dirs owned by the runtime user; config files read-only:
# Dirs 755, files 644, owner is the runtime account
chown -R www-data:www-data /var/www/html
find /var/www/html -type d -exec chmod 755 {} \;
find /var/www/html -type f -exec chmod 644 {} \;
# Only the upload dir needs write; prefer no execute
chmod 755 /var/www/html/uploads
# chattr +i does not apply to upload dirs; block PHP execution at the Nginx layer instead
Configuration Verification
# Confirm no leftover world-writable files
find / -xdev -type f -perm -0002 2>/dev/null | wc -l
# Confirm SUID list is business-required only
find / -xdev -perm -4000 -type f 2>/dev/null
# Confirm critical files are locked
lsattr /etc/passwd /etc/shadow
# Unprivileged read of shadow must fail
su - testuser -c "cat /etc/shadow"
FAQ
FAQ 1: After chattr +i, even root cannot edit the file?
Expected. immutable applies to root too. Unlock with chattr -i /etc/passwd, edit, then re-lock. If `chattr` errors Operation not permitted, check whether the filesystem supports the attribute (some containers and NFS mounts do not).
FAQ 2: Avatar upload fails with a permission error. Change to 777?
No. Own the upload dir as the PHP/Nginx runtime user (e.g. chown -R www-data:www-data uploads), dir mode 755, and make sure umask is not tighter. 777 lets every account on the host write that dir. That is a drop path for an attacker.
Summary
Permission hardening is cheap and high-yield. Put it on the go-live checklist: umask 027 everywhere, clean world-writable files, whitelist SUID binaries, chattr-lock critical auth files, least-privilege web dirs by runtime account. Pair with a periodic audit script. Shrinks lateral movement after an initial foothold.