Skip to content

[BUG]通过 zmq.Socket.recv_pyobj 进行的隐式 Pickle 反序列化导致远程代码执行 (RCE) #784

Description

@kexinoh

HttpServerManager 类中,当服务配置为多节点模式 (args.nnodes > 1) 且节点 rank 大于 0 时,代码使用 zmq.PULL socket 绑定到 tcp://*:{args.multinode_httpmanager_port}。 这意味着该端口监听来自所有网络接口的连接,潜在地将其暴露给不受信任的网络。
lightllm/server/httpserver/manager.py

# 在 HttpServerManager.__init__ 中:
        if args.nnodes > 1:
            if args.node_rank == 0:
                # ... (rank 0 code)
            else:
                context = zmq.asyncio.Context(2)
                self.multinode_req_manager = context.socket(zmq.PULL)
                # VULNERABLE BINDING: Binds to all interfaces, potentially exposing to wider network
                self.multinode_req_manager.bind(f"tcp://*:{args.multinode_httpmanager_port}")
                logger.info(
                    f"HttpServerManager listening for child node requests on *:{args.multinode_httpmanager_port}"
                )

随后,在 loop_for_request 协程中,代码调用 self.multinode_req_manager.recv_pyobj() 来接收来自主节点(rank 0)或潜在的任何网络来源的数据。

# 在 HttpServerManager.loop_for_request 中:
        async def loop_for_request(self):
            assert self.args.node_rank > 0
            tasks = []
            self.request_order_queue = []
            while True:
                (
                    prompt,
                    sampling_params,
                    multimodal_params,
                    # VULNERABLE CALL: Implicitly uses pickle.loads() to deserialize received bytes
                ) = await self.multinode_req_manager.recv_pyobj()
                # ... (process received objects)

zmq.Socket.recv_pyobj() 方法在其内部实现中**隐式地使用 pickle.loads()**将接收到的字节流反序列化回 Python 对象。

安全风险:

pickle 模块对于反序列化来自不受信任来源的数据是不安全的。攻击者可以构造一个恶意的 pickle payload,当这个 payload 被 recv_pyobj() 内部的 pickle.loads() 处理时,会导致在服务器上执行任意代码。

结合 tcp://* 绑定,这使得任何能够访问运行非 rank-0 节点的服务器上指定端口 (args.multinode_httpmanager_port) 的攻击者,都有可能发送恶意 pickle 数据并获得远程代码执行能力。

复现步骤 (概念性):

  1. 以多节点模式启动服务 (args.nnodes > 1),确保至少有一个 rank 大于 0 的 HttpServerManager 实例运行。
  2. 确定 rank > 0 的节点正在监听的 IP 地址和端口 (args.multinode_httpmanager_port)。由于绑定的是 *,这通常是服务器的所有 IP 地址。
  3. 从一个可访问该 IP 和端口的攻击者机器,使用 ZMQ 连接到目标 socket。
  4. 攻击者使用 pickle.dumps() 创建一个包含恶意代码(例如,反弹 shell 或执行系统命令的类/函数)的 Python 对象,并将其序列化为字节流。
  5. 攻击者通过 ZMQ 连接将这个恶意的字节流发送给目标服务器。
  6. 服务器上的 recv_pyobj() 调用接收到恶意字节流,并(隐式地)使用 pickle.loads() 进行反序列化,从而触发恶意代码的执行。

影响:

成功利用此漏洞允许攻击者在运行易受攻击的 HttpServerManager 节点的服务器上以运行该服务进程的用户权限执行任意代码。这可能导致服务器被完全控制、数据泄露、服务中断等严重后果。

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions