ScriptCTF 2025 - Modulo
Challenge
極めて厳しい文字制限を持つ pyjail。1800チーム中20チームのみ解答。
import re
code = input()
# ホワイトリスト: 大文字 A-Z、小文字 'c' のみ、括弧、%+:*.,[]if not re.match(r'^[A-Zc()+%:*.\[\],]+$', code): print("Invalid!") exit()
exec(code, {'__builtins__': {}})制約:
- 大文字 A-Z のみ (小文字は ‘c’ のみ)
- 数字なし
- 限られた記号:
(),%,+,:,*,.,[],,
Solution
%c フォーマットによる文字構築
"%c" % ASCII_CODE で任意の文字を生成:
"%c" % 97 # 'a'"%c" % 111 # 'o'数値の生成
数字が使えないため、別の方法で数値を生成:
# True は 1、加算で数値を作る# ただし小文字が使えないため別のアプローチが必要変数を使った数値構築
1つの変数に数値を蓄積:
A = (A + A) # 2倍A = (A + A + A) # 3倍26,578バイトのペイロード
最終的なペイロードは約26KB:
# 大量の加算で必要な ASCII コードを構築# %c で文字に変換# 文字を結合してコマンドを構築# exec で実行Technical Details
%c フォーマット
# 単一の整数を文字に変換"%c" % 65 # 'A'"%c" % 97 # 'a'
# 複数の変換"%c%c%c" % (111, 115, 46) # 'os.'数値生成の代替手段
| 方法 | 例 |
|---|---|
len() | len("A") → 1 |
ord() | ord("A") → 65 |
True + True | 2 |
[].count() | 0 |
文字制限下での構築
# 'A' から始めて数値を構築A = len(C) # C が定義されていればA = A + A # 2A = A + A # 4# ... 繰り返しAlternative Solutions
別解1: eval の再構築
# __builtins__ から eval を取得するチェーンを構築別解2: Jinja SSTI ガジェット
# Object サブクラスから os にアクセスFlag
scriptctf{...}
References
- ScriptCTF 2025 Official
- http://squar3.blog/ScriptCTF-2025-Writeups/