介绍
ret2dir 是哥伦比亚大学网络安全实验室在 2014 年提出的一种辅助攻击手法,主要用来绕过 smep、smap、pxn 等用户空间与内核空间隔离的防护手段,
原论文见此处: ret2dir原文论文
ret2dir原理
在开启了smep/smap后,内核空间到用户空间的直接访问被禁止,也就是传统的ret2usr失效了,如下图(图片来源于论文)。

为饶过这种限制,原文作者找到了一段区域,可以隐式的访问到用户空间数据。在内核空间就能访问到用户空间的数据,该区域也被称为phsymap,是很大一段的虚拟内存,映射了整个物理内存。
这片区域叫做:direct mapping of all physical memory

这个映射区其实就是内核空间会与物理地址空间进行线性的映射,我们可以在这段区域直接访问到物理地址对应的内容。

下图就是在论文中对ret2dir这种攻击的示例图,不和ret2usr一样,指针不是指向用户空间,而是指向直接映射区域,在用户空间构造的payload也会映射到物理地址,所以只要在phsymap区域找到用户空间的payload就能执行。在高版本内核中 direct mapping area没有可执行权限需要通过ROP利用。

因此若能获得指向存在payload的用户空间对应的物理地址在phsymap位置,就能够直接执行用户空间的payload
- 通过读取
/proc/pid/pagemap可获取映射地址,该文件中存放了物理地址与虚拟地址的映射关系,可是该文件需要root权限才能读取. - 利用
堆喷技术往phsymap区域填充大量payload,提高命中概率。

ret2dir手法总结:
- 利用mmap或者堆喷技术在用户空间喷射大量相同的payload
- 随机挑选direct mapping area上的地址,大概率命中写入的payload
pt_regs
系统调用:用户态布置好相应的参数后执行 syscall 进入到内核中的 entry_SYSCALL_64,随后通过系统调用表跳转到对应的函数
entry_SYSCALL_64 :当程序进入到内核态时,该函数会将所有的寄存器压入内核栈上,形成一个 pt_regs 结构体,该结构体实质上位于内核栈底.
entry_SYSCALL_64定义在arch/x86/entry/entry_64.S

pt_regs定义在arch/x86/include/asm/ptrace.h
struct pt_regs {
/*
* C ABI says these regs are callee-preserved. They aren't saved on kernel entry
* unless syscall needs a complete, fully filled "struct pt_regs".
*/
unsigned long r15;
unsigned long r14;
unsigned long r13;
unsigned long r12;
unsigned long rbp;
unsigned long rbx;
/* These regs are callee-clobbered. Always saved on kernel entry. */
unsigned long r11;
unsigned long r10;
unsigned long r9;
unsigned long r8;
unsigned long rax;
unsigned long rcx;
unsigned long rdx;
unsigned long rsi;
unsigned long rdi;
/*
* On syscall entry, this is syscall#. On CPU exception, this is error code.
* On hw interrupt, it's IRQ number:
*/
unsigned long orig_rax;
/* Return frame for iretq */
unsigned long rip;
unsigned long cs;
unsigned long eflags;
unsigned long rsp;
unsigned long ss;
/* top of stack page */
};
内核栈只有一个页面的大小,而pt_regs固定在内核栈底部,当可以劫持到rip的时候,需要通过rop来控制rsp可以使用到pt_regs来构造ROP。
注意:
-
在内核版本
5.13之前pt_regs 结构体和栈顶的偏移值基本是固定的(因为内核栈只有一个 page),通常可以借助add rsp, val ; ret 的 gadget劫持一处函数指针就能实现进一步ROP利用。 -
但是,在
5.13 及之后的do_syscall_64函数入口处,新增了一行
add_random_kstack_offset();,来源于 2021 年 的一个 commit,效果是在栈底的pt_regs
之上放了一个不超过 0x3FF 的偏移,使得利用的稳定性大幅下降。
模板:
__asm__(
"mov r15, 0xbeefdead;"
"mov r14, 0x11111111;"
"mov r13, 0x22222222;"
"mov r12, 0x33333333;"
"mov rbp, 0x44444444;"
"mov rbx, 0x55555555;"
"mov r11, 0x66666666;"
"mov r10, 0x77777777;"
"mov r9, 0x88888888;"
"mov r8, 0x99999999;"
"xor rax, rax;"
"mov rcx, 0xaaaaaaaa;"
"mov rdx, 8;"
"mov rsi, rsp;"
"mov rdi, seq_fd;" // 这里假定通过 seq_operations->stat 来触发
"syscall"
);
系统调用

最低0.47元/天 解锁文章
2129

被折叠的 条评论
为什么被折叠?



