SROP

感觉对SROP的知识还不够熟练,单独再学习一下。相关截图来自CTFWIKI

signal机制

signal机制是类unix系统中进程之间相互传递信息的一种方法。一般也称它为软中断(信号)

image-20241212142937980

1、内核向某个进程发送signal机制,该进程就会被暂时挂起并进入内核态。

2、内核会为该进程保存相应的上下文,主要是将所有寄存器压入栈中,以及压入 signal 信息,以及指向 sigreturn 的系统调用地址。此时栈中的景象是这样的:

image-20241212143214754

这里的ucontext和signfo就是我们做题时修改的Signal Frame

需要注意的是,这一部分是在用户进程的地址空间的。之后会跳转到注册过的 signal handler 中处理相应的 signal。因此,当 signal handler 执行完之后,就会执行 sigreturn 代码。

这一段感觉就和普通的栈差不多,在执行完毕之后有一个return,结构上很像,不难理解。

不同的架构下形成的signal frame是不同的

x86

image-20241212143625940

x64

image-20241212143715969

3、signal handler 返回后,内核为执行 sigreturn 系统调用,为该进程恢复之前保存的上下文,其中包括将所有压入的寄存器,重新 pop 回对应的寄存器,最后恢复进程的执行。其中,32 位的 sigreturn 的调用号为 119(0x77),64 位的系统调用号为 **15(0xf)**。

这里的15很重要,或者说如果在题目中看到gadget的功能是赋值寄存器为15就可以断定是考的SROP。

攻击原理

通过刚才的解释,我们能够找到一点其中不安全的地方。我们刚刚说了,当signal执行的时候会将进程信息打包进内核,但也仅仅只是打包而已,没有加任何的保护或者上锁机制,我们是否可以利用这一缺陷对打包好的signal frame进行修改,从而改变其功能?

由于打包好的内容存入的是用户地址,不是内核,我们是有读写权限的,那么我们刚刚的猜想就成立了。说到这里,其实,SROP 的基本利用原理也就出现了。

获取 shell

首先,我们假设攻击者可以控制用户进程的栈,那么它就可以伪造一个 Signal Frame,如下图所示,这里以 64 位为例子,给出 Signal Frame 更加详细的信息。

signal2-stack

当系统执行完 sigreturn 系统调用之后,会执行一系列的 pop 指令以便于恢复相应寄存器的值,当执行到 rip 时,就会将程序执行流指向 syscall 地址,根据相应寄存器的值,此时,便会得到一个 shell。

system call chains

上面的例子一般都是用于直接可以获得shell的情况,如果我们需要执行类似rop的函数链表,则只需要

修改两处

1、控制栈指针

2、把把原来 rip 指向的syscall gadget 换成syscall; ret gadget

如下图所示 ,这样当每次 syscall 返回的时候,栈指针都会指向下一个 Signal Frame。因此就可以执行一系列的 sigreturn 函数调用。

signal2-stack

后续

要打SROP我们必须有以下条件

  • 可以通过栈溢出来控制栈的内容

  • 需要知道相应的地址

    • “/bin/sh”
    • Signal Frame
    • syscall
    • sigreturn
  • 需要有够大的空间来塞下整个 sigal frame

利用工具

幸运的是,现在pwntools中已经有了我们更加便于利用的攻击工具,不再需要我们去大费周章的去考虑底层的内容了。

多的就不讲了,我们来看一下pwntools中是如何简化的吧,这里我们直接截取CTFwiki例题中构造signal frame的一段来看

image-20241212145443921

其实只要是栈题都和寄存器离不开关系,主要还是利用前面的弊端修改寄存器的值使其能够执行我们想要的函数功能。可能主要会有疑问的就是rsp指向哪里,就是你构造rop chain中的下一个signal frame的起始地址。