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 禁止のバイパス
# 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
- CrewCTF 2025 Official
- https://jia.je/ctf-writeups/misc/pyjail/crewctf-2025-pyfuck.html