ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Redis TLS握手UAF漏洞:NVD 9.8与官方7.5评分差异深度解析

Redis TLS握手UAF漏洞:NVD 9.8与官方7.5评分差异深度解析 凌晨两点多手机连着震了三次——不是业务报警是安全监控在刷屏Redis 官方发布安全公告修复了一个 TLS 连接处理中的 use-after-free 漏洞。我第一时间打开 NVD 页面9.8又打开 Redis 官方公告7.5。同一个 CVECVE-2024-31228同一个漏洞两家机构给出的严重性评分差了整整 2.3 分。这个场景这两年越来越常见NVD 的自动评分机制和厂商自评经常打架尤其像 Redis、Nginx 这类既是基础组件又有很清晰默认配置的中间件一旦出漏洞分数离谱是家常便饭。但是 9.8 对 7.5 这种差距确实值得掰开揉碎讲一讲。本文不打算复述一遍漏洞描述页而是把三件事讲透这个 use-after-free 到底发生在哪、NVD 为什么敢给满分档的高分、Redis 官方为什么坚持压到 7.5。如果你正在维护 Redis 集群或者经常被安全通告里的 CVSS 分数搞得一头雾水这篇应该能帮你省下不少排查时间。1. 先把漏洞讲明白TLS 握手失败路径上的一处内存回收事故1.1 一个连接对象的生命周期在哪一步出了岔子Redis 属于典型的单线程事件循环服务所有连接、命令解析、读写都在一个主线程里通过事件驱动处理。客户端连上来Redis 会创建一个connection结构体来管理这个连接的状态。如果开了 TLS这个连接对象还需要额外封装一层 SSL/TLS 上下文握手过程也是异步的客户端发 ClientHello服务端回 ServerHello然后交换证书、密钥协商最后才能进入正常的 Redis 命令协议阶段。这个漏洞就出在握手失败后的清理路径上。当 TLS 握手因为证书错误、协议版本不匹配、客户端提前断开等异常情况失败时Redis 会调用connClose()把这个连接关掉并且在大部分情况下会释放掉这个连接对象本身。问题在于错误处理路径上还有一些代码在connClose()执行完之后依然会去访问这个已经被释放的连接对象里的字段或者方法表指针。简单类比一下你退房之后房东把钥匙收了回去但保洁阿姨手里还拿着你房间的旧钥匙过一会儿又开门进去打扫了一遍。房间本身可能已经被改成了仓库阿姨还以为里面的人和物件都没变。在内存层面这就是典型的 use-after-free对象已经释放回堆管理器但还有一个悬空指针被继续使用。具体到 Redis 的 TLS 实现问题出在src/tls.c里对握手回调的错误处理分支。正常流程下connClose会触发资源回收但某些异常分支里连接对象被释放之后后续代码还会通过悬空指针访问conn-type这种成员。对攻击者来说如果能在释放之后准确控制这块内存的内容理论上就可以把函数指针劫持到自己的代码上。不过在实际攻击中大多数场景体现为服务崩溃——也就是拒绝服务——因为稳定地控制堆内存布局并不是一件容易的事。1.2 攻击者视角不需要密码只需要能碰到 TLS 端口这个漏洞最容易被误解的地方在于触发条件。很多人的第一反应是Redis 不是有密码认证吗不是有 TLS 客户端证书校验吗问题恰恰出在这里。TLS 握手发生在 Redis 应用层认证之前。攻击者根本不需要知道 requirepass 配置的密码也不需要拿到合法的客户端证书他只需要能建立 TCP 连接、能发送 TLS 握手报文就能触发漏洞。也就是说攻击面是纯粹的协议栈前置环节Redis 应用层的所有访问控制在这个阶段统统不起作用。从 CVSS 的角度看这直接决定了PR:N无需权限和UI:N无需用户交互这两项。攻击者不需要在目标系统上拥有任何账号也不需要诱导管理员点击什么链接或者执行什么操作只要网络层能到达 TLS 端口就可以尝试触发。也正因为这个漏洞处于认证之前的阶段它才在 NVD 的机器评分里拿到了非常高的攻击可行性分数。一个没有认证要求、可以远程触发、底层又是内存破坏类型的漏洞按照 CVSS 公式走很难不打到 8 分以上。1.3 官方补丁与受影响版本Redis 官方在 2024 年 4 月发布了修复版本主要覆盖 7.2.x 和 7.4.x 两个分支。修复的思路并不复杂在错误处理路径上调整释放顺序确保所有对连接对象的引用都在connClose()执行之前完成或者将连接对象标记为已关闭后立即从事件循环中摘除避免后续事件回调触碰到已释放的内存。受影响的版本范围大概是 7.2.0 到 7.2.3以及 7.4.0。修复版本是 7.2.4 和 7.4.1。如果你现在还在跑 6.2.x 或者 7.0.x需要单独检查官方的安全公告因为不同分支的维护策略不同有的分支在发布修复时可能已经进入 EOL停止维护阶段不会同步合入这个补丁。这里要提醒一句Redis 的版本号看着差别不大但修复动作是分分支各管各的别以为升级到任意一个新版本就万事大吉一定要对到具体版本号。2. NVD 的 9.8按“最坏情况”建模的机器评分2.1 CVSS 3.1 是怎么算分的要理解 9.8 分为什么出现得先搞清楚 CVSS通用漏洞评分系统3.1 的基础分公式。CVSS 分数并不是拍脑袋定的而是把漏洞的攻击特征量化成一组指标再套进固定公式里算出 0 到 10 的数值。核心指标有八个指标含义9.8 向量中的取值AV 攻击向量攻击者是通过网络、相邻网络、本地还是物理方式触发Network网络AC 攻击复杂度利用漏洞需要什么程度的特殊条件Low低PR 所需权限攻击者需要先拥有什么权限None无UI 用户交互是否需要受害者参与操作None无S 影响范围漏洞造成的危害是否影响组件之外Unchanged不变C 机密性影响是否造成数据泄露High高I 完整性影响是否造成数据篡改High高A 可用性影响是否造成服务不可用High高当攻击向量是网络、复杂度低、不需要任何权限和交互并且三个安全属性影响都是高时CVSS 3.1 公式算出来的结果就是 9.8。这也是很多严重漏洞的“标准套餐”远程、无认证、直接拿下系统。NVD 给 CVE-2024-31228 打的向量基本就是这一套它把 use-after-free 这种内存破坏漏洞放在了最坏假设里攻击者通过网络触发不需要密码不需要交互一旦利用成功可能造成机密性、完整性、可用性的全面损失。在 CVSS 的量化框架里这确实是“灾难级”漏洞的画像。2.2 NVD 为什么大胆地给了这么多满分项问题来了NVD 到底是怎么给一个漏洞打分的NVD 的核心职责是维护漏洞信息库它拿到 CVE 项之后会根据漏洞类型、公开的技术描述、参考链接等信息使用 NIST 定义的自动化和人工相结合的方式打 CVSS 基础分。关键点在于基础分只衡量漏洞本身的技术属性不考虑目标系统在真实环境中的部署情况、防御措施和业务影响。也就是说NVD 的 9.8 回答的是一个条件句如果攻击者能通过网络到达这个存在漏洞的接口如果这个接口被利用后内存破坏是稳定的如果目标没有额外的缓解措施——那么最坏情况下会造成全面危害。它不回答“你的 Redis 会不会被打穿”这个问题。NVD 手里没有你的资产清单不知道你 bind 的 IP 是多少也不知道你有没有开 TLS更不知道你的防火墙策略。能拿到的信息就是一个开源的、广泛使用的服务器软件在 TLS 握手阶段存在一个不需要认证就能触发的内存破坏漏洞。在 CVSS 的框架下这种描述天然就会映射到最高分档。从 NVD 的视角来看这不算激进反而是它的定位所在数据库要提供的是跨厂商、跨产品的统一严重性基准而不是针对每一家部署环境的定制化风险评估。2.3 9.8 的潜台词与局限性9.8 这个数字本身没有错错的是只拿一个数字做判断。我见过不少团队收到 NVD 告警后看到 9.8 就全员戒备要求所有 Redis 必须通宵升级。这种反应可以理解但往往忽略了一个事实9.8 分是“最坏情况建模”它的前提和你的生产环境大概率对不上。一个典型的例子是NVD 评分根本不考虑“该功能默认是否开启”。这个漏洞只在启用 TLS 端口时才能触发而 Redis 默认情况下 TLS 是关闭的默认端口还是 6379跑的是明文协议。如果你从来没有配置过tls-port你的 Redis 根本不监听 TLS 端口攻击者想通过网络触达这个漏洞第一步就失败了。但 NVD 不在乎这个。它的工作是回答“这个漏洞本身有多严重”而不是“你的环境里它有多容易被利用”。这两个问题经常被混为一谈也是这次评分争议的根源之一。另外CVSS 基础分在计算“影响范围 S”时把 S 设为 Unchanged意味着漏洞只能影响 Redis 自身进程。但 use-after-free 这种类型攻击者一旦实现任意代码执行影响的边界就远不止 Redis 进程本身了——他可以借 Redis 进程的权限横向移动。NVD 在这一点上其实已经做了“悲观处理”因为 S 如果设为 Changed分数会更高甚至可能到 10.0。所以某种程度上9.8 还不是 NVD 能给的最极端分数。3. 官方 7.5从真实攻击面出发的保守评估3.1 官方评分考虑的三个现实因素Redis 官方团队对自家这个漏洞的评分是 7.5。这个分数显然不是拍脑袋压下来的而是基于三个非常具体的因素评估出来的。第一个因素TLS 不是默认启用的。Redis 的默认配置里tls-port是 0也就是不监听任何 TLS 端口。要想暴露这个漏洞的攻击面运维人员必须显式开启tls-port、配置证书、密钥并且让客户端走 TLS 协议连接。这一步已经过滤掉了大量默认部署的实例。第二个因素Redis 默认绑定的是127.0.0.1。也就是说即使是默认监听端口 6379默认情况下也只允许本机访问外部网络根本到达不了。官方显然很清楚 Redis 的默认部署形态一个默认绑定回环地址、默认不开 TLS 的服务网络攻击面几乎不存在。第三个因素use-after-free 的实际利用稳定性。虽然 UAF 类型漏洞有升级为代码执行的可能性但在 Redis 这种单线程、事件驱动的服务里想稳定控制堆布局、绕过现代操作系统的内存防护ASLR、堆保护等难度并不低。官方团队见过大量实际崩溃报告知道这个 bug 在多数场景下就是让 Redis 进程直接 abort而不是被攻击者优雅地劫持控制流。综合这三个因素官方认为这个漏洞更适合被理解为一个“有条件触发的拒绝服务漏洞”而不是“公网无条件远程代码执行漏洞”。CVSS 的向量也因此显得谨慎很多。3.2 从向量推演 7.5 的由来既然是评分就绕不开向量。我们尝试反推一下什么样的向量组合能算出 7.5。CVSS 3.1 公式中其他条件不变只把攻击复杂度 AC 从 Low 调整为 High即AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H算出来的基础分大约是 7.5 左右。这符合官方评分的一个合理解释攻击路径依然是网络无需认证和交互影响依然是高大全但官方认为实际触发和利用这个漏洞的条件比 NVD 设想的要苛刻很多复杂度应该定为 High。另一种可能官方认为这个漏洞在机密性和完整性上的实际影响有限更多是可用性问题那向量会接近AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H但这个组合算出来达不到 7.5。所以更合理的推演是第一种AC 被拉高但其他影响项保持高位。两个评分的差异本质上就是“AC:L”和“AC:H”的区别也就是对“攻击者到底有多容易触发并利用这个漏洞”的判读差异。这不是数学错误而是对现实条件的两种不同理解。3.3 团队视角 vs 数据库视角用一句话概括这场争议NVD 在回答“最坏能怎么样”官方在回答“通常会发生什么”。这两个问题没有谁对谁错它们是不同决策场景下的不同工具。NVD 的分数适合做跨产品的优先级排序比如这个漏洞和其他十几个漏洞一起摆在面前先看谁官方的分数更适合做具体的漏洞响应决策比如我手上的 Redis 要不要立刻停机升级、能不能等到维护窗口。但这里有个陷阱官方评分低不代表你可以不修。7.5 在 CVSS 里依然是 High高风险档不是中低危。很多团队的负责人一看到“官方 7.5”就觉得“没那么严重”结果拖了几个月还停留在老版本上。这是对评分的另一种误读。4. 运维自救版本检查、修复升级、紧急缓解4.1 十秒定位当前环境状态不管评分怎么吵落地应对才是正事。第一步永远是确认自己到底是不是受影响的那个。在 Redis 服务器上执行redis-server --version或者进入命令行查看redis-cli INFO server看redis_version字段。如果你在 7.2.0 到 7.2.3 之间或者刚好是 7.4.0那基本确定在受影响范围内。版本在这一范围之外的也别立刻放松去官方安全公告页面核对一下是否有分支同步修复的补充说明。接下来确认 TLS 端口状态redis-cli CONFIG GET tls-port如果tls-port返回的是 0说明当前实例没有启用 TLS 端口。注意这并不代表你绝对安全——还要确认port配置是否被关闭、是不是有其他云平台或容器网络层面的端口映射。更稳妥的做法是检查实际监听端口ss -lntp | grep redis看有没有 0.0.0.0:6380 或者类似的非回环监听地址。凡是监听在非回环地址上的 TLS 端口都意味着攻击面真实存在。4.2 升级到修复版本编译与容器两种路径确认受影响之后最彻底的方案是升级到修复版本。这里给两条路径。源码编译升级的思路是这样# 下载修复版本源码 wget https://download.redis.io/releases/redis-7.2.4.tar.gz tar xzf redis-7.2.4.tar.gz cd redis-7.2.4 # 编译安装注意保留原有的配置参数 make BUILD_TLSyes MALLOClibc -j$(nproc) make install # 重启前备份配置和数据 cp /etc/redis/redis.conf /etc/redis/redis.conf.bak # 确认新版本 redis-server --version编译时BUILD_TLSyes一定不要漏否则新版可能不带 TLS 支持启动后反而报错。如果你用的是容器事情更简单docker pull redis:7.2.4Docker Compose 部署的话把镜像版本改掉然后重建services: redis: image: redis:7.2.4 command: [redis-server, /usr/local/etc/redis/redis.conf] ports: - 6379:6379 volumes: - ./redis-data:/data - ./redis.conf:/usr/local/etc/redis/redis.conf重建容器之前务必确认数据目录挂载是完整的并且先做一次BGSAVE拿到持久化文件备份。容器重建的瞬间 Redis 连接会断开有副本的集群建议先升级副本手动触发故障转移后再把原主节点升级回来能有效减少对业务的影响。4.3 暂时不能升级的缓解措施有些场景确实没法立刻升级比如 Redis 版本被某个商业组件写死、需要走繁琐的变更审批流程又或者业务高峰期不适合动缓存。如果不能马上升级至少要把下面几件事做完。把 TLS 端口限制在受信网络里。防火墙层面按来源 IP 做白名单而不是只依赖安全组# 只允许内网段访问 6379/6380 iptables -A INPUT -p tcp --dport 6379 -s 10.0.0.0/8 -j ACCEPT iptables -A INPUT -p tcp --dport 6379 -j DROP iptables -A INPUT -p tcp --dport 6380 -s 10.0.0.0/8 -j ACCEPT iptables -A INPUT -p tcp --dport 6380 -j DROP云环境里对应的是安全组规则在源地址里填具体的 VPC 网段或运维跳板机 IP不要把 0.0.0.0/0 放进来。如果业务上并不强制要求 TLS可以考虑临时把tls-port设置为 0将客户端流量切回内网明文协议同时用网络层策略严格限制来源。操作前确认内网链路可信度这个办法适合短期内快速收敛漏洞。开启监控告警重点盯 Redis 进程重启记录、异常崩溃日志和连接失败次数# 定期检查 Redis 日志中是否有 SIGABRT 或 TLS 错误 grep -iE SIGABRT|SSL|TLS|connection /var/log/redis/redis.log | tail -50使用 systemd 托管的话systemctl status redis里的活跃时间也能助攻判断是否有异常重启。有了告警至少能在被攻击的第一时间感知到而不是等业务侧反馈缓存全没了才想起排查。5. 评分争议背后安全工程师应该建立的三个认知5.1 评分是起点不是终点处理安全漏洞最大的坑就是只看分数不看上下文。CVE 页面上每个字段都有意义但信息密度有限。真正要做的是顺藤摸瓜先看官方安全公告的技术描述了解漏洞触发的具体条件再看补丁到底改了哪些文件、改动逻辑是什么如果条件允许下载修复版本源码 diff 一下搞清楚前因后果。以这次 Redis 的 UAF 为例你只要认真读一遍补丁涉及的tls.c代码就会立刻明白它只影响 TLS 握手失败路径跟普通命令执行八竿子打不着。这比盯着 9.8 还是 7.5 争论半天有价值得多。看懂根因之后判断就变得很自然我的环境开没开 TLSTLS 端口暴露给了谁有没有其他缓解措施这三个问题答案清晰了该不该升级、多紧急不需要任何评分数字来告诉你。5.2 厂商自评与第三方库评分的常见分歧模式NVD 和厂商评分打架这两年几乎是常态。总结几个常见模式分歧类型典型表现处理建议默认配置争议NVD 假设功能开启厂商考虑默认关闭以实际部署为准自查配置项利用复杂度争议NVD 按最坏情况给 Low厂商认为实际条件苛刻给 High阅读漏洞分析报告判断技术细节影响范围争议NVD 判 Confidentiality/Integrity 高厂商认为主要是 DoS关注是否有公开在野利用案例时间评分差异NVD 发布的初始分没有考虑漏洞被利用程度定期回看 NVD 页面的 CVSS 时间评分变动这里有一条经验值得分享厂商自评一般更贴近“技术事实”因为他们最了解自己产品的默认行为和代码路径NVD 的分数更适合用来做跨产品横向比较。真实的风险评估应该把两边分数都当作输入而不是二选一。5.3 建立自己的漏洞响应一小时工作流每次安全公告发布后与其临时抓瞎不如沉淀一份可执行的一小时排查单。前十五分钟确认资产是否受影响。查版本、查配置、查暴露面。把跑在内网和外网的所有 Redis 实例列出来标注版本、TLS 开关状态、监听地址。中间三十分钟评估业务影响。如果升级涉及多少依赖方有没有主从切换机制是否在业务低峰期如果只做缓解防火墙规则怎么加最稳妥最后十五分钟决策和留痕。记录这次漏洞的评估结论、临时措施、后续升级计划。哪怕最后决定“观察”也要写清楚为什么观察、观察多久、什么信号触发升级。这份记录在未来的审计和复盘里非常有用。这套流程看似简单真到半夜收到告警的时候能救不少命。我自己的习惯是把脚本写成一个check_redis_cve.sh一键输出所有实例的版本、端口、TLS 状态配合监控系统的告警推送随时可以快速评估。6. 常见问题速查与排错记录整理一些我在排查这类问题时被问得比较多的点希望能帮你少走弯路。问题可能原因处理方式NVD 显示 9.8官方只有 7.5到底该听谁的两个机构评分口径不同一个按最坏状况建模一个结合实际利用条件都参考最终以自己环境的实际暴露面为准Redis 没开 TLS还需要处理这个漏洞吗默认不监听 TLS 端口攻击面很小暂时可以低优先级处理但要防止以后启用 TLS 时遗忘升级到 7.2.4 后需要重启吗需要升级不是热替建议主从滚动重启先副本后主节点如何确认补丁真的生效只看版本号不够最好验证编译信息执行redis-server --version并确认版本号必要时连接测试 TLS 握手失败场景下进程是否稳定这个漏洞影响 Redis Cluster 吗影响面是连接对象和集群模式无关但集群节点之间的 TLS 通信同样在影响范围内集群环境要一并升级所有节点包括哨兵升级时遇到BUILD_TLSyes没配置后期能补吗编译时不带 TLS 支持运行时就无法启用 tls-port重新编译或改用官方带 TLS 支持的容器镜像有几个实际操作中的坑提一下。有次我在测试环境升级编译时忘了加BUILD_TLSyes启动后CONFIG GET tls-port直接报错说不支持该配置项。当时第一反应是配置文件语法错了排查半天才发现编译参数漏了。所以自己编译的朋友装完之后先跑一下redis-server --version看到输出里带 TLS 字样再继续。另一个常见问题是容器场景下镜像标签混乱。redis:7.2这种大版本标签在不同时间拉取可能对应不同的小版本最好直接锁定小版本标签比如redis:7.2.4-alpine或redis:7.4.1,避免在不知情的情况下拉到一个未修复的旧标签。还有一次客户环境用的 Redis 是云厂商托管的底层版本不透明。这种情况下没法自己改版本只能靠云厂商发布漏洞修复公告配合安全组的严格策略度过窗口期。如果托管实例可以重建也可以考虑用官方最新版自建实例替换但成本要评估清楚。写在最后评分争议不是偶然习惯它、用活它这次 Redis 的 TLS use-after-free 评分差异不是 CVSS 体系的 bug恰恰是这个体系正常运作的表现。NVD 负责给出一个脱离部署上下文的最大风险基线官方负责根据真实产品行为给出修正反馈而我们作为实际使用者真正的任务是把自己的环境信息填进这个模型里。我个人在实际操作中的做法是每次遇到厂商和 NVD 评分不一致都会顺手在本地把两个向量各自输入一遍 CVSS 计算器亲手算一下两个分数怎么来的。这个习惯帮我养成了对评分公式的直觉——看到向量里的 AC、PR、S 这几个关键项基本就能判断出评分的“脾气”。最后再分享一个小技巧如果某个公告让你纠结优先级试着把“分数”这个词从脑子里删掉换成三个问题——我的资产暴露了吗、漏洞能触达吗、最坏后果我能接受吗。这三个问题有了答案升级不升级、多紧急、先做哪一步根本不需要等别人告诉你。
返回列表