栈作用域后使用漏洞:libcurl HTTP/3 POST请求处理中的CURLOPT_POSTFIELDS问题
漏洞摘要
在libcurl的HTTP/3请求处理过程中存在一个栈作用域后使用漏洞,当使用CURLOPT_POSTFIELDS与栈分配缓冲区时会出现此问题。libcurl会保留用户提供的POST数据指针,但在原始栈帧被销毁后仍访问该指针,导致内存损坏和潜在的拒绝服务攻击。
该漏洞发生在transfer.c:569的Curl_pretransfer()函数中,当libcurl对先前存储的POST数据指针(现在指向无效的栈内存)调用strlen()时触发。
复现步骤/概念验证
环境配置
- libcurl版本:8.16.0-DEV(master分支)
- 编译器:Clang 20.1.8 with AddressSanitizer
- 平台:macOS(ARM64)
- 配置:启用HTTP/3(使用ngtcp2/nghttp3)
复现步骤
- 使用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
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
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进行HTTP/3请求并带有POST数据的应用程序
- 任何CURLOPT_POSTFIELDS指向栈分配内存的代码模式
- 特别影响:
- HTTP/3客户端应用程序
- 使用栈缓冲区作为请求体的API客户端
- 堆使用受限的嵌入式系统
实际暴露风险
- 语言绑定:许多curl绑定可能无意中创建此模式
- 示例应用程序:CLI工具、网络爬虫、API客户端
- 严重性:由于HTTP/3采用率增长和远程可利用性,被评为高风险
项目方回应
curl开发团队确认CURLOPT_POSTFIELDS的文档特别强调了此行为,认为这是用户错误而非libcurl缺陷:
“指向的数据不会被库复制:因此,调用应用程序必须保留该数据,直到相关传输完成。可以通过改用CURLOPT_COPYPOSTFIELDS(3)选项来改变此行为(这样libcurl会复制数据)。”
报告最终被标记为"不适用"并已公开披露。