Stack Buffer Overflow in curl’s OpenSSL Provider Handling
摘要
报告者oblivionsage提交了一个关于curl的OpenSSL提供者处理代码中栈缓冲区溢出的漏洞报告。该漏洞位于lib/vtls/openssl.c
文件的ossl_set_provider()
函数中,当传入的提供者名称长度超过MAX_PROVIDER_LEN
(128字节)时,函数会将其复制到固定大小的缓冲区中,缺乏适当的长度检查,可能导致栈溢出。
漏洞位置
缓冲区溢出发生在lib/vtls/openssl.c
的第2003-2004行:
1
2
|
memcpy(name, curlx_str(&prov), curlx_strlen(&prov));
name[curlx_strlen(&prov)] = 0;
|
代码分析
ossl_set_provider()
函数定义了一个固定缓冲区:
1
|
char name[MAX_PROVIDER_LEN + 1]; // 第1986行
|
其中MAX_PROVIDER_LEN
定义为128(同一文件的第1974行)。
随后在第2003-2004行,函数从提供者字符串复制数据:
1
2
|
memcpy(name, curlx_str(&prov), curlx_strlen(&prov));
name[curlx_strlen(&prov)] = 0;
|
问题在于没有检查curlx_strlen(&prov)
是否小于或等于MAX_PROVIDER_LEN
。如果提供超过128字节的字符串,就会导致栈缓冲区溢出。此外,name[curlx_strlen(&prov)] = 0;
在溢出发生时会在缓冲区末尾之后写入一个空字节。
复现漏洞
代码路径如下:
lib/vtls/openssl.c
中的ossl_set_engine()
调用ossl_set_provider()
Curl_ssl_set_engine()
调用ossl_set_engine()
CURLOPT_SSLENGINE
选项触发Curl_ssl_set_engine()
无法直接通过curl命令行触发崩溃,因为它在到达易受攻击的代码之前会停止并显示“SSL Engine not found”错误。
概念验证(PoC)
创建了一个最小化的PoC来复现确切的易受攻击代码模式:
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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
|
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 与curl代码相同
#define MAX_PROVIDER_LEN 128
typedef struct {
char *data;
size_t len;
} Curl_str;
// 模拟curl的函数
char *curlx_str(Curl_str *s) {
return s->data;
}
size_t curlx_strlen(Curl_str *s) {
return s->len;
}
// 重新创建易受攻击的函数
void simulate_curl_provider_vulnerability(const char *iname) {
char name[MAX_PROVIDER_LEN + 1]; // 与curl相同的缓冲区大小
Curl_str prov;
printf("[+] Input: %s\n", iname);
// 设置提供者字符串
prov.data = (char *)iname;
prov.len = strlen(iname);
printf("[+] Provider length: %zu\n", prov.len);
printf("[+] Buffer size: %zu\n", sizeof(name));
// 易受攻击的部分 - 与curl源代码完全相同
memcpy(name, curlx_str(&prov), curlx_strlen(&prov));
name[curlx_strlen(&prov)] = 0;
printf("[+] Done\n");
}
int main(void) {
char *overflow_string = malloc(300);
// 创建长提供者名称以触发溢出
strcpy(overflow_string, "pkcs11:");
for(int i = 0; i < 200; i++) {
strcat(overflow_string, "A");
}
// 调用易受攻击的函数
simulate_curl_provider_vulnerability(overflow_string);
free(overflow_string);
return 0;
}
|
使用AddressSanitizer编译并运行:
1
2
|
gcc -g -fsanitize=address -o poc poc.c
./poc
|
清楚地显示了栈缓冲区溢出。
补充说明
尝试直接使用curl命令行工具触发此漏洞但未成功,因为curl在到达易受攻击的代码之前返回“SSL Engine not found”错误。然而,易受攻击的代码清楚地存在于curl源代码中,并通过PoC得到确认。
如果需要,可以提供更详细的GDB分析。
影响
此漏洞允许用受控内容覆盖栈内存。在特定上下文中,可能导致:
严重性取决于此代码在应用程序中的使用方式。如果攻击者可以控制提供者名称输入,则最为危险。
后续讨论
curl团队成员dfandrich指出,ossl_set_provider()
包含对curlx_str_until()
的调用,该调用包含长度检查,而PoC模拟缺乏此检查。报告者确认了这一疏忽,并道歉。
最终,报告被关闭,状态更改为“不适用”,因为实际代码中存在长度检查,防止了缓冲区溢出。
披露
应curl团队成员bagder的要求,为了透明度,此报告被公开披露。