← Back to sandbox
Security - Data Handling Advanced 4 possible tests

Insecure Deserialization

A session endpoint that stores user data in a pickled cookie and deserializes it on every request without validation. A crafted cookie value with a __reduce__ method executes arbitrary OS commands inside the server process. Find the payloads that trigger code execution, and verify the JSON endpoint handles the same input safely.

What is Insecure Deserialization?

Insecure deserialization occurs when user-controlled data is passed to a deserializer without validation. Python's pickle module is particularly dangerous - a pickled object can embed a __reduce__ method that calls any importable function with any arguments when deserialized. If a server calls pickle.loads() on attacker-supplied data, the attacker controls what code runs on the server. JSON does not have this property - json.loads() can only produce primitive values and collections, never invoke callables.

What is hidden here

True Negative Benign pickle of {"name": "Alice", "role": "viewer"} - deserialized correctly, data returned
Bug Found Pickle with os.system("id") via __reduce__ - REDUCE + STACK_GLOBAL triggers RCE, command output simulated
Bug Found Pickle with subprocess.check_output(["cat", "/etc/passwd"]) - file contents leaked via RCE
True Positive Any input on the JSON endpoint - safely parsed or rejected, no code executed

Endpoint A - Unsafe Deserialization

This endpoint reads the session_data cookie and calls pickle.loads() directly. Paste a base64-encoded pickle payload or use a quick-test button.

✗ Deserializes with pickle.loads()
Quick tests
shell@webapp:~$ (simulated RCE output)

    
deserialized data

    

Endpoint B - Safe Deserialization

This endpoint parses session data with json.loads(). Try submitting valid JSON to see it parsed safely, or paste a pickle payload to see it rejected without executing any code.

✓ Parses with json.loads()
Quick tests
parsed JSON

    

  • Use the Benign dict button on Endpoint A - a safe pickle payload deserializes to a plain dict with no code execution (true negative)
  • Use the os.system("id") button on Endpoint A - the STACK_GLOBAL + REDUCE opcodes import posix.system and invoke it; the server process runs the command (bug found)
  • Use the subprocess read /etc/passwd button on Endpoint A - same RCE technique with subprocess.check_output to read a sensitive file (bug found)
  • Use the Valid JSON button on Endpoint B - json.loads() parses it safely and returns plain data with no code execution (true positive)
  • Use the Pickle payload button on Endpoint B - the base64 pickle bytes are not valid JSON; json.loads() raises JSONDecodeError and rejects it without executing anything (true positive)