TSG CTF 2025 - SafePickle
Challenge
特定の pickle オペコードが禁止された環境。
import pickleimport io
BANNED_OPCODES = { pickle.REDUCE, # R pickle.GLOBAL, # c pickle.INST, # i pickle.OBJ, # o pickle.BUILD, # b}
data = input()pickled = bytes.fromhex(data)
# バイトコードチェックfor byte in pickled: if byte in BANNED_OPCODES: print("Banned opcode!") exit()
result = pickle.loads(pickled)Solution
使用可能なオペコード
禁止されていないオペコードを確認:
| オペコード | 記号 | 機能 |
|---|---|---|
| PROTO | \x80 | プロトコルバージョン |
| FRAME | \x95 | フレーム |
| MARK | ( | スタックマーク |
| STOP | . | 終了 |
| PUT | p | メモに保存 |
| GET | g | メモから取得 |
| STRING | S | 文字列 |
| TUPLE | t | タプル |
| DICT | d | 辞書 |
BUILD なしでの属性設定
BUILD (b) が禁止されているが、SETITEM や他の方法で属性を設定:
# SETITEM を使用pickle.SETITEM # s代替のコード実行方法
# __reduce__ の代わりに# STACK_GLOBAL (Python 3.7+) を使用pickle.STACK_GLOBAL # \x93Technical Details
pickle プロトコル
# プロトコルバージョン# 0-2: ASCII ベース# 3-5: バイナリベース
# GLOBAL vs STACK_GLOBAL# GLOBAL: cmodule\nname\n# STACK_GLOBAL: (文字列をスタックから取得) \x93セキュリティバイパス
# REDUCE なしでのコード実行# - STACK_GLOBAL + TUPLE + NEWOBJ# - INST (禁止されていない場合)攻撃ペイロードの構築
import pickletools
payload = b'\x80\x04\x95...' # 手動構築pickletools.dis(payload) # デバッグAlternative Solutions
別解1: NEWOBJ_EX
# Python 3.6+ の新しいオペコードpickle.NEWOBJ_EX # \x92別解2: プロトコル 0/1 のオペコード
古いプロトコルのオペコードは禁止リストにない場合がある。
Flag
TSGCTF{...}
References
- TSG CTF 2025 Official
- https://jia.je/ctf-writeups/misc/pyjail.html
- Python pickle documentation