前言
SROP(Sigreturn Oriented Programming) 于 2014 年被 Vrije Universiteit Amsterdam 的 Erik Bosman 提出,其相关研究Framing Signals — A Return to Portable Shellcode 其中相关的 paper 以及如下:
paper
机制详解
signal 机制是类 unix 系统中进程之间相互传递信息的一种方法。一般,我们也称其为软中断信号,或者软中断。比如说,进程之间可以通过系统调用 kill 来发送软中断信号。一般来说,信号机制常见的步骤如下图所示:

- 内核向某个进程发送 signal 机制,该进程会被暂时挂起,进入内核态。
- 内核会为该进程保存相应的上下文,主要是将所有寄存器压入栈中,以及压入 signal 信息,以及指向
sigreturn的系统调用地址。此时栈的结构如下图所示,我们称ucontext以及siginfo这一段为 Signal Frame。需要注意的是,这一部分是在用户进程的地址空间的。之后会跳转到注册过的 signal handler 中处理相应的 signal。因此,当 signal handler 执行完之后,就会执行sigreturn代码。 signal handler返回后,内核为执行sigreturn系统调用,为该进程恢复之前保存的上下文,其中包括将所有压入的寄存器,重新 pop 回对应的寄存器,最后恢复进程的执行。其中,32 位的sigreturn的调用号为 77,64 位的系统调用号为 15。

上述谈到的从栈中POP出寄存器内容的过程由 setcontext 函数实现,如下图所示:

我们可以看到,从指令mov rsp, [rdi+0A0h]开始,便是一连串对于寄存器的恢复操作。而且结构由Signal Frame结构体实现,以下是结构源码
X86
1 | struct sigcontext |
X64
1 | struct _fpstate |
攻击方式
直接getshell
示意图

我们可以直接在栈上伪造Signal Frame,利用syscall(0xF)来触发对于伪造寄存器的恢复,在setcontext 执行完毕后,便会getshell(或利用栈转移到其他地址也可以,但无论怎样都要保证在syscall时,rsp需指向Fake Frame 的开头)
SROP
在上面直接getshell的基础上,我们可以自然的想到,通过不断伪造sigframe可以实现类似ROP的效果,只需要将其中rsp控制到下一个fakeframe的开头,rip加上ret即可。
示意图

栈转移
由于其可以轻易的控制几乎所有寄存器的值,栈转移这样的操作也可以轻松实现
堆中直接利用setcontext
在面对堆题目时,我们很难直接在栈上构造内容并且控制rsp指向frame开头。此时可以直接通过劫持hook为setcontext+53 处(mov rsp, [rdi+0A0h]),直接触发对于寄存器的一系列pop操作。且由于free时,rip指向chunk的mem域,那么我们只需要在将要free的chunk里写上Fake Frame,并合理控制与rip的距离即可。
例题
平台题目SROP、 ciscn 2021 silverwolf