跟上时代之高版本GLIBC下堆利用(三)
字数 1659 2025-08-07 08:22:33
高版本GLIBC下堆利用:Largebin Attack详解
0x00 前言
在GLIBC-2.29之后,unsorted bin attack由于新增的保护机制基本失效,需要寻找替代的利用方法。本文详细讲解largebin attack技术,它可以在不需要泄露堆地址的情况下,向任意地址写入一个堆地址。
0x01 Unsorted Bin Attack回顾
在GLIBC-2.29之前,unsorted bin attack是常用的利用技术:
- 原理:控制unsorted bin的bk指针指向可写地址,向其写入unsorted bin的地址
- 关键代码:
/* remove from unsorted list */
if (__glibc_unlikely (bck->fd != victim))
malloc_printerr("malloc(): corrupted unsorted chunks 3");
unsorted_chunks (av)->bk = bck;
bck->fd = unsorted_chunks (av);
0x02 Largebin Attack基础
传统Largebin Attack (GLIBC-2.29前)
在旧版本中,通过伪造largebin的bk_nextsize实现利用:
-
largebin特点:
- 存储大小不同的chunk
- 特有字段:fd_nextsize和bk_nextsize
- 按大小排序,fd_nextsize指向下一个更小的chunk,bk_nextsize指向上一个更大的chunk
-
关键分配代码:
if (!in_smallbin_range(nb)) {
bin = bin_at(av, idx);
if ((victim = first(bin)) != bin &&
(unsigned long)(victim->size) >= (unsigned long)(nb)) {
victim = victim->bk_nextsize; // 反向遍历
while (((unsigned long)(size = chunksize(victim)) < (unsigned long)(nb)))
victim = victim->bk_nextsize;
// ...后续unlink操作
}
}
实例分析:2017 LCTF-2ez4u
-
泄露堆地址:
- 释放两个largebin大小的堆块形成链表
- 利用UAF打印fd_nextsize/bk_nextsize字段
-
伪造largebin chunk:
- 修改被释放堆块的bk_nextsize字段
- 绕过unlink检查
- 申请出伪造的堆块后泄露libc地址
0x03 新版Largebin Attack (GLIBC-2.30+)
GLIBC-2.30新增了两个检查:
// 检查1
if (__glibc_unlikely(fwd->bk_nextsize->fd_nextsize != fwd))
malloc_printerr("malloc(): largebin double linked list corrupted (nextsize)");
// 检查2
if (bck->fd != fwd)
malloc_printerr("malloc(): largebin double linked list corrupted (bk)");
绕过方法
利用以下代码路径实现攻击:
if ((unsigned long)(size) < (unsigned long)chunksize_nomask(bck->bk)){
fwd = bck;
bck = bck->bk;
victim->fd_nextsize = fwd->fd;
victim->bk_nextsize = fwd->fd->bk_nextsize;
fwd->fd->bk_nextsize = victim->bk_nextsize->fd_nextsize = victim;
}
攻击步骤详解
- 准备两个largebin chunk(p1 > p2)
- 释放p1,然后分配更大的chunk使p1进入largebin
- 释放p2到unsorted bin
- 修改p1的bk_nextsize指向target-0x20
- 分配更大的chunk使p2进入largebin
关键操作:
victim->bk_nextsize = fwd->fd->bk_nextsize(即target-0x20)fwd->fd->bk_nextsize = victim导致(target-0x20)->fd_nextsize = victim- 最终效果:在target处写入victim(p2)的地址
0x04 利用场景
-
修改global_max_fast:
- 使所有堆块被视为fastbin
- 便于后续fastbin attack
-
指针劫持:
- 劫持到可控区域
- 伪造结构体控制程序流(如iofile攻击)
-
结合tls_dtor_list:
- 通过两次largebin attack写入结构体指针
- 伪造dtor_list结构体
- 利用__call_tls_dtors函数调用指针
0x05 实例分析:2021湖湘杯husk
利用步骤
-
泄露libc地址:
- 释放largebin chunk后利用UAF泄露
-
第一次largebin attack:
- 修改pointer_guard(fs:0x30)
-
第二次largebin attack:
- 修改tls_dtor_list
-
布置ROP链:
- 利用gadget控制rdx寄存器:
mov rdx, [rdi+8] mov [rsp+0C8h+var_C8], rax call qword ptr [rdx+20h]
- 利用gadget控制rdx寄存器:
-
最终实现任意代码执行
关键代码片段
# 第一次largebin attack修改pointer_guard
pay = free(3, 0)
pay += edit(1, 0x20, p64(0)*3 + p64(pointer_guard_addr-0x20), 0)
pay += add(5, 0x500, 0)
# 第二次largebin attack修改tls_dtor_list
pay = free(3, 0)
pay += edit(1, 0x20, p64(0)*3 + p64(tls_dtor_list_addr-0x20), 0)
pay += add(5, 0x500, 0)
# 布置ROP链
rop = (0x0000000000169e90 + libc_base) ^ (heap+0x2f50)
rop = ((rop>>(64-0x11))|(rop<<0x11))
pay = b''.ljust(0x410, b's') + p64(rop) + p64(heap+0x26d0)
edit(2, len(pay), pay)
0x06 总结
在GLIBC高版本环境下,largebin attack成为替代unsorted bin attack的重要技术。通过精心构造largebin chunk的bk_nextsize字段,可以实现向任意地址写入堆地址的效果,为进一步的利用奠定基础。这种技术在未来可能会成为主流的堆利用方法之一。
0x07 参考
- 奇安信攻防社区文章《跟上时代之高版本GLIBC下堆利用(三)》
- how2heap largebin_attack.c
- 2017 LCTF-2ez4u
- 2021湖湘杯husk