Privilege escalation on Linux is less about a single vulnerability and more about exploiting a series of small oversights to gain root access.

Let’s see what this looks like in practice. Imagine a web application running as www-data that has a cron job executing a script.

# /etc/cron.d/webapp_backup
* * * * * www-data /opt/webapp/backup.sh > /dev/null 2>&1

And the script itself:

#!/bin/bash
tar -czf /var/backups/webapp_$(date +%Y%m%d).tar.gz /var/www/html/webapp

If an attacker can modify the /var/www/html/webapp directory, they could potentially inject malicious code into files that are then backed up. However, a more direct approach might be to exploit the script itself. What if the script doesn’t exist, or if we can place a symlink?

# Attacker gains initial low-privilege shell, discovers the cron job.
# Checks if the script exists:
ls -l /opt/webapp/backup.sh
# If it doesn't, or if we can overwrite it:
rm /opt/webapp/backup.sh
ln -s /tmp/malicious_script.sh /opt/webapp/backup.sh
chmod +x /tmp/malicious_script.sh

Now, when the cron job runs, it executes the attacker’s script as www-data.

# /tmp/malicious_script.sh
#!/bin/bash
cp /bin/bash /tmp/bash_root
chmod +s /tmp/bash_root

The attacker now has a copy of bash in /tmp with the SUID bit set. When they execute this:

/tmp/bash_root -p

They get a root shell.

This is a simplified example. In reality, privilege escalation often involves a chain of events. Here are common vectors and how to mitigate them:

Exploitable SUID Binaries

Any binary with the SUID bit set runs with the permissions of the owner, not the user executing it. If /usr/bin/find has the SUID bit set and is owned by root, running find . -exec /bin/sh \; -quit as an unprivileged user would spawn a shell as root.

Diagnosis:

find / -perm -u=s -type f 2>/dev/null

This command lists all SUID files on the system. Scrutinize this list for binaries that shouldn’t have SUID set, or for custom binaries that might have vulnerabilities.

Fix: Remove the SUID bit from non-essential binaries.

chmod u-s /path/to/exploitable/binary

This command ensures the binary runs with the user’s privileges, not the owner’s.

Why it works: It removes the ability for an unprivileged user to execute a program with elevated privileges by leveraging its SUID bit.

World-Writable Files and Directories

If a user can write to a file that is later executed or used by a privileged process, they can inject malicious code. This is particularly dangerous for scripts or configuration files.

Diagnosis:

find / -xdev -type f -perm -0002 -print
find / -xdev -type d -perm -0002 -print

These commands find all world-writable files and directories, respectively. Focus on system-critical locations like /etc, /usr/local/bin, or directories where sensitive applications store data.

Fix: Remove world-writability.

chmod o-w /path/to/world_writable_file
chmod o-w /path/to/world_writable_directory

This prevents any user on the system from modifying these files or directories.

Why it works: It restricts modification access to only the file’s owner and group, removing the attacker’s ability to alter its contents.

Insecure Cron Jobs

Cron jobs running with elevated privileges that execute scripts with weak permissions, or that can be manipulated by less privileged users, are a prime target. This includes jobs that:

  • Execute scripts in world-writable directories.
  • Execute scripts where the script itself is writable by the user running the cron job.
  • Use relative paths or lack full path specification for commands, allowing PATH variable manipulation.

Diagnosis: Examine /etc/crontab and files in /etc/cron.d/. Check permissions of scripts being executed and the directories they reside in.

ls -l /etc/crontab
ls -l /etc/cron.d/*
ls -l /path/to/script.sh
ls -ld /path/to/script_directory

Fix: Ensure cron scripts are owned by root and not writable by other users. Use absolute paths for all commands and files within cron scripts.

chown root:root /path/to/script.sh
chmod 644 /path/to/script.sh
# Example script fix:
# Instead of 'tar', use '/bin/tar'

This ensures that only root can modify the script and that the script executes with predictable, absolute paths.

Why it works: It hardens the execution environment of privileged tasks, preventing unauthorized modification or execution by lower-privileged users.

Unpatched Kernel Vulnerabilities

The Linux kernel itself can have vulnerabilities that allow for privilege escalation. These are often the most dangerous and can grant immediate root access.

Diagnosis: Check the kernel version.

uname -r

Cross-reference this version with known kernel exploits on sites like Exploit-DB.

Fix: Keep the kernel updated.

sudo apt update && sudo apt upgrade -y # For Debian/Ubuntu
sudo yum update -y # For RHEL/CentOS/Fedora

Regularly apply security patches to the operating system, including kernel updates.

Why it works: It replaces the vulnerable kernel code with a patched version that fixes the exploit.

Weak File Permissions on Sensitive Files

Files like /etc/shadow (password hashes), /etc/sudoers, or SSH private keys, if not properly secured, can be read or modified by attackers.

Diagnosis: Check permissions of critical system files.

ls -l /etc/shadow
ls -l /etc/sudoers
ls -la ~attacker/.ssh/id_rsa

Fix: Ensure correct ownership and restrictive permissions.

chown root:root /etc/shadow
chmod 0640 /etc/shadow
chown root:root /etc/sudoers
chmod 0440 /etc/sudoers
chown attacker:attacker ~attacker/.ssh/id_rsa
chmod 0600 ~attacker/.ssh/id_rsa

These commands set ownership and permissions to the most restrictive levels that allow necessary system operations.

Why it works: It enforces the principle of least privilege, ensuring only authorized users or processes can access sensitive data.

Misconfigured sudo Rules

The sudo command allows users to execute commands as other users (typically root). Misconfigurations, such as allowing a user to run a specific command that can then be used to spawn a shell, are common.

Diagnosis:

sudo -l

This command lists the commands a user is allowed to run via sudo. Look for commands that can execute other commands or manipulate files.

Fix: Restrict sudo rules to only necessary commands. Avoid rules that allow arbitrary command execution or file manipulation. Example in /etc/sudoers (use visudo to edit):

# Instead of this:
# www-data ALL=(ALL) /usr/bin/vim
# Do this:
www-data ALL=(ALL) /usr/bin/vim /var/www/html/webapp/config.php

This limits vim to only editing a specific configuration file, preventing its use for shell escapes.

Why it works: It narrows the scope of commands that can be elevated, reducing the attack surface for unintended shell access.

After fixing these, the next hurdle you’ll likely encounter is a system that’s been hardened against basic privilege escalation, forcing you to look for more advanced techniques like exploiting specific application vulnerabilities or race conditions.

Want structured learning?

Take the full Cdk course →