curl OpenSSL提供者处理中的栈缓冲区溢出漏洞分析

本文详细分析了curl的OpenSSL提供者处理代码中潜在的栈缓冲区溢出漏洞,包括漏洞位置、代码分析、复现方法和PoC演示,最终确认该漏洞因存在长度检查而无法实际利用。

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;在溢出发生时会在缓冲区末尾之后写入一个空字节。

复现漏洞

代码路径如下:

  1. lib/vtls/openssl.c中的ossl_set_engine()调用ossl_set_provider()
  2. Curl_ssl_set_engine()调用ossl_set_engine()
  3. 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的要求,为了透明度,此报告被公开披露。

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