目录
前言
文件上传漏洞概述
文件上传功能背后的业务逻辑是什么
文件上传的安全风险
什么是文件上传漏洞
漏洞复现演示
后端实现
前言
这篇文章记录我搭建文件上传 MIME类型漏洞的环境,以及如何利用该漏洞进行攻击的过程。
文件上传漏洞概述
大部分站点都具有 文件上传功能 ,例如头像更改,文章编辑,附件上传等等
文件上传功能背后的业务逻辑是什么
- 文件上传的这个功能是如何实现的呢?
- 文件上传功能的作用是将?
本地文件上传至服务器上 进行保存。 - 当我们找到上传的入口,上传文件之后。
- 可能会回显文件上传的路径,如果回显了文件上传路径,那么我们就可以根据回显的文件上传路径进行访问,那么我们就可以在浏览器中访问到服务器上的这个文件。
文件上传的安全风险
- 假设文件上传功能没有对上传的文件进行限制,可能会引发哪些安全风险?
- 如果是对方是LAMP架构,是否能上传PHP的WebShell到服务端上,然后通过访问上传后的文件地址,从而执行WebShell中的代码。达到控制对方服务器的目的。
什么是文件上传漏洞
- 文件上传漏洞是指文件上传功能
没有对上传的文件做合理严谨的过滤 ,导致用户可以利用此功能,上传能被服务端解析执行的文件 ,并通过此文件获得执行服务端命令的能力 。
漏洞复现演示
前端界面
选择一个图片上传
存储目录中出现该图片
?试试上传其他类型的文件
上传失败 后端有对文件类型的检查
进行攻击 实现上传非法文件 抓包
修改Content-Type
发送包
成功上传非法文件?
后端实现
@Controller
public class UploadController {
private static final Logger LOGGER = LoggerFactory.getLogger(UploadController.class);
@GetMapping("/upload")
public String upload() {
return "upload";
}
@PostMapping("/upload")
@ResponseBody
public String upload(@RequestParam("file") MultipartFile file) {
if (file.isEmpty()) {
return "上传失败,请选择文件";
}
String fileName = file.getOriginalFilename();
String contentType = file.getContentType();
System.out.println("\tcontentType=" + contentType);
List<String> types = new ArrayList<String>();
types.add("image/jpeg");
types.add("image/png");
types.add("image/gif");
if (!types.contains(contentType)) {
return "上传失败!不允许上传此类型的文件";
}
String filePath = "C:\\Users\\liu\\Desktop\\spring-boot-upload\\src\\main\\resources\\static\\temp\\";
File dest = new File(filePath + fileName);
try {
file.transferTo(dest);
LOGGER.info("上传成功");
return "上传成功";
} catch (IOException e) {
LOGGER.error(e.toString(), e);
}
return "上传失败!";
}
?多文件上传实现
@GetMapping("/multiUpload")
public String multiUpload() {
return "multiUpload";
}
@PostMapping("/multiUpload")
@ResponseBody
public String multiUpload(HttpServletRequest request) {
List<MultipartFile> files = ((MultipartHttpServletRequest) request).getFiles("file");
String filePath = "/Users/itinypocket/workspace/temp/";
for (int i = 0; i < files.size(); i++) {
MultipartFile file = files.get(i);
if (file.isEmpty()) {
return "上传第" + (i++) + "个文件失败";
}
String fileName = file.getOriginalFilename();
File dest = new File(filePath + fileName);
try {
file.transferTo(dest);
LOGGER.info("第" + (i + 1) + "个文件上传成功");
} catch (IOException e) {
LOGGER.error(e.toString(), e);
return "上传第" + (i++) + "个文件失败";
}
}
return "上传成功";
}
|