jailCTF 2025 - auniquechallenge
Challenge
各識別子の各文字は1回のみ使用可能。
import refrom collections import Counter
code = input()
# 各識別子を抽出identifiers = re.findall(r'[a-zA-Z_][a-zA-Z0-9_]*', code)
# 各文字が1回のみかチェックfor ident in identifiers: counter = Counter(ident.lower()) for char, count in counter.items(): if count > 1: print(f"Character '{char}' appears {count} times in '{ident}'") exit()
eval(code, {'__builtins__': {}})Solution
NFKC 正規化による文字の等価性
Python の識別子は NFKC 正規化される。異なる Unicode 文字が同じ ASCII 文字として認識される:
# 全角 'a' と半角 'a' は同じ識別子として動作a = 1print(a) # 1 が出力される同じ文字の異なる表現
| ASCII | 全角 | 上付き | 下付き | その他 |
|---|---|---|---|---|
| a | a | ᵃ | ₐ | 𝐚 |
| e | e | ᵉ | - | 𝐞 |
| s | s | ˢ | - | 𝐬 |
完全なペイロード
# __class__ の各文字を異なるUnicode表現で__clasˢ__ # c, l, a(全角), s(全角), s(上付き)Technical Details
NFKC 正規化
import unicodedata
# 正規化の確認unicodedata.normalize('NFKC', 'a') # 'a'unicodedata.normalize('NFKC', 'ᵃ') # 'a'unicodedata.normalize('NFKC', '𝐚') # 'a'
# すべて同じ識別子として動作a = 1print(a) # 1利用可能な等価文字
# 'class' を重複なしで'c' - 通常'l' - 通常'a' - 通常 または 'a' または 'ᵃ''s' - 通常 または 's' または 'ˢ''s' - (2つ目) 別の表現を使用Python の識別子処理
# PEP 3131: Python での識別子処理# 1. ソースコードを読む# 2. NFKC 正規化を適用# 3. 正規化後の文字列を識別子として使用Alternative Solutions
別解1: 数学記号
# 数学太字、斜体なども NFKC 正規化される𝐚𝐛𝐜 # abc として認識別解2: 囲み文字
# 一部の囲み文字も正規化されるFlag
jail{...}
References
- jailCTF 2025 Official
- PEP 3131 - Supporting Non-ASCII Identifiers
- Unicode NFKC Normalization