Glibc高版本堆利用方法总结
截止到目前,主要总结在
2.35~2.37
之间仍然残存的堆利用手法。注意,本文的撰写时间为2023-03-01
。
- 1-攻击向量
- 2-参考
可以在Bilibili上观看视频进行学习:
或者在Youtube上观看视频进行学习:
进入到glibc-2.31
之后,很多原有的堆利用方法就失效,因此glibc
给堆分配机制陆陆续续打上了很多patch
,目前来看,与堆利用有关的patch
有:
tcachebin
堆指针异或加密(glibc-2.32
引入)tcahebin
链的数量检查(glibc-2.33
引入)fastbin
堆指针异或加密(glibc-2.32
引入)- 堆内存对齐检查(
glibc-2.32
引入) - 移除
__malloc_hook
和__free_hook
(glibc-2.34
引入) - 引入
tcache_key
作为tcache
的key
检查(glibc-2.34
引入) __malloc_assert
移除掉IO
处理函数(glibc-2.36
引入)- 移除
__malloc_assert
函数(glibc-2.37
引入) - 将
global_max_fast
的数据类型修改为uint8_t
(glibc-2.37
引入)
根据目前已有的patch
,结合之前已有的堆利用方法,总结2.35
版本之后的攻击向量与攻击面,给出针对这些攻击面的攻击手段,并对某些攻击面的利用方法进行思考和拓展。如有错误或遗漏,欢迎批评指正。
本文所提到的house of
系列的利用手段,可以参考我之前写的博客Glibc堆利用之house of系列总结 - roderick - record and learn! (roderickchan.cn)。
1-攻击向量
1-1 tcachebin
事实上,在泄露地址的基础上劫持tcachebin
的next
,依然可以任意地址分配。
1-1-1 绕过指针保护
绕过指针异或的保护方法主要有两种:
-
当
tcachebin
链表中只有一个chunk
的时候,此时chunk->next << 12
即可得到堆地址。 -
当
tcachebin
链表的前两个chunk
的地址相差不是很大的时候,可以用下面的公式计算:1 2 3 4 5 6 7 8
def calc_heap(addr): s = hex(addr)[2:] s = [int(x, base=16) for x in s] res = s.copy() for i in range(9): res[3+i] ^= res[i] res = "".join([hex(x)[2:] for x in res]) return int16_ex(res)
这里的
addr
就是头部chunk
的加密后的next
,只泄露一次就能还原出来。
1-1-2 劫持tcache_ptheread_struct
这个结构体的重要性不言而喻,劫持了这个结构体可以控制tcachebin
的分配。一般可以用tcachebin stash unlink
或者largebin attack
劫持。
1-1-3 修改线程tcache变量
在tls
区域,有一个线程变量tcache
,如果能用largebin attack
修改tcache
变量,也可以控制tcache
的分配。
1-1-4 修改mp_结构体
关注与tcache
有关的几个变量:
|
|
修改掉tcache_bins
可以把很大的chunk
用tcachebin
管理;修改掉tcache_count
可以控制链表的chunk
的数量。tcache_max_bytes
目前没啥用,tcache_unsorted_limit
可以影响unsortedbin
链表的遍历过程。
1-2 fastbin
1-2-1 house of corrosion
使用的范围只能在2.35~2.37
,进入到2.37
之后,global_max_fast
的类型被修改为int8_t
,使用该技巧可以控制的地址范围大大缩小。
有关house of corrosion
的技巧可以参考House-of-Corrosion 一种新的堆利用技巧 - 先知社区 (aliyun.com)。
1-2-2 tcache reverse into fastbin
目前检查了对齐,所以要注意控制的地址要是0x?0
结尾,否则报错。利用效果是任意地址写一个libc
地址。
虽然0x?0
写的是加密后的堆地址,但是0x?8
会写上tcache_key
,这也是可以利用的点。而且,在写上地址后,还能分配到该处。其利用过程如下:
- 分配
13
个fastbin
范围内的chunk
,假设大小为A
- 全部释放这
13
个chunk
- 分配
7
个,把tcachebin[A]
耗尽 - 把
fastbin
最后一个chunk
的fd
修改为addr
- 调用一次
malloc(A)
即可触发tcache reverse into fastbin
,可以分配到addr
,也能给addr/addr+8
处写上地址/数
1-3 smallbin
1-3-1 house of lore
很显然,house of lore
依然可以使用,但是house of lore
使用的时候,一方面是需要满足victim->fd->bk == victim
;另一方面,需要绕过下面讲的tcache stash unlink
流程。除此之外,还需要注意内存对齐的问题。
1-3-2 tcache stash unlink attack
在我之前的博客中,分析house of rust
的时候总结过这个利用手法。
第一个技巧叫 tcachebin stash unlinking
,下面称之为 TSU
技巧:
tcachebin[A]
为空smallbin[A]
有8
个- 修改第
8
个smallbin chunk
的bk
为addr
- 分配
malloc(A)
的时候,addr+0x10
会被写一个libc
地址
第二个技巧叫 tcachebin stash unlinking+
,下面称之为 TSU+
技巧:
tcachebin[A]
为空smallbin[A]
有8
个- 修改第
7
个smallbin chunk
的bk
为addr
,还要保证addr+0x18
是一个合法可写的地址 - 分配
malloc(A)
的时候,addr
会被链入到tcachebin
,也就是可以分配到addr
处
可以看到,和fastbin reverse into tcache
的攻击方法很类似,但是得到的效果不一样。TSU
可以在任意地址写libc
地址,而TSU+
除了可以写libc
地址,还能再任意地址分配。
1-4 largebin
目前能用的largebin attack
只能使用下面这个分支:
|
|
效果是可以任意地址写堆地址。
largebin attack
往往会与其他攻击方法结合起来,因为其写地址的能力,可以修改变量,所以常常用来构造写原语。
1-4-1 house of husk
house of husk
方法仍然可以利用,需要找到一个格式化字符串的场景,且打house of husk
的时候,至少需要两次格式化字符串。
1-4-2 libc/ld上的变量
libc/ld
的地址空间上关键变量非常多,比如_IO_list_all
,pointer_guard
、tcache
等等。具体的方法会在相关的篇幅里面进行详细说明和补充。
1-5 IO_FILE
1-5-1 house of kiwi
在这个commit里面将__malloc_assert
的实现逻辑修改了。
也就是说,在glibc-2.36
及其之后,house of kiwi
的利用链失效了。
而在这个commit,直接使用默认的assert
,__malloc_assert
被删掉了:
1-5-2 house of emma
只要_IO_cookie_jumps
还在,这个方法就能继续使用。但是,由于poniter_guard
处于ld
的地址空间,所以某些场景是需要爆破的。
1-5-3 house of obstack
glibc-2.36
的时候,_IO_obstack_jumps
被去掉了,但是还有其他方法可以触发调用链。
glibc-2.37
开始这个方法的调用链为:__printf_buffer_as_file_overflow -> __printf_buffer_flush -> __printf_buffer_flush_obstack->__obstack_newchunk
。
1-5-4 house of apple1/2/3
apple1
需要和其他技巧结合使用,可以任意地址写堆地址apple2
利用的_wide_vtable
缺乏校验调用函数指针apple3
利用shlib_handle
去绕过指针加密调用函数指针
1-5-5 house of lyn/snake
_obstack_newchunk
中仍然调用了函数指针,所以还方法仍可以使用。
1-6 _rtld_global
1-6-1 house of banana
整体来看,就是hosue of banana
的利用
1-6-2 利用link_map
围绕link_map
有很多利用技巧,比如之前有使用格式化字符串修改掉link_map->l_addr
,可以让函数解析后的地址被写入到其他地址处。而house of banana
的本质也是围绕link_map
做利用。
1-7 libc.got
1-7-1 libc.got in IO
比如高版本house of pig
没有办法覆写hook
指针,因为这些指针都被删掉了,那么可以覆写libc.got
项,在IO
处理函数中存在着memcpy/memmove
等函数,当这些函数被调用的时候会jmp
到对应的libc.got
存储的地址,因此可以控制libc.got
的内容来劫持RIP
。
1-7-2 libc.got in malloc_printerr
此外,在malloc
中的malloc_printerr
和assert
,都会调用到strlen
的got
,因此,在高版本中可劫持该函数的got
,来控制RIP
。
具体来看,就是在__libc_message
中有调用strlen
:
|
|
1-8 heap_info/malloc_state
攻击堆管理中最核心的数据结构,比如有:
house of mind
伪造heap_info
结构体,进而控制arena
- 直接打掉
thread_arena
,伪造一个arena
- 打掉线程的
tcache
变量 - 修改
pointer_guard
等
1-9 __environ
-
GLIBC_TUNABLE
环境变量的设置会控制ptmalloc_init
的流程,影响很多关键变量的设置,比如tcache_counts
等。在这里有着设置示例Tunables (The GNU C Library)。比如export GLIBC_TUNABLES=glibc.malloc.tcache_count=2
-
有些特殊的环境变量会泄露出信息,比如
LD_SHOW_AUXV
1-10 other
这里是一些不太好归类的攻击面。有:
house of muney
,一种steal heap
的技巧,通过修改mmap chunk
的size
来达成利用exit
的时候会call tls_call_list
里面的函数指针,但是也要能控制pointer_guard
exit
的时候会调用一些锁的函数指针,某些博客中称之为exit_hook
,但是在2.34
之后这些hook
被静态函数所代替
2-参考
[1] Tunables (The GNU C Library)
[2] shellphish/how2heap: A repository for learning various heap exploitation techniques. (github.com)
[3] Overview of GLIBC heap exploitation techniques (0x434b.dev)
[4] [原创] CTF 中 glibc堆利用 及 IO_FILE 总结-Pwn-看雪论坛-安全社区|安全招聘|bbs.pediy.com (kanxue.com)