- 实验所属系列:二进制安全
- 实验对象:本科/专科信息安全专业
- 相关课程及专业:计算机网络
- 实验时数(学分):2学时
- 实验类别:实践实验类
通过实验掌握Signal机制的原理,以及掌握利用signal机制实现srop的攻击方法。
Signal机制
signal 机制是类 unix 系统中进程之间相互传递信息的一种方法。也被称之为软中断信号,或者软中断。进程之间可以通过系统调用kill来发送软中断信号。信号机制的流程如下:
-
内核会向某个进程发送一个 signal,该进程被挂起并进入内核态
-
内核为该进程保存相应的上下文,然后跳转到用户态中注册好的 signal handler 中处理相应的 signal
-
signal handler 执行完毕返回内核态
-
内核为该进程恢复之前保存的上下文,最终恢复进程的执行
内核保存上下文时,主要是将所有寄存器入栈,以及将signal和指向 sigreturn 系统调用的地址入栈。此时的栈结构如下图所示:需要注意的是,这一部分是在用户进程的地址空间的。
我们称ucontext以及siginfo这一段为Signal Frame。然后跳转到注册的signal handler中处理相应的 signal。当signal handler执行完之后,就会返回到sigreturn系统调用中。sigreturn 系统调用会利用signal frame将所有寄存器恢复到之前的状态,程序继续执行。
对于 signal Frame 来说,会因为架构的不同而有所区别,这里分别列出 x86 以及 x64 的 sigcontext结构:
x86 sigcontext:
struct sigcontext
{
unsigned short gs, __gsh;
unsigned short fs, __fsh;
unsigned short es, __esh;
unsigned short ds, __dsh;
unsigned long edi;
unsigned long esi;
unsigned long ebp;
unsigned long esp;
unsigned long ebx;
unsigned long edx;
unsigned long ecx;
unsigned long eax;
unsigned long trapno;
unsigned long err;
unsigned long eip;
unsigned short cs, __csh;
unsigned long eflags;
unsigned long esp_at_signal;
unsigned short ss, __ssh;
struct _fpstate * fpstate;
unsigned long oldmask;
unsigned long cr2;
};
x64 sigcontext:
struct sigcontext
{
__uint64_t r8;
__uint64_t r9;
__uint64_t r10;
__uint64_t r11;
__uint64_t r12;
__uint64_t r13;
__uint64_t r14;
__uint64_t r15;
__uint64_t rdi;
__uint64_t rsi;
__uint64_t rbp;
__uint64_t rbx;
__uint64_t rdx;
__uint64_t rax;
__uint64_t rcx;
__uint64_t rsp;
__uint64_t rip;
__uint64_t eflags;
unsigned short cs;
unsigned short gs;
unsigned short fs;
unsigned short __pad0;
__uint64_t err;
__uint64_t trapno;
__uint64_t oldmask;
__uint64_t cr2;
__extension__ union
{
struct _fpstate * fpstate;
__uint64_t __fpstate_word;
};
__uint64_t __reserved1 [8];
};
攻击原理
系统在执行 sigreturn
系统调用的时候,不会对 signal frame 做检查,它不知道当前的这个 frame 是不是之前保存的那个 frame。由于 sigreturn
会从用户栈上恢复恢复所有寄存器的值,而用户栈是保存在用户进程的地址空间中的,是用户进程可读写的。如果攻击者控制了栈,也就控制了所有寄存器的值,而这一切只需要一个 gadget:syscall
。
当系统执行完 sigreturn 系统调用之后,会执行一系列的 pop 指令以便于恢复相应寄存器的值,当执行到 rip 时,就会将程序执行流指向 syscall 地址,根据相应寄存器的值,此时,就可以get shell。
服务器:kali 2019 x64
辅助工具: pwndbg, pwntools
实验工具:http://tools.yijinglab.com/tools/ciscn_srop.tar.gz