跟上时代之高版本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实现利用:

  1. largebin特点:

    • 存储大小不同的chunk
    • 特有字段:fd_nextsize和bk_nextsize
    • 按大小排序,fd_nextsize指向下一个更小的chunk,bk_nextsize指向上一个更大的chunk
  2. 关键分配代码:

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

  1. 泄露堆地址:

    • 释放两个largebin大小的堆块形成链表
    • 利用UAF打印fd_nextsize/bk_nextsize字段
  2. 伪造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;
}

攻击步骤详解

  1. 准备两个largebin chunk(p1 > p2)
  2. 释放p1,然后分配更大的chunk使p1进入largebin
  3. 释放p2到unsorted bin
  4. 修改p1的bk_nextsize指向target-0x20
  5. 分配更大的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 利用场景

  1. 修改global_max_fast:

    • 使所有堆块被视为fastbin
    • 便于后续fastbin attack
  2. 指针劫持:

    • 劫持到可控区域
    • 伪造结构体控制程序流(如iofile攻击)
  3. 结合tls_dtor_list:

    • 通过两次largebin attack写入结构体指针
    • 伪造dtor_list结构体
    • 利用__call_tls_dtors函数调用指针

0x05 实例分析:2021湖湘杯husk

利用步骤

  1. 泄露libc地址:

    • 释放largebin chunk后利用UAF泄露
  2. 第一次largebin attack:

    • 修改pointer_guard(fs:0x30)
  3. 第二次largebin attack:

    • 修改tls_dtor_list
  4. 布置ROP链:

    • 利用gadget控制rdx寄存器:
      mov rdx, [rdi+8]
      mov [rsp+0C8h+var_C8], rax
      call qword ptr [rdx+20h]
      
  5. 最终实现任意代码执行

关键代码片段

# 第一次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
高版本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的地址 关键代码: 0x02 Largebin Attack基础 传统Largebin Attack (GLIBC-2.29前) 在旧版本中,通过伪造largebin的bk_ nextsize实现利用: largebin特点: 存储大小不同的chunk 特有字段:fd_ nextsize和bk_ nextsize 按大小排序,fd_ nextsize指向下一个更小的chunk,bk_ nextsize指向上一个更大的chunk 关键分配代码: 实例分析:2017 LCTF-2ez4u 泄露堆地址: 释放两个largebin大小的堆块形成链表 利用UAF打印fd_ nextsize/bk_ nextsize字段 伪造largebin chunk: 修改被释放堆块的bk_ nextsize字段 绕过unlink检查 申请出伪造的堆块后泄露libc地址 0x03 新版Largebin Attack (GLIBC-2.30+) GLIBC-2.30新增了两个检查: 绕过方法 利用以下代码路径实现攻击: 攻击步骤详解 准备两个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寄存器: 最终实现任意代码执行 关键代码片段 0x06 总结 在GLIBC高版本环境下,largebin attack成为替代unsorted bin attack的重要技术。通过精心构造largebin chunk的bk_ nextsize字段,可以实现向任意地址写入堆地址的效果,为进一步的利用奠定基础。这种技术在未来可能会成为主流的堆利用方法之一。 0x07 参考 奇安信攻防社区文章《跟上时代之高版本GLIBC下堆利用(三)》 how2heap largebin_ attack.c 2017 LCTF-2ez4u 2021湖湘杯husk