Permissions

Overview

Linux file permissions control who can read, write, and execute files and directories. The permissions model is the foundation of Linux security — and its misconfigurations are one of the most common paths to privilege escalation. SUID binaries, world-writable scripts executed by root, and misconfigured sudoers entries are staples of Linux privilege escalation.

Key Concepts

Permission Basics

Every file and directory has three permission sets applied to three categories of users:

Category Symbol Description
Owner (user) u The user who owns the file
Group g Members of the file's group
Others o Everyone else

Each category has three permission types:

Permission Symbol On Files On Directories
Read r (4) View contents List contents
Write w (2) Modify contents Create/delete files inside
Execute x (1) Run as program Enter directory (cd)

Reading Permissions

ls -la /etc/passwd

Output:

-rw-r--r-- 1 root root 2847 Jan 15 10:30 /etc/passwd

Breaking down -rw-r--r--:

Position Characters Meaning
1 - File type: - regular, d directory, l symlink, c char device, b block device
2-4 rw- Owner: read + write, no execute
5-7 r-- Group: read only
8-10 r-- Others: read only

The two fields after the permission string are owner (root) and group (root).

Numeric (Octal) Notation

Permissions map to numbers: read = 4, write = 2, execute = 1. Add them per category.

Octal Binary Permission
0 --- None
1 --x Execute only
2 -w- Write only
3 -wx Write + execute
4 r-- Read only
5 r-x Read + execute
6 rw- Read + write
7 rwx Read + write + execute

Common permission sets:

Octal Symbolic Typical Use
644 rw-r--r-- Regular files (owner writes, everyone reads)
755 rwxr-xr-x Executables and directories
600 rw------- Private files (SSH keys, configs with credentials)
700 rwx------ Private directories
777 rwxrwxrwx World-writable (security risk)
4755 rwsr-xr-x SUID executable

Changing Permissions

# chmod — change file mode
chmod 644 file.txt                  # Set exact permissions (octal)
chmod 755 script.sh                 # Owner rwx, group/others rx

# Symbolic mode
chmod u+x script.sh                # Add execute for owner
chmod g-w file.txt                 # Remove write for group
chmod o-rwx file.txt               # Remove all permissions for others
chmod a+r file.txt                 # Add read for all (a = all)
chmod u+x,g-w,o-rwx file.txt      # Multiple changes

# Recursive
chmod -R 755 directory/            # Apply to directory and all contents

Changing Ownership

# chown — change owner and group
chown user file.txt                # Change owner
chown user:group file.txt          # Change owner and group
chown :group file.txt              # Change group only
chown -R user:group directory/     # Recursive

# chgrp — change group only
chgrp developers project/

Special Permissions

SUID (Set User ID) — Octal 4000

When set on an executable, it runs with the file owner's effective UID (EUID) regardless of who executes it. The real UID (RUID) remains the calling user's. If a SUID binary is owned by root, it runs as root. Note: the Linux kernel ignores the SUID bit on interpreted scripts (shebangs) — only compiled binaries honour it.

# Identify SUID files
find / -perm -4000 -type f 2>/dev/null

# Example: /usr/bin/passwd has SUID set
ls -la /usr/bin/passwd
# -rwsr-xr-x 1 root root 68208 ... /usr/bin/passwd

The s in the owner execute position indicates SUID. /usr/bin/passwd needs SUID to modify /etc/shadow, which is only writable by root.

SUID binaries are the first thing to check during privilege escalation. Resources like GTFOBins document which SUID binaries can be abused to gain root access.

# Set SUID
chmod 4755 binary
chmod u+s binary

# Remove SUID
chmod 0755 binary
chmod u-s binary

SGID (Set Group ID) — Octal 2000

On executables: runs with the file's group privileges. On directories: new files created inside inherit the directory's group (instead of the creator's primary group).

# Identify SGID files
find / -perm -2000 -type f 2>/dev/null

# SGID on directory — new files inherit group
ls -la /opt/shared/
# drwxrwsr-x 2 root developers 4096 ... /opt/shared/

The s in the group execute position indicates SGID.

# Set SGID
chmod 2755 directory/
chmod g+s directory/

Sticky Bit — Octal 1000

On directories: only the file owner (or root) can delete files inside, even if the directory is world-writable. /tmp uses this to prevent users from deleting each other's files.

ls -la / | grep tmp
# drwxrwxrwt  15 root root  ... tmp

The t in the others execute position indicates the sticky bit.

# Set sticky bit
chmod 1777 directory/
chmod +t directory/

Linux Capabilities

Capabilities fragment root privileges into granular units, allowing binaries to perform specific privileged operations without full root. A binary with elevated capabilities is a privilege escalation vector just like SUID root.

# List capabilities on all binaries (primary privesc check)
getcap -r / 2>/dev/null

# View capabilities on a specific binary
getcap /usr/bin/python3

# Set a capability
sudo setcap cap_net_bind_service+ep /usr/bin/python3

# Remove all capabilities
sudo setcap -r /usr/bin/python3

High-value capabilities for privilege escalation:

Capability Abuse Potential
cap_setuid+ep Call setuid(0) → root shell
cap_sys_ptrace+ep Inject into any process
cap_dac_read_search+ep Read any file (bypass ACLs)
cap_net_raw+ep Craft raw packets, sniff traffic

umask

umask defines the default permission mask for newly created files and directories. It works by bitwise AND with the complement of the mask: effective_perms = default_mode & (~umask). For common values the result is the same as subtraction, but they are not equivalent for arbitrary masks.

# View current umask
umask          # Octal format (e.g., 0022)
umask -S       # Symbolic format (e.g., u=rwx,g=rx,o=rx)
umask File result (from 0666) Directory result (from 0777)
0022 644 (rw-r--r--) 755 (rwxr-xr-x)
0077 600 (rw-------) 700 (rwx------)
0002 664 (rw-rw-r--) 775 (rwxrwxr-x)
# Set umask for current session
umask 0077     # Restrictive — new files 600, new directories 700

Sudoers

/etc/sudoers controls which users can run commands as other users via sudo. Misconfigurations in sudoers are a primary privilege escalation vector.

# View current sudo privileges
sudo -l

sudo -l shows what the current user can run with sudo. Output format:

User kali may run the following commands on host:
    (ALL : ALL) ALL
    (root) NOPASSWD: /usr/bin/vim

The first line allows all commands as any user (with password). The second allows /usr/bin/vim as root without a password — a direct path to root shell via :!/bin/bash inside vim.

Common dangerous sudoers entries:

Entry Risk
(ALL) NOPASSWD: ALL Full root without password
(root) NOPASSWD: /usr/bin/vim Shell escape via :!/bin/bash
(root) NOPASSWD: /usr/bin/find Command execution via -exec
(root) NOPASSWD: /usr/bin/python3 Direct code execution
(root) NOPASSWD: /usr/bin/less Shell escape via !sh
(root) NOPASSWD: /usr/bin/env Run arbitrary commands
# Sudoers file editing (always use visudo to prevent syntax errors)
sudo visudo

visudo validates syntax before saving — a broken sudoers file can lock all users out of sudo.

Practical Examples

Privilege Escalation Enumeration

# 1. Check sudo permissions
sudo -l

# 2. Find SUID binaries
find / -perm -4000 -type f 2>/dev/null

# 3. Find SGID binaries
find / -perm -2000 -type f 2>/dev/null

# 4. Find files writable by current user (includes owned, group-writable, world-writable)
find / -writable -type f 2>/dev/null

# 5. Find directories writable by current user
find / -writable -type d 2>/dev/null

# 6. Check cron jobs for scripts you can modify
cat /etc/crontab
ls -la /etc/cron.d/
ls -la /etc/cron.daily/

# 7. Check for misconfigured file permissions
ls -la /etc/shadow      # Should be 640 or 600, owned by root:shadow
ls -la /etc/passwd       # Should be 644, owned by root:root
ls -la /etc/sudoers      # Should be 440, owned by root:root

If /etc/shadow is readable by your user, extract the hashes and crack them offline. If /etc/passwd is writable, add a new root-level user directly.

References

Official Documentation