heap_study
heap_study
1 | +-------------------+ <- chunk起始地址(低地址) |
Chunk Extend and Overlapping
条件
- 程序中存在基于堆的漏洞
- 漏洞可以控制 chunk header 中的数据
chunk extend可以做什么
这种技术并不能直接控制程序的执行流程,但是可以控制 chunk 中的内容。如果 chunk 存在字符串指针、函数指针等,就可以利用这些指针来进行信息泄漏和控制执行流程。此外通过 extend 可以实现 chunk overlapping,通过 overlapping 可以控制 chunk 的 fd/bk 指针从而可以实现 fastbin attack 等利用。
对inuse的fastbin进行extend
对inuse的smallbin进行extend
对 free 的 smallbin 进行 extend
与前一个相同只不过不需要防止与top_chunk合并
通过 extend 后向 overlapping
通过 extend 前向 overlapping
通过unlink进行向前的overlapping
unsafe_unlink(glibc2.31)
向前合并向后合并
当两个free的堆块在物理上相邻时,会将他们合并,并将原来free的堆块在原来的链表中解链,加入新的链表中。这里的向前即低地址的chunk而非fd,bk指针所指的chunk(向后同理),以当前chunk为基准,将next_free_chunk与当前chunk合并为向前合并,将previous_free_chunk与当前chunk合并为向后合并。
向后合并
1 | /*malloc.c int_free函数中*//*这里p指向当前malloc_chunk结构体,bck和fwd分别为当前chunk的向后和向前一个free chunk*/ |
向前合并
1 | if (nextchunk != av->top) { |
unlink
1 |
|
1 |
|
分配完两个chunk后
我们利用chunk0_ptr构造一个fake_chunk来绕过unlink的检查
满足(P->fd->bk != P || P->bk->fd != P) == False
此时假设能实现堆溢出就可以修改chunk1的元数据
来使free认为chunk0为free,以便free(chunk1)后触发unlink
此时chunk_ptr指向chunk_ptr - 0x18
fastbin_attack
fastbin_double_free
Fastbin Double Free 能够成功利用主要有两部分的原因
- fastbin 的堆块被释放后 next_chunk 的 pre_inuse 位不会被清空
- fastbin 在执行 free 的时候仅验证了 main_arena 直接指向的块,即链表指针头部的块。对于链表后面的块,并没有进行验证。
以下是一个简单的演示
1 |
|
先进行两次申请
在进行三次释放此时
可以看到尾部的chunk1指向chunk2
修改后可以看到
house_of_spirit(glibc2.31)
1 | house-of-spirit 是一种通过堆的 fast bin 机制来辅助栈溢出的方法 |
1 |
|
栈上还未进行构造的fake_chunks
我们将要将fake_chunks进行以下构造而绕过glibc的检查
下面是构造后的fake_chunks
构造 chunk 的时候要注意绕过一些检查:
后面那三个特殊的标志位前两个必须都为 0,构造 size 的时候直接 0x*0就可以了,然后大小要注意符合 fastbin 的大小,next chunk 的大小也要注意,必须大于 2*SIZE_SZ,小于 av->system_mem.64位下:16< next chunk 的 size < 128kb。
fastbin_dup_into_stack(Alloc to Stack)
1 |
|
在UAF的基础上,修改chunk1的fd指针指向stack_var前的0x20的位置
此时main_arena指向了栈上,再malloc一次就分配到了栈上
Arbitrary Alloc
Arbitrary Alloc 其实与 Alloc to stack 是完全相同的,唯一的区别是分配的目标不再是栈中。 事实上只要满足目标地址存在合法的 size 域(这个 size 域是构造的,还是自然存在的都无妨),我们可以把 chunk 分配到任意的可写内存中,比如 bss、heap、data、stack 等等。
1 |
|
fd指针得出
1 | //这里的size指用户区域,因此要小2倍SIZE_SZ |
人工
可以看到0x7f9558141af5处能错位出一个0x000000000000007f的size域,可以在此构造一个0x70的fake_chunk,需要malloc 0x60的chunk
pwndbg
利用pwndbg的find_fake_fast指令第一个参数是想要overlap的地址,第二个参数是大小(要在fastbin的范围内)
fastbin_dup_consolidate
绕过tcache对double free的检查(latest)
1 |
|
填充完tcache后calloc一个相同大小的chunk,free它后将会被放入fastbin中
随后malloc一个0x400的chunk触发malloc_consolidate此时p1 = p3
此时可以实现对p1的重释放
此时我们再malloc一个0x400的chunk就可以实现对tcache上的UAF(p3 = p4)
注意:这种复制也可以用于更大的块大小,块的行为相同,只是从 top 而不是从 tcache bin 中取出。
绕过fastbin 对 double free 的检查(glibc2.23)
1 |
|
一开始calloc()两个0x10的chunk
先释放掉p1放到fastbin中
此时malloc一个 large chunk 即:void *p3 = malloc(0x400); 触发malloc_consolidate将fastbin中的chunk放入到smallbin或者unstoredbin
此时p1就不在fastbin中链表的头部了,就可以被再次free
那么p1就既在fastbin和smallbin中了
现在再进行两次malloc那么就都分配到p1
此时就实现了UAF
house_of_force(glibc2.31)
house_of_lore(glibc2.31)
1 | House of Lore 的作用主要是利用 malloc 实现中的逻辑漏洞,在堆溢出攻击中实现任意内存写入。攻击者通过精心构造的堆块伪造和未检查的合并操作,可以欺骗 malloc 认为一个伪造的块是合法的堆块,从而进行任意内存写入。这种攻击技术允许攻击者修改全局变量、函数指针等关键数据,甚至可能实现远程代码执行,造成严重安全问题。 |
1 |
|
- Small Bin Corruption Check (small bin 受损检查):
glibc
内存分配器在管理 small bin 时,会检查堆块的fwd
和bk
指针,以确保它们指向正确的位置。这是为了防止堆块链表被破坏,从而导致潜在的内存损坏或安全漏洞。- 当内存分配器从 small bin 中分配或释放内存块时,它会检查每个堆块的
fwd
(前向)和bk
(后向)指针。这些指针用于维护堆块链表,确保堆块能够正确插入和移除。 - 如果链表中存在不一致(例如指针指向错误的内存位置),内存分配器会检测到并触发一个错误,防止恶意利用。
- Smallbin-to-Tcache Mechanism (small bin 转换为 tcache 机制):
glibc
引入了 tcache(thread cache)机制,以加速小块内存的分配和释放。tcache 通过维护每个线程的私有缓存,减少了全局锁争用。然而,small bin 和 tcache 之间的转换会进行额外的检查,以确保堆块链表的完整性和一致性。- 当内存块从 small bin 转移到 tcache 时,内存分配器会进行检查,以确保转移过程中的堆块链表没有损坏。这包括检查
fwd
和bk
指针的有效性,以及确保链表的完整性。 - 这些检查可以防止攻击者通过伪造堆块链表来操纵内存分配过程。
首先申请一个smallbin的范围内的chunk-victim_chunk,再在栈上构造两个fake_chunk和一个freelist以绕过上面的保护机制
随后构造stack_buffer_1和stack_buffer_2的fd和bk指针
此时再malloc一个chunk以防止victim_chunk与top_chunk合并
随后再malloc一个large_chunk触发malloc_consolidate然后glibc会将victim_chunk由unstoredbin放入smallbin中
再将victim_chunk的fd指针改为stack_buffer_1
此时malloc一次将会malloc到victim_chunk,再malloc一次就会malloc到stack_buffer_1。