libcurl HTTP/3 POST请求处理中的栈使用后释放漏洞解析

本文详细分析了libcurl在处理HTTP/3 POST请求时,因CURLOPT_POSTFIELDS使用栈分配缓冲区导致的栈使用后释放漏洞。包括漏洞成因、复现步骤、技术分析和修复建议,帮助开发者避免类似内存安全问题。

栈使用后释放漏洞:libcurl HTTP/3 POST请求处理中的CURLOPT_POSTFIELDS问题

摘要

libcurl的HTTP/3请求处理在使用CURLOPT_POSTFIELDS与栈分配缓冲区时存在栈使用后释放漏洞。libcurl保留用户提供的POST数据指针,但在原始栈帧销毁后访问该指针,导致内存损坏和潜在拒绝服务。

漏洞详情

漏洞存在于Curl_pretransfer()(transfer.c:569),当libcurl对先前存储的POST数据指针调用strlen()时,该指针现已指向无效的栈内存。

复现步骤/概念验证

环境

  • libcurl版本:8.16.0-DEV(master分支)
  • 编译器:带AddressSanitizer的Clang 20.1.8
  • 平台:macOS(ARM64)
  • 配置:启用HTTP/3(使用ngtcp2/nghttp3)

复现步骤

  1. 使用ASAN构建libcurl:
1
2
3
4
export CC=clang
export CFLAGS="-O1 -g -fsanitize=address,undefined"
./configure --with-openssl --with-nghttp2 --with-nghttp3 --with-ngtcp2
make
  1. 编译复现程序:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// http3_crash_poc.c
#include <curl/curl.h>
#include <string.h>

int main() {
    CURL *curl = curl_easy_init();
    
    // 栈分配缓冲区,超出作用域
    {
        char body_data[257];
        memset(body_data, 'A', 256);
        body_data[256] = '\0';
        
        curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
        curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_3);
        curl_easy_setopt(curl, CURLOPT_POST, 1L);
        curl_easy_setopt(curl, CURLOPT_POSTFIELDS, body_data); // 漏洞调用
        curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, 50L);
    } // body_data在此处超出作用域
    
    // libcurl在传输期间访问无效内存
    curl_easy_perform(curl);
    curl_easy_cleanup(curl);
    return 0;
}
  1. 编译并运行:
1
2
clang -fsanitize=address http3_crash_poc.c -lcurl -o poc
./poc

崩溃输出

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
==3720==ERROR: AddressSanitizer: stack-use-after-scope on address 0x00016fa21470
READ of size 45 at 0x00016fa21470 thread T0
    #0 strlen
    #1 Curl_pretransfer transfer.c:569
    #2 multi_runsingle multi.c:2376
    #3 curl_multi_perform multi.c:2756
    #4 easy_transfer easy.c:705
    #5 easy_perform easy.c:813

SUMMARY: AddressSanitizer: stack-use-after-scope transfer.c:569 in Curl_pretransfer

技术分析

根本原因

漏洞源于libcurl的CURLOPT_POSTFIELDS行为:

  • libcurl存储指针但不复制数据
  • 应用程序的栈缓冲区在作用域退出后变为无效
  • libcurl随后在Curl_pretransfer()中解引用无效指针

受影响代码路径

1
2
3
4
5
curl_easy_setopt(CURLOPT_POSTFIELDS) →
curl_easy_perform() →
Curl_pretransfer() →
strlen(invalid_pointer) →
崩溃

建议修复

  • 文档说明:明确CURLOPT_POSTFIELDS数据必须在传输完成前保持有效
  • API增强:考虑为栈检测指针添加边界检查或自动复制
  • 替代API:推广CURLOPT_COPYPOSTFIELDS以实现更安全的使用模式

影响

安全影响

  • 拒绝服务:保证崩溃导致应用程序终止
  • 内存损坏:使用后释放可能导致不可预测行为
  • 潜在代码执行:在特定情况下,内存损坏可能被利用进行控制流劫持

受影响场景

  • 使用libcurl进行带POST数据的HTTP/3请求的应用程序
  • 任何CURLOPT_POSTFIELDS指向栈分配内存的代码模式
  • 特别影响:
    • HTTP/3客户端应用程序
    • 使用栈缓冲区作为请求体的API客户端
    • 堆使用受限的嵌入式系统

实际暴露

  • 语言绑定:许多curl绑定可能无意中创建此模式
  • 示例应用程序:CLI工具、网络爬虫、API客户端
  • 严重性:由于HTTP/3采用增长和远程可利用性而评为高

时间线

  • geeknik 提交报告:10天前
  • bagder(curl工作人员)回复:将调查报告
  • bagder 进一步评论:CURLOPT_POSTFIELDS文档特别强调此行为,认为是用户错误而非libcurl缺陷
  • geeknik 同意并关闭报告,状态改为"不适用"
  • 报告已披露:10天前

报告详情

  • 报告ID:#3279804
  • 严重性:高(7 ~ 8.9)
  • 披露时间:2025年7月31日 15:09 UTC
  • 弱点类型:释放后使用
  • CVE ID:无
  • 赏金:隐藏

注意:根据curl团队反馈,此问题被认定为用户未遵循CURLOPT_POSTFIELDS文档要求所致,而非libcurl本身的安全漏洞。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计