pyjail wiki

jailCTF 2025 - primal

Challenge

全ての識別子が素数長でなければならない pyjail。

import re
import 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, …

長さ
2id, os, __
3str, int, len
5class, 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) # True
sympy.isprime(3) # True
sympy.isprime(4) # False
sympy.isprime(5) # True
sympy.isprime(9) # False

素数長の組み込み名

名前長さ素数?
id2Yes
str3Yes
eval4No
print5Yes
getattr7Yes
__class__9No
__bases__9No

’eta’ 禁止の影響

# getattr に 'eta' が含まれる!
# g-eta-ttr
# これも使えない

Alternative Solutions

別解1: 数値演算のみ

# 素数長の変数名と数値演算
ab = 123 # 2文字 (素数)

別解2: lambda

# lambda は6文字 (非素数)
# 使用不可

Flag

jail{...}

References