pyjail wiki

CrewCTF 2025 - pyfuck

Challenge

特定の builtins のみが利用可能で、文字制限もある pyjail。

ALLOWED_BUILTINS = {
'next', 'chr', 'ord', 'max', 'min', 'bin', 'int',
'len', 'str', 'set', 'hex', 'print', 'range', 'open'
}
code = input()
# 制約:
# - アルファベットと括弧と + のみ
# - + は最大12個
# - 340文字以内
# - 'print' をコマンドに含めない
if not re.match(r'^[a-zA-Z()+]+$', code):
exit()
if code.count('+') > 12:
exit()
if len(code) > 340:
exit()
if 'print' in code:
exit()
restricted_builtins = {k: __builtins__[k] for k in ALLOWED_BUILTINS}
exec(code, {'__builtins__': restricted_builtins})

Solution

open でフラグを読む

open が使えるため、ファイル読み取りは可能:

open(chr(70)+chr(108)+chr(97)+chr(103)+chr(46)+chr(116)+chr(120)+chr(116))
# 'Flag.txt' を開く

chr() での文字列構築

# 'Flag.txt' を構築
chr(70)+chr(108)+chr(97)+chr(103)+chr(46)+chr(116)+chr(120)+chr(116)

+ の制限への対応

12個の + 制限があるため、効率的に文字を構築:

# 文字列結合で + を使用
# chr() 呼び出しで + を使用

next() と range() の活用

# next(iter(...)) でインデックスアクセスを代替
next(open(...)) # 最初の行を読む

Technical Details

利用可能な関数

関数用途
chr()数値 → 文字
ord()文字 → 数値
open()ファイル読み取り
int()文字列 → 数値
len()長さ取得
next()イテレータから取得
range()数列生成
# print を使わずに出力
# open で /dev/tty に書き込み
open(chr(47)+chr(100)+chr(101)+chr(118)+chr(47)+chr(116)+chr(116)+chr(121), chr(119)).write(flag)

文字数の最適化

# 変数に中間値を保存
a = chr(111) # 'o'
b = chr(115) # 's'
# 再利用で + を節約

Alternative Solutions

別解1: hex() と int() の組み合わせ

# hex() で16進文字列を作り、int() で戻す

別解2: set() と str() の活用

# set の文字列表現から文字を抽出

Flag

crew{...}

References