Handbook sections

File Permissions & Ownership

Last reviewed

Sensitive files like /etc/shadow, SSH keys and cron jobs are only as safe as their mode bits. Tighten permissions, set a strict UMASK, kill world-writable files and review SUID/SGID so a low-privilege account can't read secrets or escalate.

The threat: a loose mode bit turns a foothold into a breach

Discretionary access control is the last line of defense when an attacker already has an account on the box. A loose permission turns a foothold into a breach: a world-readable /etc/shadow hands over every password hash for offline cracking; a group-writable /etc/passwd, /etc/sudoers or /etc/crontab lets an unprivileged user rewrite identity, sudo policy or a root cron job and escalate at will. World-writable files (-rw-rw-rw-) in shared paths like /tmp are a classic vector for symlink and config-injection attacks. SUID/SGID binaries run with the owner's privileges regardless of who launches them: a single misplaced setuid-root binary is a direct path to root. And SSH host keys or private keys readable by other undermine the whole trust chain.

Why harden it

Permissions are cheap to get wrong and catastrophic when wrong. There is no exploit to write: the attacker simply reads the file or runs the binary the kernel already lets them touch. Hardening this domain means that even after an account is compromised, the secrets stay unreadable, the privilege-policy files stay untouchable, and there are no surprise paths to root, shrinking the blast radius of every other failure.

Defense principles applied

  • Least privilege: secrets get the minimum mode. /etc/shadow and /etc/gshadow unreadable to group/other (0000 or 0640), /etc/sudoers root-only (0440), /etc/passwd//etc/group 0644, audit logs 0640 or stricter.
  • Attack-surface reduction: no unauthorized world-writable files; no stray SUID/SGID bits where they aren't needed.
  • Integrity over confidentiality where it matters: /etc/passwd must stay world-readable to function, so the rule is that it is not writable by group/other; the credential files get both.
  • Accountability: log files under /var/log are locked down so an attacker can't read or tamper with the trail.
  • Fine-grained control with ACLs: when owner/group/other modes are too coarse, POSIX ACLs (setfacl/getfacl) grant a specific user exactly the access needed.

Set a strict default with UMASK 027

Every file a process creates inherits a mode masked by UMASK. The permissive default 022 makes new files world-readable; 027 removes all access for other (and write for group), so a freshly written log, key or config is private by default. Set it in /etc/login.defs (UMASK 027), reinforce it through PAM (pam_umask), and in /etc/profile//etc/bashrc. This is a system-wide safety net: it fixes the files you forget, not just the ones you chmod.

Hunt the dangerous files

# World-writable files (and dirs missing the sticky bit)
find / -xdev -type f -perm -0002 -ls
find / -xdev -type d -perm -0002 ! -perm -1000 -ls

# SUID / SGID inventory: review against a known baseline
find / -xdev \( -perm -4000 -o -perm -2000 \) -type f -ls

# Unowned files: a deleted user's UID still owns these
find / -xdev \( -nouser -o -nogroup \) -ls

An unowned file is dangerous because a new account reusing that UID silently inherits ownership. A surprise SUID binary is the shortest escalation path; compare the inventory to the distro's expected set and chmod u-s anything unexpected.

What Pavois audits: the actual mode on the target

Pavois's File permissions rules resolve the actual mode and ownership on the target (via CINC's file resource), not what a template claims. It checks credential/identity files (/etc/shadow, /etc/gshadow carry no access; /etc/passwd, /etc/group are not writable by group/other, plus their .bak), privilege policy (/etc/sudoers, /etc/sudoers.d/), the full cron/at surface, SSH material (/etc/ssh, host keys, *.pub, sshd_config.d/), bootloader files, and the log trail. Every rule asserts the setuid/setgid/sticky bits are off where they must be, and a dedicated world-writable canary confirms shared paths like /tmp are not writable by other. These map to CIS file-permission sections and ANSSI BP-028 R29/R50.

Pitfalls

  • A blanket chmod -R breaks things: tightening /etc recursively can strip execute bits off directories. Target specific files.
  • Removing a legitimate SUID bit breaks a tool (passwd, sudo, ping historically): review, don't strip blindly.
  • UMASK in one place isn't enough: a login shell, a cron job and a systemd service can each have a different umask; set it in login.defs and PAM.
  • /etc/passwd at 0600 locks out name resolution: it must stay 0644 (readable), only unwritable by others.

FAQ

Why 0000/0640 on /etc/shadow and not 0644? Because it holds password hashes; only root (and the shadow group on some distros) needs them. World-readable shadow is offline cracking handed over.

UMASK 022 or 027? 027 for a hardened host: new files are private to owner and group, denied to others. 022 leaves them world-readable.

How do I find escalation paths I missed? Inventory SUID/SGID (find -perm -4000), world-writable files, and unowned files; compare against the distro baseline and your expectations.