glibc中realloc函数源码分析与利用
字数 2020 2025-08-29 08:29:58

glibc中realloc函数源码分析与利用

1. realloc函数概述

realloc函数是C标准库中用于重新分配内存块大小的函数,其原型为:

void *realloc(void *ptr, size_t size);

realloc函数的行为取决于传入的参数组合:

  1. ptr为NULL时,等同于malloc(size)
  2. size为0且ptr不为NULL时,等同于free(ptr)
  3. ptr不为NULL且size大于0时,尝试调整内存块大小

2. realloc源码分析

2.1 基本流程

realloc函数的核心逻辑在_int_realloc函数中实现,主要处理以下几种情况:

情况1:oldmem为空 (ptr == NULL)

  • 直接调用malloc分配新chunk
  • 等同于malloc(size)

情况2:oldmem不为空且size == 0

  • 调用free释放ptr指向的chunk
  • 返回NULL
  • 等同于free(ptr)

情况3:oldmem不为空且size > oldsize

  • 尝试扩展现有chunk
  • 如果相邻高地址有足够空间(top chunk或free chunk),则合并扩展
  • 否则分配新chunk并复制数据

情况4:oldmem不为空且size < oldsize

  • 尝试分割现有chunk
  • 如果剩余空间足够大,则分割并释放剩余部分
  • 否则保持原chunk不变

2.2 关键代码路径

  1. 检查realloc_hook指针(与malloc和free类似)
  2. 进入_int_realloc函数,参数为oldsize和nb(请求大小)
  3. 判断下一个chunk是否是top chunk:
    • 如果是top chunk且空间足够,则从top chunk分割
    • 更新size字段和main_arena的top指针
  4. 如果相邻chunk是free chunk:
    • 检查是否可以合并(unlink操作)
    • 合并后分割,释放剩余部分

3. realloc的利用技术

3.1 利用场景

  1. 从top chunk分割

    • 当请求大小大于原chunk且相邻top chunk有足够空间时
    • 可用于构造特定大小的chunk
  2. unlink合并操作

    • 当相邻高地址chunk为free状态时
    • 可触发unlink操作,造成堆块重叠
    • 需要伪造prev_size和size字段
  3. off-by-one漏洞利用

    • 通过修改size字段最低字节
    • 可构造伪造的chunk结构

3.2 具体利用方法

方法1:利用unlink造成overlapping

  1. 构造场景:

    • chunk1(可控)
    • chunk2(目标)
    • 通过off-by-one修改chunk1的size字段,使其包含伪造的fake_chunk
  2. 伪造结构:

    • 修改chunk1的size和prev_size字段
    • 在chunk2中伪造fake_chunk结构,满足unlink检查
  3. 触发realloc:

    • 对chunk1进行realloc,size大于修改后的size
    • 触发unlink操作,合并fake_chunk
    • 造成chunk2的fd/bk指针被覆盖

方法2:直接修改size字段

  1. 构造多个chunk
  2. 利用漏洞(如off-by-one)修改中间chunk的size字段
  3. 通过realloc操作获得修改后的chunk
  4. 覆盖后续chunk的关键字段(如fd/bk)

3.3 例题分析:[广东强网杯 2021 团队组]GirlFriend

  1. 漏洞点

    • off-by-one漏洞,可修改size字段最低字节
    • add操作限制16次
    • show函数仅一次机会
  2. 利用步骤

    • 申请三个chunk
    • 利用第一个chunk修改第二个chunk的size字段
    • 释放并重新申请,获得修改后的chunk
    • 覆盖第三个chunk的fd指针为free_hook
    • 申请free_hook并写入setcontext+51进行栈迁移
    • 在libc上布置ORW链
  3. 关键点

    • libc-2.27中tcache仅检查头指针是否为空,不检查count
    • 可直接申请到free_hook而不受count限制

4. 防御与绕过

  1. unlink检查

    • 现代glibc加强了unlink的双向链表检查
    • 需要精心构造fake_chunk满足检查
  2. tcache机制

    • libc-2.30后tcache会检查count
    • 需要确保tcache中有可用chunk
  3. size字段检查

    • 对size字段的合法性检查更严格
    • off-by-one利用难度增加

5. 总结

realloc函数的利用关键在于:

  1. 理解不同参数组合下的行为差异
  2. 掌握_int_realloc中的合并与分割逻辑
  3. 利用unlink操作造成堆块重叠
  4. 结合其他漏洞(如off-by-one)修改关键字段

与malloc/free相比,realloc的利用更复杂但也更灵活,特别是在只有单个指针控制的场景下,通过精心构造可以绕过一些常规防护措施。

glibc中realloc函数源码分析与利用 1. realloc函数概述 realloc函数是C标准库中用于重新分配内存块大小的函数,其原型为: realloc函数的行为取决于传入的参数组合: 当 ptr 为NULL时,等同于 malloc(size) 当 size 为0且 ptr 不为NULL时,等同于 free(ptr) 当 ptr 不为NULL且 size 大于0时,尝试调整内存块大小 2. realloc源码分析 2.1 基本流程 realloc函数的核心逻辑在 _int_realloc 函数中实现,主要处理以下几种情况: 情况1:oldmem为空 (ptr == NULL) 直接调用malloc分配新chunk 等同于malloc(size) 情况2:oldmem不为空且size == 0 调用free释放ptr指向的chunk 返回NULL 等同于free(ptr) 情况3:oldmem不为空且size > oldsize 尝试扩展现有chunk 如果相邻高地址有足够空间(top chunk或free chunk),则合并扩展 否则分配新chunk并复制数据 情况4:oldmem不为空且size < oldsize 尝试分割现有chunk 如果剩余空间足够大,则分割并释放剩余部分 否则保持原chunk不变 2.2 关键代码路径 检查realloc_ hook指针(与malloc和free类似) 进入 _int_realloc 函数,参数为oldsize和nb(请求大小) 判断下一个chunk是否是top chunk: 如果是top chunk且空间足够,则从top chunk分割 更新size字段和main_ arena的top指针 如果相邻chunk是free chunk: 检查是否可以合并(unlink操作) 合并后分割,释放剩余部分 3. realloc的利用技术 3.1 利用场景 从top chunk分割 : 当请求大小大于原chunk且相邻top chunk有足够空间时 可用于构造特定大小的chunk unlink合并操作 : 当相邻高地址chunk为free状态时 可触发unlink操作,造成堆块重叠 需要伪造prev_ size和size字段 off-by-one漏洞利用 : 通过修改size字段最低字节 可构造伪造的chunk结构 3.2 具体利用方法 方法1:利用unlink造成overlapping 构造场景: chunk1(可控) chunk2(目标) 通过off-by-one修改chunk1的size字段,使其包含伪造的fake_ chunk 伪造结构: 修改chunk1的size和prev_ size字段 在chunk2中伪造fake_ chunk结构,满足unlink检查 触发realloc: 对chunk1进行realloc,size大于修改后的size 触发unlink操作,合并fake_ chunk 造成chunk2的fd/bk指针被覆盖 方法2:直接修改size字段 构造多个chunk 利用漏洞(如off-by-one)修改中间chunk的size字段 通过realloc操作获得修改后的chunk 覆盖后续chunk的关键字段(如fd/bk) 3.3 例题分析:[ 广东强网杯 2021 团队组 ]GirlFriend 漏洞点 : off-by-one漏洞,可修改size字段最低字节 add操作限制16次 show函数仅一次机会 利用步骤 : 申请三个chunk 利用第一个chunk修改第二个chunk的size字段 释放并重新申请,获得修改后的chunk 覆盖第三个chunk的fd指针为free_ hook 申请free_ hook并写入setcontext+51进行栈迁移 在libc上布置ORW链 关键点 : libc-2.27中tcache仅检查头指针是否为空,不检查count 可直接申请到free_ hook而不受count限制 4. 防御与绕过 unlink检查 : 现代glibc加强了unlink的双向链表检查 需要精心构造fake_ chunk满足检查 tcache机制 : libc-2.30后tcache会检查count 需要确保tcache中有可用chunk size字段检查 : 对size字段的合法性检查更严格 off-by-one利用难度增加 5. 总结 realloc函数的利用关键在于: 理解不同参数组合下的行为差异 掌握 _int_realloc 中的合并与分割逻辑 利用unlink操作造成堆块重叠 结合其他漏洞(如off-by-one)修改关键字段 与malloc/free相比,realloc的利用更复杂但也更灵活,特别是在只有单个指针控制的场景下,通过精心构造可以绕过一些常规防护措施。