Nacos默认密钥漏洞实战:QVD-2023-6271攻击链深度解析
1. 从一次内部预警说起:为什么这个Nacos漏洞值得警惕
那天下午,公司安全部门的预警邮件准时弹了出来,标题赫然写着“QVD-2023-6271:Nacos身份认证绕过漏洞”。领导很快就把任务派了下来,要求我们团队立即评估风险并制定排查方案。说实话,刚看到“身份绕过”这几个字时,我心里咯噔一下。Nacos作为微服务架构里的“中枢神经”,一旦被攻破,意味着服务注册列表、配置信息这些核心资产可能全部暴露。更关键的是,这个漏洞的利用条件听起来有点“简单”——仅仅是因为一个默认的密钥没改。
我决定先在本地环境把它复现出来。老话说得好,知己知彼,百战不殆。只有亲手走一遍攻击者可能走过的路,你才能真正理解漏洞的杀伤力在哪里,防守的盲点又在何处。这个漏洞编号QVD-2023-6271,本质上是因为Nacos在默认安装后,使用了一个硬编码的、公开的JWT(JSON Web Token)签名密钥。攻击者不需要知道任何真实的用户名和密码,只需要用这个默认密钥,自己“伪造”一个合法的身份令牌(Token),就能骗过系统,直接进入后台管理界面。
这让我想起了很多历史安全事件,根源往往不是高深莫测的零日漏洞,而是这些“默认配置”留下的隐患。管理员安装完系统,觉得能登录进去就行了,很少会去翻看厚厚的配置文档,把那些默认的密钥、默认的密码改掉。攻击者恰恰就喜欢盯着这些“懒惰”留下的缝隙。所以,这次复现不仅仅是为了完成任务,更是想通过一个鲜活的案例,给所有运维和开发同学提个醒:默认不等于安全,开箱即用之后,安全加固的第一步必须跟上。
2. 漏洞核心原理拆解:默认密钥是如何打开后门的
要理解这个漏洞,我们得先搞明白Nacos是怎么管理用户登录状态的。它使用了JWT这种流行的无状态身份验证机制。简单来说,当你用正确的用户名密码登录后,Nacos服务器会用一个密钥(token.secret.key)生成一串加密的字符串(就是JWT Token),里面包含了你的身份信息和过期时间。之后,你每次访问后台,只需要在请求头里带上这个Token,服务器用同样的密钥验证一下签名是否有效、是否过期,就能确认你的身份,而无需每次都查数据库验证密码。
这个机制本身是高效且安全的,但安全性的基石完全在于那个密钥token.secret.key。如果这个密钥足够复杂且只有服务器自己知道,那么伪造Token几乎不可能。然而,问题就出在Nacos 2.2.0之前的版本中,这个关键的密钥在conf/application.properties文件里,是一个公开的默认值:
token.secret.key=SecretKey012345678901234567890123456789012345678901234567890123456789这相当于把自家大门的万能钥匙,直接贴在了门框上。任何能访问到Nacos界面(哪怕只是登录页面)的人,都可以通过查看前端源码或一些简单的信息收集手段,推测出这个默认密钥的存在。拿到这个密钥后,攻击者就可以扮演“令牌制造者”的角色。
JWT主要由三部分组成,中间用点号分隔:Header.Payload.Signature。其中Payload(载荷)是我们能操控的部分,我们可以在这里面声明:“我是nacos用户(sub字段),我的令牌在某个未来时间(exp字段)才过期”。然后用那个公开的默认密钥,对“头+载荷”进行签名,生成第三部分。最终,一个完全由攻击者伪造,但能被Nacos服务器成功验证的“合法”令牌就诞生了。服务器看到签名验证通过(因为密钥对得上),就会相信Payload里的声明,从而将攻击者识别为合法的nacos用户(这是一个内置的高权限用户),实现身份绕过。
这个漏洞的可怕之处在于它的“无交互性”。攻击者不需要进行暴力破解,不需要寻找SQL注入点,甚至不需要系统存在任何其他用户。他只需要一个公开的密钥和一个能构造JWT的工具(网上有很多在线网站),就能凭空创造一个高权限身份。这对于暴露在公网、且未做任何安全加固的Nacos实例来说,是致命一击。
3. 手把手搭建漏洞复现环境
光讲原理有点干,我们直接动手搭一个环境,把整个攻击过程跑通。这样你不仅能理解,还能自己验证和测试。
3.1 准备Java与Nacos漏洞版本
首先,你需要一个Java环境。Nacos依赖于JAVA_HOME这个环境变量,这一点很关键,只在Path里加Java路径是不行的。我习惯用JDK 11,比较稳定。安装完JDK后,务必在系统环境变量里新建一个JAVA_HOME,值就是你的JDK安装目录,比如C:\Program Files\Java\jdk-11.0.2。
接下来是重头戏:下载存在漏洞的Nacos版本。这个漏洞在Nacos 2.2.0版本中被修复,所以我们必须找2.2.0之前的版本。我复现时用的是2.2.0-RC版本,你可以从Nacos的GitHub Release页面找到2.1.0、2.0.4等历史版本。这里一定要注意,从官方或可信源下载,避免引入其他风险。
下载完成后,解压到一个方便操作的目录,比如D:\nacos。关键的配置文件在conf目录下,我们稍后会看到它。
3.2 启动Nacos并确认状态
启动非常简单。打开命令行,进入Nacos的bin目录,执行单机模式启动命令:
startup.cmd -m standalone如果你是Linux或Mac系统,对应的脚本是startup.sh。
看到命令行输出一堆日志,最后有“Nacos started successfully in stand alone mode”之类的字样,就说明启动成功了。这时,打开浏览器,访问http://localhost:8848/nacos,你应该能看到Nacos的登录界面。默认的用户名密码是nacos/nacos,但现在我们先不登录,因为我们要演示的是“绕过”登录。
到这一步,一个脆弱的、待宰的Nacos服务就已经在本地运行起来了。它使用的正是那个要命的默认密钥。我们可以通过检查conf/application.properties文件来确认,找到token.secret.key那一行,它应该和上面提到的那个默认值一模一样。
4. 锻造“万能钥匙”:构造绕过认证的JWT令牌
环境就绪,我们现在来扮演攻击者,制作那把能打开所有门的“万能钥匙”——伪造的JWT令牌。
4.1 准备Payload数据
JWT的Payload部分我们需要关注两个字段:
sub(Subject): 主题,这里我们填nacos。在Nacos的上下文中,这通常代表一个内置用户。exp(Expiration Time): 过期时间,必须是一个未来的时间戳(Unix时间戳,秒级)。
我们需要一个大于当前时间的时间戳。比如今天是2023年10月27日,我可以构造一个明天此时过期的时间戳。有很多在线网站可以帮你转换日期和时间戳,这里为了方便,我用Python快速算一个:
import time future_time = int(time.time()) + 86400 # 当前时间戳加一天(86400秒) print(future_time)假设我们得到的时间戳是1698412800。
所以,我们的Payload数据就是:
{ "sub": "nacos", "exp": 1698412800 }4.2 使用默认密钥签名
现在,我们需要用Nacos的那个默认密钥,对这个Payload进行签名。手动计算HMAC SHA256签名太麻烦,我们利用现成的工具。强烈建议在断网的虚拟机或隔离环境中操作这些在线工具,避免敏感信息泄露。
打开一个JWT在线构造网站(例如 jwt.io)。在界面中:
- 在“PAYLOAD: DATA”部分,粘贴上面的JSON。
- 在“VERIFY SIGNATURE”部分,把算法选为
HS256。 - 在密钥输入框里,填入Nacos的默认密钥:
SecretKey012345678901234567890123456789012345678901234567890123456789。
你会发现,随着你填入密钥,左侧“Encoded”框里的JWT字符串瞬间发生了变化,生成了一个新的第三部分(签名)。最终,你会得到一串像这样的Token:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJuYWNvcyIsImV4cCI6MTY5ODQxMjgwMH0.4qk8pV7P6rRlC3xY1Z2A3bB4cD5eF6gH7iJ8kL9mN0oP(注意:这只是示例,实际生成的签名部分会不同)
这串字符就是我们的“万能钥匙”。它被分成了三段,用点连接。服务器拿到后,会用同样的默认密钥对前两段重新计算签名,如果计算结果和第三段一致,就认为令牌是合法的,并相信Payload里的内容:你是nacos用户,令牌还没过期。
5. 发起攻击:利用Burp Suite篡改请求完成绕过
钥匙有了,现在我们去开门。这里我们用Burp Suite这个安全测试神器来拦截和修改流量,模拟攻击过程。如果你没有Burp,用其他能修改HTTP请求的工具(如Postman)也可以,但Burp的拦截和重放功能更直观。
5.1 配置代理与拦截登录请求
首先,确保你的浏览器配置了代理,指向Burp Suite(默认127.0.0.1:8080)。然后,在Burp中打开“Proxy” -> “Intercept”选项卡,确保拦截是开启的。
回到浏览器,访问Nacos登录页面 (http://localhost:8848/nacos/index.html)。在登录框中,随意输入一个用户名和密码,比如attacker和hack123,然后点击登录。这个操作的目的不是为了登录成功,而是为了产生一个我们可以拦截的登录请求。
此时,请求会被Burp Suite截获。你应该能看到一个POST请求,发往/nacos/v1/auth/users/login,内容大概是username=attacker&password=hack123。
5.2 植入伪造的Token并获取Cookie
这是最关键的一步。我们不需要修改这个登录请求的参数,而是要在请求头里“声明”我们已经有合法的身份了。在Burp的拦截界面,找到请求头部分,手动添加一个Authorization头:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJuYWNvcyIsImV4cCI6MTY5ODQxMjgwMH0.4qk8pV7P6rRlC3xY1Z2A3bB4cD5eF6gH7iJ8kL9mN0oP把Bearer后面的部分替换成你在上一步自己生成的JWT Token。
然后,点击“Forward”放行这个请求。服务器收到这个请求后,会先检查Authorization头。它发现有一个JWT Token,于是用默认密钥去验证。验证通过!服务器认为这是一个带着合法令牌的请求,于是它不会再去校验username和password字段,而是直接根据Token里的sub字段(nacos)为你创建登录会话。
在Burp的“HTTP history”里找到这个请求的响应。如果一切顺利,你会在响应包里看到一个Set-Cookie头,里面包含了一个JSESSIONID。这就是服务器给你下发的会话Cookie,标志着你已经“登录”成功了!把这个Cookie的值复制出来。
5.3 绕过登录进入后台
现在,你已经拥有了一个有效的会话。关闭Burp的拦截功能,或者直接关闭代理设置,让浏览器恢复正常访问。然后,打开一个新的浏览器标签页,访问Nacos首页http://localhost:8848/nacos。
这时,浏览器会跳转到登录页。别急,我们需要让浏览器使用我们刚刚获得的那个Cookie。这里有两种方法:
- 使用浏览器开发者工具:按F12打开控制台,进入“网络”(Network)选项卡,刷新页面。在第一个请求(通常是
index.html)上右键,选择“编辑并重发”(Edit and Resend)。在请求头中添加Cookie: JSESSIONID=你刚才复制的值,然后发送请求。 - 使用浏览器插件:安装可以编辑Cookie的插件(如EditThisCookie),直接将当前站点的
JSESSIONID值修改为我们获取到的那个。
修改Cookie并刷新页面后,神奇的事情发生了:你没有输入正确的nacos/nacos密码,甚至没有输入我们伪造请求时用的attacker/hack123,但页面直接跳过了登录界面,进入了Nacos的管理后台!你可以看到完整的服务列表、配置管理、命名空间等所有功能模块。这意味着攻击者已经获得了与nacos管理员同等的权限,可以随意注册恶意服务、篡改关键配置,对整个微服务体系造成毁灭性打击。
6. 漏洞的深度利用场景与潜在危害
成功绕过登录进入后台,只是攻击的开始。在一个真实的攻击场景中,攻击者会利用这个后台权限做很多事情,每一样都可能给业务带来严重损失。
第一,服务注册与劫持。在“服务管理”页面,攻击者可以注册一个恶意的服务实例,指向他控制的服务器IP和端口。如果公司的服务消费者没有严格的服务校验机制,流量就可能被引导到攻击者的服务器上,导致数据泄露、中间人攻击或服务瘫痪。更隐蔽的做法是,修改一个现有健康实例的元数据或IP地址,进行流量劫持。
第二,配置信息窃取与篡改。这是危害最大的地方。在“配置管理”页面,Nacos存储着所有微服务的配置文件,数据库连接串、Redis密码、第三方API密钥、业务开关等敏感信息一览无余。攻击者可以直接导出这些配置,获取整个系统的核心机密。他还可以修改配置,比如将数据库连接指向一个恶意地址,或者开启某个隐藏的后门功能开关,这种破坏往往是静默且深远的。
第三,命名空间与集群破坏。攻击者可以创建或删除命名空间,扰乱服务的隔离环境。他也可以操作集群节点,如果权限足够高,甚至可能通过后台接口执行一些系统命令,从而在服务器上获得一个命令执行shell,将攻击面从应用层延伸到宿主机层。
我印象很深的一次内部演练,我们利用这个漏洞,在测试环境里仅仅花了10分钟,就“接管”了整个微服务配置中心,并模拟篡改了支付服务的回调地址配置。这要是发生在生产环境,后果不堪设想。这个漏洞之所以被定为高危,正是因为它提供了一个直达核心管控平台的捷径,后续的利用方式多种多样,完全取决于攻击者的想象力。
7. 企业级防御方案与加固实践
复现漏洞是为了更好地防御。对于企业安全团队和运维人员来说,绝不能止步于了解攻击过程,必须立刻行动起来,检查并加固自己的Nacos实例。
立即检查与修复(治标):
- 升级!升级!升级!这是最根本、最有效的解决方案。请立即将Nacos升级到2.2.0或更高版本。新版本不仅修复了默认密钥问题,还增强了其他安全特性。
- 修改默认密钥。如果因客观原因无法立即升级,必须立刻修改
token.secret.key。打开conf/application.properties文件,找到token.secret.key这一行,将其值修改为一个足够复杂、随机且足够长的字符串(建议使用密码生成器生成64位以上的随机字符串)。修改后,必须重启Nacos集群所有节点才能生效。 - 检查暴露面。立即通过网络扫描或资产梳理,检查是否有Nacos管理界面被错误地暴露在公网(8848端口)。任何中间件的管理后台都不应直接对公网开放。
构建纵深防御体系(治本):
- 网络隔离。将Nacos服务器部署在内网,严格通过VPN或堡垒机进行访问。如果微服务需要跨网络访问,应通过专线或安全的API网关进行代理,而不是直接暴露Nacos服务端口。
- 启用认证与授权。除了修改默认密钥,务必在
application.properties中启用完整的鉴权体系(nacos.core.auth.enabled=true),并为不同运维人员创建独立的账号,分配最小必要权限,避免全部使用nacos这个超级管理员。 - 配置定期巡检与漏洞扫描。将Nacos等基础组件纳入统一的安全配置基线管理,定期检查配置文件中的默认密码、弱密码、不必要的端口开放等情况。使用漏洞扫描器定期对内部服务进行扫描,及时发现类似QVD-2023-6271的已知漏洞。
- 日志审计与监控。开启Nacos的访问日志和操作日志,并接入公司的SIEM(安全信息和事件管理)系统。特别关注异常登录行为(如非办公时间、陌生IP地址登录)、大量的配置查询或修改操作。设置告警规则,一旦发现可疑行为立即通知安全人员。
安全是一个持续的过程,而不是一次性的任务。这个漏洞给我们最大的教训就是:默认配置是安全的敌人。无论是Nacos、Redis、Elasticsearch还是其他任何中间件,在投入生产环境之前,请务必花时间阅读官方安全文档,完成最基本的安全加固。有时候,攻破一个系统的,往往不是最高明的黑客技术,而是一个被所有人忽视的、写在默认配置文件里的秘密。
