cURL WebSocket握手缓冲区溢出漏洞分析

本文详细分析了cURL WebSocket实现中的缓冲区溢出漏洞,涉及lib/ws.c:1287处的strcpy函数使用问题,包含完整的技术分析、复现步骤和修复建议,最终确认为误报。

缓冲区溢出漏洞报告 #3392174 - WebSocket握手过程 (lib/ws.c:1287)

摘要

cURL WebSocket实现中的缓冲区溢出漏洞,由于在握手过程中不安全使用strcpy()函数。漏洞位于lib/ws.c:1287处,调用strcpy(keyval, randstr)时未进行适当的边界检查,尽管代码中较早处有边界检查。

AI披露声明:此漏洞分析是在AI协助下进行的。所有技术细节、代码分析和漏洞利用开发都通过手动测试和代码审查进行了验证。该漏洞存在于实际的cURL源代码中,并已通过有效的概念验证进行演示。

受影响版本

  • cURL版本:cURL 8.7.1 (x86_64-apple-darwin25.0)
  • libcurl/8.7.1 (SecureTransport) LibreSSL/3.3.6 zlib/1.2.12 nghttp2/1.66.0
  • 发布日期:2024-03-27
  • 平台:macOS 25.0.0

复现步骤

1. 创建恶意WebSocket服务器

 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
# Save as websocket_exploit.py
import socket

class WebSocketExploitServer:
    def __init__(self, host='127.0.0.1', port=8080):
        self.host = host
        self.port = port

    def start_server(self):
        self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.server_socket.bind((self.host, self.port))
        self.server_socket.listen(1)

        print(f"Malicious WebSocket server started on {self.host}:{self.port}")

        while True:
            client_socket, addr = self.server_socket.accept()
            print(f"Connection from {addr}")

            # Handle WebSocket handshake
            request = client_socket.recv(4096).decode('utf-8')

            # Parse Sec-WebSocket-Key to confirm vulnerability trigger
            for line in request.split('\n'):
                if line.startswith('Sec-WebSocket-Key:'):
                    key = line.split(':', 1)[1].strip()
                    print(f"Sec-WebSocket-Key: {key}")
                    print(f"Key length: {len(key)} bytes")
                    print("VULNERABILITY TRIGGERED!")
                    print("curl executed: strcpy(keyval, randstr);")
                    break

            # Send WebSocket handshake response
            response = (
                "HTTP/1.1 101 Switching Protocols\r\n"
                "Upgrade: websocket\r\n"
                "Connection: Upgrade\r\n"
                "Sec-WebSocket-Accept: dGhlIHNhbXBsZSBub25jZQ==\r\n"
                "\r\n"
            )

            client_socket.send(response.encode('utf-8'))
            print("WebSocket handshake completed")
            client_socket.close()

if __name__ == "__main__":
    server = WebSocketExploitServer()
    server.start_server()

2. 启动恶意服务器

1
python3 websocket_exploit.py

3. 使用cURL触发漏洞

1
2
3
4
curl -i -N -H 'Connection: Upgrade' \
     -H 'Upgrade: websocket' \
     -H 'Sec-WebSocket-Version: 13' \
     http://127.0.0.1:8080/

4. 观察成功利用

1
2
3
4
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=

支持材料/参考文献

漏洞代码位置:lib/ws.c:1287

漏洞函数:Curl_ws_request()

精确代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
char keyval[40];  // 40-byte buffer

result = curlx_base64_encode((char *)rand, sizeof(rand), &randstr, &randlen);
if(result)
  return result;
DEBUGASSERT(randlen < sizeof(keyval));
if(randlen >= sizeof(keyval)) {
  free(randstr);
  return CURLE_FAILED_INIT;
}
strcpy(keyval, randstr);  // VULNERABLE!

技术分析

  • 输入:16字节随机数据
  • Base64编码:(16+2)/3*4+1 = 25字节
  • 缓冲区大小:40字节
  • 问题:strcpy()本质上不安全

CVSS评分:7.5(高)

CWE:CWE-120(经典缓冲区溢出)

影响

摘要:

  • CVSS评分:7.5(高)
  • 攻击向量:网络(AV:N)
  • 攻击复杂度:低(AC:L)
  • 所需权限:无(PR:N)
  • 用户交互:无(UI:N)
  • 范围:未改变(S:U)
  • 机密性:高(C:H)
  • 完整性:高(I:H)
  • 可用性:高(A:H)

安全影响:

  • 内存损坏:通过不安全的strcpy()导致缓冲区溢出
  • 栈/堆溢出:边缘情况下可能发生
  • 信息泄露:可能泄露内存内容
  • 远程代码执行:通过内存损坏
  • 拒绝服务:应用程序崩溃

可利用性:

  • 远程:是 - 通过WebSocket握手
  • 认证:无需认证
  • 用户交互:无需用户交互
  • 复杂度:中等 - 需要WebSocket协议知识

受影响用户:所有启用WebSocket支持的cURL用户

推荐修复

替换不安全的strcpy()为安全替代方案:

1
2
3
4
5
6
7
8
9
// Instead of:
strcpy(keyval, randstr);

// Use:
strncpy(keyval, randstr, sizeof(keyval) - 1);
keyval[sizeof(keyval) - 1] = '\0';

// Or better:
snprintf(keyval, sizeof(keyval), "%s", randstr);

时间线

  • 8小时前:aybanda向cURL提交报告
  • 8小时前:bagder(cURL工作人员)发表评论,要求解释strcpy()如何能复制超过keyval容量的字节
  • 7小时前:aybanda撤回报告,承认分析错误
  • 7小时前:bagder禁止该用户提交更多问题,称其违反AI垃圾规则
  • 7小时前:报告状态更改为"不适用"并关闭
  • 7小时前:bagder请求公开此报告
  • 7小时前:报告被公开

最终状态

报告被确认为误报,提交者被禁止继续提交问题。cURL团队确认边界检查if(randlen >= sizeof(keyval))实际上防止了缓冲区溢出,因此strcpy()的使用是安全的。

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