Double Free漏洞浅析

1. 概述

Double Free(双重释放)是一种严重的堆内存管理安全漏洞。当程序对同一块动态分配的堆内存连续调用两次 free()(C语言)或 delete(C++),且两次释放之间没有重新分配该内存时,就会触发该漏洞。

该漏洞在 MITRE CWE 标准 中被归类为CWE-415。它与 Use After Free (UAF) 漏洞关系极其紧密,常常是攻击者用来攻破现代操作系统内存防护的关键手段。

2. 漏洞工作原理(以 glibc 堆管理器为例)

动态内存分配(如 malloc)依靠堆管理器(ptmalloc)来维护内存状态。释放内存时,堆管理器不会立刻将内存归还给操作系统,而是将其插入内部的空闲链表(如 tcache、fastbin、unsorted bin)中,以便下次malloc()时快速复用

  • 1. 首次释放:程序调用free(P) 后,P指向的内存块被放入空闲链表中,但指针P仍然保存着该地址(成为悬挂指针/Dangling Pointer);
  • 2. 重复释放:由于逻辑错误,在未对P重新赋值的情况下再次调用 free(P),指针P依然指向同一个内存块,堆管理器尝试将同一个内存块再次挂载到空闲链表上;
  • 3. 链表结构破坏:这会导致同一个内存块在空闲链表中被插入了两次;空闲链表的头部指针(Head)指向P,而指针P的内部指针(Next)竟然也指向了P自身,形成了一个环形链表(Cyclic List)
  • 4. 后续分配:当程序再次调用 malloc() 时,堆管理器会连续两次返回完全相同的内存地址。这导致两个不同的程序逻辑同时持有并修改同一块内存,产生内存重叠(Heap Overlap)。

3. 漏洞成因与危害

在实际开发中,导致 Double Free 的常见逻辑缺陷包括:

  • 1. 异常处理路径不当:程序在正常流程末尾会释放内存,但在中途发生错误(异常退出、条件跳转)时,误进入了另一条也会释放该内存的清理路径;
  • 2. 多线程竞争(Race Condition):两个不同的线程同时持有同一个对象的指针,并在没有互斥锁保护的情况下,几乎同时对该对象调用了释放函数;
  • 3. 错误的指针拷贝(浅拷贝):在 C++ 中,如果一个类持有一个普通的堆指针,但在进行对象复制时没有重写拷贝构造函数(执行了浅拷贝),就会导致两个对象指向同一块堆内存;当这两个对象相继析构时,就会触发 Double Free;

4. 代码示例

代码示例一:经典的 Double Free 漏洞触发

#include <stdio.h>
#include <stdlib.h>

int main() {
    char *buf1 = (char *)malloc(64);
    
    // 正常使用内存
    snprintf(buf1, 64, "Hello, Double Free!");

    // 第一次释放
    free(buf1); 

    // 执行了其他业务逻辑,但未清空 buf1 指针...

    // 第二次释放同一个指针(触发 Double Free 漏洞)
    free(buf1); 

    return 0;
}

代码示例二:Double Free 漏洞触发与利用逻辑模型:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct Data {
    char buffer[64];
};

struct Config {
    void (*execute_cmd)(const char *); // 函数指针
};

void safe_command(const char *cmd) { printf("[+] 执行安全命令: %s\n", cmd); }
void evil_command(const char *cmd) { printf("[!!!] 权限绕过!执行恶意命令: %s\n", cmd); }

int main() {
    // 1. 分配一个初始数据块
    struct Data *d1 = (struct Data *)malloc(sizeof(struct Data));
    
    // 2. 触发 Double Free 漏洞(连续释放,且未置空)
    free(d1);
    free(d1); // 在某些旧版或未加固的堆管理器中,此时空闲链表已成环

    // 3. 第一次分配:正常业务申请内存,拿到地址 d1
    struct Data *d2 = (struct Data *)malloc(sizeof(struct Data));
    // 攻击者控制 d2 的输入,往里面写入一个恶意的函数地址
    long *ptr = (long *)d2->buffer;
    *ptr = (long)evil_command; 

    // 4. 第二次分配:系统由于链表成环,再次将地址d1分配给另一个敏感对象
    struct Config *cfg = (struct Config *)malloc(sizeof(struct Config));
    
    // 5. 灾难发生:cfg 和 d2 共享同一块内存!
    // 此时 cfg->execute_cmd 本应指向 safe_command,但已经被第3步的 d2->buffer 篡改了
    cfg->execute_cmd("whoami"); 

    return 0;
}

5. 漏洞现状与修复手段

由于 Double Free 的危害极大,现代操作系统和编译器引入了极强的硬核防护技术:

5.1 堆管理器的运行时检测(Glibc 缓解措施)

现代的 glibc(如近年来的新版本)引入了 Double Free 检测机制

  • 当程序调用 free(P) 时,堆管理器会检查当前准备放入空闲链表(如 tcache)的块,是否与链表顶部的块地址相同;
  • 如果相同,程序会立刻强制崩溃并抛出错误提示:double free or corruption (fasttop)double free or corruption (out),从而直接阻止攻击者进行下一步的“成环占坑”;

5.2 安全的编码规范

5.2.1 释放后立即将指针置空(NULL)

与防御 UAF 一样,释放指针后必须立刻将其赋值为 NULL。因为在C/C++语言规范中,free(NULL) 是完全安全的,不会执行任何操作:

free(P);
ptr = NULL; // 即使再次 free(P) 也不会产生危害

也可定义安全释放宏:

#define SAFE_FREE(p) do { free(p); (p) = NULL; } while(0)

5.2.2 使用现代化内存管理(C++ RAII)

在 C++ 中应尽量避免手动控制 new/delete,转而使用智能指针(std::unique_ptrstd::shared_ptr)或标准容器(如 std::vector),由编译器和作用域自动管理生命周期。

5.3 开启编译检测与静态分析

AddressSanitizer (ASan):在编译时开启 -fsanitize=address。在运行时,一旦程序触发 Double Free,ASan 会立刻精准捕捉并输出两处 free() 分别发生的完整调用栈(Call Stack),极大地降低了漏洞排查难度。

静态代码分析: 在 CI/CD 流程中使用 Coverity、Cppcheck 等工具提早发现未重置的悬挂指针。

免责声明:

1. 一般免责声明:本文所提供的技术信息仅供参考,不构成任何专业建议。读者应根据自身情况谨慎使用且应遵守《中华人民共和国网络安全法》,作者及发布平台不对因使用本文信息而导致的任何直接或间接责任或损失负责。

2. 适用性声明:文中技术内容可能不适用于所有情况或系统,在实际应用前请充分测试和评估。若因使用不当造成的任何问题,相关方不承担责任。

3. 更新声明:技术发展迅速,文章内容可能存在滞后性。读者需自行判断信息的时效性,因依据过时内容产生的后果,作者及发布平台不承担责任。
觉得有帮助可以赞赏本文哦~万分感谢!
文章:Double Free漏洞浅析
作者:沛旗
链接:https://www.peiqiblog.com/article/13460/
版权声明::本博客站点所有文章除特别声明外,均采用 CC BY-NC-SA 4.0协议
转载请注明文章地址及作者哦~
暂无评论

发送评论(禁止发表一切违反法律法规的敏感言论) 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇