CVE-2026-85295是任何知道这个默认值的未认证攻击者,都能伪造一个指向任意用户"

admin 2026-11-09 18:58:55 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

CVE-2026-85295 是任何知道这个默认值的未认证攻击者,都能伪造一个指向任意用户

原创

网络安全民工
网络安全民工

网络安全民工

2026年11月8日 15:26
北京

去阅读

核心结论:CVE-2026-85295 是 Chartbrew 5.2.3 之前版本中一个 CVSS 9.8 的认证绕过漏洞。其根源在于,代码中一个被注释为“未使用”的默认密钥 CB_SECRET,被遗留的 JWT 回退验证逻辑所接受。任何知道这个默认值的未认证攻击者,都能伪造一个指向任意用户 ID 的 HS256 令牌,从而完全绕过密码和双因素认证,接管账户。修复版本 5.2.3 已发布,但已使用默认密钥的部署在升级后,必须立即轮换 CB_SECRET 并作废现有会话。


一、漏洞定性:一个默认密钥,一条遗留的回退路径

Chartbrew 是一个开源的 BI 工具,能直接连接数据库和 API 来生成图表。CVE-2026-85295 的起因,是代码中一个被标记为“未使用”的默认密钥,被一段遗留的验证逻辑意外地接受了。

在 Chartbrew 的代码中,存在两把密钥:一把是实际用于签名会话 JWT 的 CB_ENCRYPTION_KEY,另一把是名为 CB_SECRET 的密钥。CB_SECRET 出现在项目的示例配置文件中,旁边注释写着“unused”(未使用)。但 GitHub 的安全公告指出,Chartbrew 的四个认证辅助函数——分布在 verifyToken.js、verifyUser.js、getUserFromToken.js 和 socketManager.js 中——在验证 JWT 时,会先尝试 CB_ENCRYPTION_KEY,如果失败,则回退到接受由 CB_SECRET 签名的令牌。

这意味着,只要部署时保留了默认的 CB_SECRET 值,这个“未使用”的密钥实际上就成了一把有效的备用钥匙。

项 值
漏洞类型 使用默认加密密钥(CWE-1394),导致认证绕过 / 账户接管
CVSS 3.1 9.8 Critical(AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H)
影响版本 Chartbrew < 5.2.3
修复版本 5.2.3
攻击入口 API 与 Socket 层的 JWT 验证
认证要求 无(攻击者只需知道默认的 CB_SECRET)
在野利用 未确认。不在 CISA KEV 中
公开 PoC 截至本文撰写时,未见公开的武器化利用代码

二、技术原理:HS256 的对称性与回退的致命组合

这个漏洞的危险性,来自 JWT 的 HS256(HMAC-SHA256) 算法特性和回退逻辑的组合。

HS256 是一种对称签名算法:签名和验证使用同一个密钥。这意味着,任何持有密钥的一方,都可以生成一个有效的签名。在 Chartbrew 的正常流程中,CB_ENCRYPTION_KEY 是这个对称密钥。但由于回退逻辑的存在,CB_SECRET 也获得了同等的签名效力。

攻击的步骤很简单:

  1. 获取密钥:攻击者从 Chartbrew 的公开示例配置或 Docker Compose 文件中,读取默认的 CB_SECRET 值。
  2. 伪造令牌:攻击者选择一个目标用户的 ID(通常可以通过用户列表或公开信息推断),用默认的 CB_SECRET 生成一个 HS256 签名的 JWT。这个令牌的 payload 中,sub 或 userId 字段指向目标用户。
  3. 提交令牌:攻击者将伪造的令牌作为 Bearer Token,发送给 Chartbrew 的 API 或建立 Socket 连接。回退逻辑在 CB_ENCRYPTION_KEY 验证失败后,用 CB_SECRET 验证成功,令牌被接受。

结果是:攻击者不需要目标用户的密码,不需要通过双因素认证,就能以目标用户的身份,在 API 和 Socket 层执行该用户权限内的所有操作。

IONIX 的威胁分析对此的总结很直接:“攻击向量是网络。不需要任何权限,也不需要用户交互。”

一个重要的边界:如果 Chartbrew 是以裸容器方式运行,且 CB_SECRET 环境变量完全未定义,则回退路径不会被触发。漏洞的暴露面,精确地落在那些保留了默认值,或使用了已知/弱 CB_SECRET 的部署上——包括从源码安装和从仓库 Docker Compose 部署的标准配置。


三、检测与排查:版本、密钥、会话三件事

3.1 Python 检测脚本(只读核对)

以下脚本仅做只读核对:检查 Chartbrew 的版本线索,并确认 CB_SECRET 是否仍为默认值。不发送任何伪造令牌,不尝试认证绕过。

#!/usr/bin/env python3# -*- coding: utf-8 -*-\"\"\"CVE-2026-85295 Chartbrew 只读检测用法: python check_chartbrew_cve_2026_85295.py https://chartbrew.example.com仅核对版本与 CB_SECRET 配置线索,不发送伪造令牌。\"\"\"import sysimport osimport reimport requestsimport urllib3urllib3.disable_warnings()
TIMEOUT = 10# 常见默认 CB_SECRET 值(来源:Chartbrew 示例配置 / Docker Compose)KNOWN_DEFAULT_SECRETS = {    \"change_to_random_string\",    \"your_secret_key\",    \"secret\",    \"changeme\",}
def check_version(base):    \"\"\"尝试从公开端点提取版本线索\"\"\"    for path in [\"/api/version\", \"/health\", \"/\"]:        try:            r = requests.get(f\"{base}{path}\", timeout=TIMEOUT, verify=False)        except requests.RequestException:            continue        m = re.search(r\"(\\d+\\.\\d+\\.\\d+)\", r.text)        if m:            return m.group(1)    return None
def check_env_secret():    \"\"\"检查本地环境变量或 .env 文件中的 CB_SECRET(仅限在目标主机上运行)\"\"\"    secret = os.environ.get(\"CB_SECRET\", \"\")    if secret:        if secret in KNOWN_DEFAULT_SECRETS or secret == \"change_to_random_string\":            return True, f\"环境变量 CB_SECRET 为默认/弱值: {secret}\"        return False, \"环境变量 CB_SECRET 已设置(非已知默认值)\"
    # 尝试读取常见 .env 文件    for env_path in [\".env\", \"../.env\"]:        if os.path.exists(env_path):            with open(env_path, \"r\", errors=\"ignore\") as f:                for line in f:                    if line.strip().startswith(\"CB_SECRET=\"):                        val = line.split(\"=\", 1)[1].strip().strip('\"').strip(\"'\")                        if val in KNOWN_DEFAULT_SECRETS or val == \"change_to_random_string\":                            return True, f\".env 文件中 CB_SECRET 为默认/弱值: {val}\"                        return False, \".env 文件中 CB_SECRET 已设置(非已知默认值)\"    return None, \"未能读取 CB_SECRET 配置(需在目标主机上运行或手动检查)\"
def main(base):    base = base.rstrip(\"/\")    print(f\"[*] 目标: {base}\")
    ver = check_version(base)    if ver:        print(f\"[*] 检测到版本线索: {ver}\")        parts = tuple(int(x) for x in ver.split(\".\")[:3])        if parts < (5, 2, 3):            print(f\"[!] 版本 {ver} < 5.2.3,受 CVE-2026-85295 影响\")        else:            print(f\"[+] 版本 {ver} >= 5.2.3,已修复此 CVE\")    else:        print(\"[*] 无法自动提取版本,请在 Chartbrew 管理界面或 package.json 中确认\")
    is_default, msg = check_env_secret()    if is_default is True:        print(f\"[!] {msg}\")        print(\"[!] 默认 CB_SECRET 与遗留回退路径组合,构成可利用的认证绕过\")    elif is_default is False:        print(f\"[*] {msg}\")    else:        print(f\"[*] {msg}\")
    print(\"\
[*] 本脚本不发送伪造令牌。修复优先级:升级到 5.2.3+,并轮换 CB_SECRET。\")
if __name__ == \"__main__\":    if len(sys.argv) != 2:        print(f\"用法: {sys.argv[0]} https://chartbrew.example.com\")        sys.exit(1)    main(sys.argv[1])

说明:脚本的版本检测依赖 Chartbrew 暴露的端点,可能因部署方式而异。密钥检查仅在目标主机上运行时有效;远程运行时需要人工审查部署配置。

3.2 Nuclei 模板(安全指纹版)

id: CVE-2026-85295-chartbrew-detect
info:  name: Chartbrew CVE-2026-85295 - Safe Version Fingerprint  author: security-research  severity: critical  description: |    探测 Chartbrew 版本线索。不发送伪造 JWT,不尝试认证绕过。    漏洞需要默认/已知的 CB_SECRET 与遗留回退路径组合才可利用。  reference:    - https://cvepremium.circl.lu/vuln/cve-2026-85295    - https://www.ionix.io/threat-center/cve-2026-85295/  classification:    cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H    cvss-score: 9.8    cwe-id: CWE-1394  tags: cve,cve2026,chartbrew,jwt,auth-bypass,detect
http:  - method: GET    path:      - \"{{BaseURL}}/api/version\"      - \"{{BaseURL}}/health\"
    stop-at-first-match: true    matchers:      - type: regex        part: body        name: version        regex:          - '(\\d+\\.\\d+\\.\\d+)'
    extractors:      - type: regex        part: body        name: detected_version        regex:          - '(\\d+\\.\\d+\\.\\d+)'        group: 1

运行方式:nuclei -t CVE-2026-85295-chartbrew-detect.yaml -u https://target

说明:模板仅做版本指纹。Nuclei 无法在不发送伪造令牌的前提下验证认证绕过,因此不宜用触发型模板对生产环境执行。

3.3 失陷排查:会话日志是核心信号

由于漏洞利用的是合法的 JWT 验证路径,日志中可能不会出现“认证失败”的异常。排查的重点是寻找不可能发生的会话:

  • Chartbrew 自身的登录日志:是否有来自异常地理位置、异常 User-Agent 的 API 或 Socket 请求,且携带了并非通过正常登录流程签发的令牌。
  • 密钥使用审计:如果 Chartbrew 或反向代理记录了 JWT 的签名密钥标识(kid),检查是否有令牌使用了 CB_SECRET 而非 CB_ENCRYPTION_KEY 签名。
  • 会话异常:是否有用户在未进行密码或双因素认证的情况下,出现了新的活跃会话。

四、修复与加固:升级、轮换、作废

4.1 升级到 5.2.3+

# 如果使用 npm / 源码部署npm install [email protected]
# 如果使用 Dockerdocker pull chartbrew/chartbrew:5.2.3

升级后,回退到 CB_SECRET 的验证路径已被移除,只有 CB_ENCRYPTION_KEY 签名的令牌会被接受。

4.2 轮换 CB_SECRET(升级后必须执行)

这是最容易被遗漏、但最关键的一步。升级本身不会改变已经存在的 CB_SECRET 值。如果一个部署之前一直使用默认的 CB_SECRET,那么:

  • 在升级前,这个默认值已经被攻击者知晓;
  • 在升级后,虽然回退路径被移除,但如果 Chartbrew 的其他功能(如分享令牌)仍然使用 CB_SECRET,默认值依然是一个弱点。

IONIX 的建议明确:“设置 CB_SECRET 为一个强且唯一的值。不要使用仓库或 Docker Compose 文件中的任何默认值。”

# 生成一个强随机值openssl rand -hex 32
# 更新环境变量或 .env 文件CB_SECRET=<新生成的随机值>

4.3 作废现有会话

由于漏洞允许伪造令牌,任何在修复前签发的令牌,都可能已经被攻击者掌握或伪造。升级和轮换密钥后,应使所有现有会话失效。IONIX 对此的表述是:“考虑轮换 CB_SECRET 并使现有会话失效,因为用已知密钥签名的令牌可以被伪造。”

Chartbrew 的具体会话作废机制可能涉及清除服务端的会话存储或更改 CB_ENCRYPTION_KEY。在变更密钥后,所有用户都需要重新登录,这是预期行为。


五、今晚的判断

CVE-2026-85295 的风险画像:CVSS 9.8、未认证、网络可达、利用逻辑简单(知道默认密钥 + 伪造 HS256 令牌),但它的可利用性精确地绑定在“是否保留了默认 CB_SECRET”这一个配置事实上。

行动顺序:

  1. 确认版本:低于 5.2.3 的 Chartbrew 实例,先标记为受影响。
  2. 检查 CB_SECRET:在目标主机上检查环境变量或 .env 文件。如果值仍是 change_to_random_string 或示例文件中的占位符,这个实例就是可利用的。
  3. 升级到 5.2.3+。这是关闭回退路径的唯一方式。
  4. 升级后立即轮换 CB_SECRET。升级不会自动更改密钥,默认值的历史暴露不会因为升级而消失。
  5. 作废现有会话。伪造令牌的窗口期是从“默认密钥被部署”到“密钥被轮换且会话失效”之间的全部时间。

一个被注释为“未使用”的密钥,一段遗留的回退代码,组合起来就是 CVSS 9.8。 修复的终点不是 npm install,而是让那个默认值真正不再被任何代码路径接受。

用DeepSeekHarness,学会造一个Harness" 网络安全文章

用DeepSeekHarness,学会造一个Harness"

本文详细介绍了DeepSeekHarness的使用方法,从认知、选教材、骨架、动手、拆解、复盘、踩坑、路线到收尾,全面解析了如何使用Harness来增强AI模型的实际应用能力,包括工具使用、上下文管理、权限控制、并行执行、观测和可学习性等方面。
评论:0   参与:  0