jailCTF 2025 - primal
Challenge
全ての識別子が素数長でなければならない pyjail。
import reimport sympy
code = input()
# 200文字以内if len(code) > 200: exit()
# 'eta' を禁止if 'eta' in code.lower(): exit()
# 非ASCII文字を禁止if not code.isascii(): exit()
# 全ての識別子が素数長かチェックfor match in re.finditer(r'[a-zA-Z_][a-zA-Z0-9_]*', code): word = match.group() if not sympy.isprime(len(word)): print(f"'{word}' has non-prime length {len(word)}") exit()
eval(code, {'__builtins__': {}})Solution
素数長の識別子
素数: 2, 3, 5, 7, 11, 13, …
| 長さ | 例 |
|---|---|
| 2 | id, os, __ |
| 3 | str, int, len |
| 5 | class, print |
| 7 | __class__ ではない (9文字) |
問題: __class__ は9文字 (非素数)
__class__ (9文字) は使えない。代替手段が必要:
# type() は4文字 (非素数)# __class__ は9文字 (非素数)解決策: getattr の活用
# getattr は7文字 (素数)getattr((), '__class__') # ただし '__class__' は文字列文字列の構築
# chr は3文字 (素数)# 文字列として渡すため、長さ制限を回避chr(95) + chr(95) + ...Technical Details
素数チェック
import sympy
sympy.isprime(2) # Truesympy.isprime(3) # Truesympy.isprime(4) # Falsesympy.isprime(5) # Truesympy.isprime(9) # False素数長の組み込み名
| 名前 | 長さ | 素数? |
|---|---|---|
id | 2 | Yes |
str | 3 | Yes |
eval | 4 | No |
print | 5 | Yes |
getattr | 7 | Yes |
__class__ | 9 | No |
__bases__ | 9 | No |
’eta’ 禁止の影響
# getattr に 'eta' が含まれる!# g-eta-ttr# これも使えないAlternative Solutions
別解1: 数値演算のみ
# 素数長の変数名と数値演算ab = 123 # 2文字 (素数)別解2: lambda
# lambda は6文字 (非素数)# 使用不可Flag
jail{...}
References
- jailCTF 2025 Official
- https://jia.je/ctf-writeups/misc/pyjail/jailctf-2025-primal.html