初始信息
已知export/excel端点具有sql注入,先使用jadx反编译,全局搜索export/excel,找到com/fr/nx/app/web/v9/handler/handler/largeds/LargeDatasetExcelExportHandler.class
官方文档: https://help.fanruan.com/finereport/doc-view-2597.html
@override 基类的handle方法
protected void doHandle(HttpServletRequest var1, HttpServletResponse var2, String var3) throws Exception {
TemplateSessionIDInfo var4 = (TemplateSessionIDInfo)SessionPoolManager.getSessionIDInfor(var3, TemplateSessionIDInfo.class);
Calculator var5 = this.getCalculatorFromPara(var1, var2, var3);
try {
WorkbookDataCreator var6 = this.initCreator(var5, var1, var2, var4);
DirectExcelExportPool.getInstance().export(var6, var2.getOutputStream());
MetricRegistry.getMetric().submit(FocusPoint.newBuilder().id("function_plugin_com.export.ds").text(var4.getRelativePath()).source(Original.EMBED).username(var4.getWebContext().getUserName()).ip(WebUtils.getIpAddr(var1)).build());
} finally {
ExportSessionManager.getInstance().removeExportSession(var3, "excel");
}
}
private Calculator getCalculatorFromPara(HttpServletRequest var1, HttpServletResponse var2, String var3) {
TemplateSessionIDInfo var4 = (TemplateSessionIDInfo)SessionPoolManager.getSessionIDInfor(var3, TemplateSessionIDInfo.class);
if (var4 != null) {
Calculator var5 = var4.createSessionCalculator(var1, var2); //跟入发现request未使用
var5.pushNameSpace(ParameterMapNameSpace.create(WebUtils.parameters4SessionIDInfor(var1))); // 收集request中的参数信息到一个hashMap里,方便后续统一调用
return var5;
} else {
return null;
}
}
private WorkbookDataCreator initCreator(Calculator var1, HttpServletRequest var2, HttpServletResponse var3, TemplateSessionIDInfo var4) throws Exception {
String var5 = WebUtils.getHTTPRequestParameter(var2, "__parameters__");
Map var6 = this.getParamsMap(var5);
// Json格式解析__paraemters__参数
LargeDatasetExcelExportJavaScript var7 = this.getEntity(var2);
// 获取http请求中params参数作为xml字符串生成xml(已过滤外部实体注入) 其中会根据输入的xml为JavaScript对象赋值。
// 映射如下 xml->javascript_obj : {exportFilename:filename,dsName:DsName,colNames:ColNamesMap}
String var8 = var7.getFileName();
String var9 = var7.getDsName();
LinkedHashMap var10 = var7.getColNamesMap();
// 以上变量均可控
DirectExcelExportModel var11 = new DirectExcelExportModel();
TableDataSource var12 = var4.getTableDataSource();
if (StringUtils.isNotEmpty(var8) && var8.startsWith("=$")) {
var8 = (String)var6.get("__filename__");
}
// var8可控
if (StringUtils.isEmpty(var8)) {
var8 = getDefaultFileName(var2, var4, var9);
} else if (var8.endsWith(".xlsx")) {
var8 = var8.substring(0, var8.lastIndexOf(".xlsx"));
} // 文件名处理,无视
this.setRes(var3, Browser.resolve(var2).getEncodedFileName4Download(var8));
// 设置response body参数
var11.setDataSource(var12);
var11.setSessionID(var4.getSessionID());
if (StringUtils.isEmpty(var9)) {
throw new Exception("No datasource name specified for exportation.");
} else {
var11.setDsName(var9);
this.dealParam(var11, var1, var7, var2, var4, var6); //往下看
if (!var10.isEmpty()) {
var11.setColNamesMap(var10);
}
return WorkbookDataCreator.build(var11); // 根据模型查表,构建数据导出
}
}
private void dealParam(DirectExcelExportModel var1, Calculator var2, LargeDatasetExcelExportJavaScript var3, HttpServletRequest var4, TemplateSessionIDInfo var5, Map<String, Object> var6) throws UtilEvalError {
String var7 = WebUtils.getHTTPRequestParameter(var4, "functionParams");
Map var8 = this.getParamsMap(var7); // 可控Map
ParameterProvider[] var9 = var3.getParameters();
ParameterMapNameSpace var10 = ParameterMapNameSpace.create(var9);
NameSpace var11 = SessionIDInfo.asNameSpace(var5.getSessionID());
this.addNameSpace(var4, var2, var11, var10);
Parameter[] var12 = Parameter.providers2Parameter(var9);
LinkedHashMap var13 = new LinkedHashMap(16);
for(Parameter var17 : var12) {
Object var18 = var6.get(var17.getName());
if (var18 != null) {
var13.put(var17.getName(), var18);
} else {
JSONObject var19 = (JSONObject)var8.get(var17.getName());
if (var19 == null) {
if (var17.getValue() instanceof Formula) {
Object var24 = var2.evalValue(String.valueOf(var17.getValue()));
var13.put(var17.getName(), var24);
} else {
Object var25 = var17.getValue();
var13.put(var17.getName(), var25);
}
} else {
String var20 = String.valueOf(var17.getValue());
Map var21 = var19.toMap();
for(Map.Entry var23 : var21.entrySet()) {
var20 = var20.replaceAll("\\$" + (String)var23.getKey(), "\"" + var23.getValue().toString() + "\"");
}
Object var26 = var2.evalValue(var20);
var13.put(var17.getName(), var26);
}
}
}
var1.setParameters(this.dealWithAuthParam(var13, var5));
}
com/fr/io/exporter/excel/direct/WorkbookDataCreator.class
private void init() throws Exception {
if (this.model != null) {
TableData var1;
if (this.model.getDataSource().getTableData(this.model.getDsName()) != null) {
var1 = this.model.getDataSource().getTableData(this.model.getDsName());
} else {
var1 = TableDataAssist.getTableData(this.model.getDataSource(), this.model.getDsName());
}
if (var1 instanceof DBTableData) {
this.tableData = (DBTableData)var1;
Calculator var3 = Calculator.createCalculator();
NameSpace var4 = this.prepareParameterNameSpace(var3);
String var2 = this.renderSql(var3, var4);
Connection var6 = ((DBTableData)var1).getDatabase();
if (var6 instanceof NameDatabaseConnection) {
var6 = ((NameDatabaseConnection)var6).createDatabase();
}
String var7 = this.model.getExportFormat();
String var5 = this.model.getEncodeFormat();
this.option = new WorkbookDataCreatorOption(var2, var6, this.prepareColumnNames(), var7, var5);
} else if (var1 == null) {
throw new Exception("[LARGE DATA EXPORTER]tableData is null");
} else {
throw new Exception("[LARGE DATA EXPORTER]" + var1.getClass().getSimpleName() + " is not support to export by this way!");
}
}
}
implements\s+TableDataSource 全局搜索实现接口,也没发现数据库连接,等有空再看看。