Java代码审计之文件上传

一、任意文件上传漏洞

​ 任意文件上传漏洞常发生在文件上传功能中,由于后端代码中没有严格限制用户上传的文件,导致攻击者可以上传带有恶意攻击代码的JSP 脚本到目标服务器,进而执行脚本,以达到控制操纵目标服务器等目的。

1.1 SpringBoot JSP 的限制

现在大多数项目都是基于SpringBoot架构进行的开发,官方不建议 SpringBoot 使用 JSP,并且做了一些限制。(SpringBoot 默认不解析JSP文件)

如果想要使用JSP也可以,需要引入相关依赖,自建WEB-INF,web.xml等操作,这样一通操作下来失去了 SpringBoot的一些特性。当然这也仅是一部分原因。

我们在对SpringBoot项目审计时如果想要查看是否对JSP完全解析,可以从熟悉的 pom.xml 文件下手,查看是否引入了相关依赖

1
2
3
4
5
6
<!--用于编译jsp-->
<dependency>
   <groupId>org.apache.tomcat.embed</groupId>
   <artifactId>tomcat-embed-jasper</artifactId>
   <scope>provided</scope>
</dependency>

二. 校验文件类型

2.1 文件后缀名校验

这里我们主要关注后端是否对上传的文件后缀名进行了检查判断。如果在后端对后缀名没有限制。那么就极有可能存在任意文件上传漏洞。很多项目是通过前端限制文件上传类型。但我们都知道,不论前端怎么限制,我们都可以通过抓包的方式修改后缀为敏感文件,以达到上传Webshell的目的。

2.2、文件后缀名校验黑白名单

如果后端使用了黑白名单限制后缀名已经初步起到了一定的防护作用。但具体还需要根据实际情况分析。如果是黑名单是否存在遗漏的情况。我会使用模糊字典Fuzz后缀名,看看是否能绕过。

2.3、MIME type 检测

校验文件类型还有一种方式检测MIME Type。也就是我们在请求中常见的 Content-Type 字段。如果项目中使用MIME type黑白名单检测文件类型,可以分析黑白名单中是否有遗漏的敏感文件类型。

2.4 文件名操作

在这里我们关注上传的文件名是否有所改动。

常见的情况是后端直接接受保存我们上传的文件名。

但也常后端自定义不可预测的文件名,比如使用 。比如以下代码

1
2
3
4
String originalFileName = file.getOriginalFilename();
String extension = originalFileName.substring(originalFileName.lastIndexOf('.'));
String fileName = UUID.randomUUID() + extension;
//UUID.randomUUID() 随机值

2.5 保存路径

在这里我们关注是否保存在本地,保存文件路径是否是在非解析路径,保存路径是否可控。

2.6 是否保存在本地

现在很多项目可以说是都在向云服务器迁移,并且对数据,文件做了隔离。不同的的场景应用不同的存储服务器。

后端在对上传文件保存时无非要么是保存在服务器本地,要么保存在相关云存储服务器。比如:七牛云OSS,阿里OSS等等。如果保存在了OSS上,尽管上传了敏感Webshell脚本,也是无法执行的。

2.7 是否解析路径

判断目录是否可以解析 JSP 文件,进而造成了任意文件上传漏洞。

2.8 路径是否可控

在获取文件名后,大多会进行路径拼接操作。

在这里我们可以检查拼接路径是有相关防护,如果没有限制 ../ 那么极有可能存在目录穿越漏洞。如果保存图片的地址是非解析目录,我们可以配合目录穿越漏洞操作WebShell存储到其他地方,尝试执行。

FileUploadDemo项目中路径使用了直接拼接的方式,并且没有任何防护,代码如下:

1
2
String fileName = file.getOriginalFilename();
String filePath = path + fileName;

可以启动运行该项目自行调试,将上传的文件名改为 ../../../../../../../test.txt 后观察结果。

三. 文件上传关键字

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
File
MultipartFile
MultipartRequestEntity
FileUpload
FileUploadBase
FileItemIteratorImpl
FileItemStreamImpl
FileUtils
UploadHandleServlet
FileLoadServlet
FileOutputStream
DiskFileItemFactory
MultipartRequestEntity
MultipartFile
com.oreilly.servlet.MultipartRequest
......

3.1 JSP木马

JSP木马也叫作Java WebShell,代码使用JSP(Java Server Pages)编写,只不过是在代码中加入了一些操作文件,访问系统等功能,也就成为了我们口中的JSP木马

四. 任意文件上传漏洞修复

1
2
3
4
5
6
7
8
9
10
11
12
列出允许的扩展。只允许业务功能的安全和关键扩展
确保在验证扩展名之前应用输入验证。
验证文件类型,不要相信Content-Type头,因为它可以被欺骗。
将文件名改为由应用程序生成的文件名
设置一个文件名的长度限制。如果可能的话,限制允许的字符
设置一个文件大小限制
只允许授权用户上传文件
将文件存储在不同的服务器上。如果不可能,就把它们存放在webroot之外。
在公众访问文件的情况下,使用一个处理程序,在应用程序中被映射到文件名(someid -> file.ext)。
通过杀毒软件或沙盒(如果有的话)运行文件,以验证它不包含恶意数据。
确保任何使用的库都是安全配置的,并保持最新。
保护文件上传免受CSRF攻击

五.补充:

如果本地代码无法执行某项特定的功能(比如在登陆后才能进行代码的审计,可以使用远程调用API的方法)

1.远程代码 (action:明确了表单数据的发送目的地)

1
2
3
4
5
<form action="http://localhost:8080/video/uploadvideo"  enctype="multipart/form-data" id="frmUpload" method="post">
<input name="uploadfile" type="file">
<input type ="text" name = "fileType" value="">
<input id="btnUpload" type="submit" value="上传">
</form>

2.部署在apache服务里面,进行上传文件

六. 实战:

对于 SpingBoot项目 来说,想要SpringBoot内嵌的Tomcat对JSP解析,一定要引入相关依赖。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!-- Jsp compatible-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.taglibs</groupId>
<artifactId>taglibs-standard-impl</artifactId>
<version>1.2.5</version>
</dependency>

对于很多SpringBoot项目来说,是无需引入解析JSP依赖的。那么对于任意文件上传漏洞来说,上传JSP,木马肯定是没有办法解析的。对于任意文件上传漏洞利用,只能通过内存马等方式进行攻击了。

补充:UUID+extension 方式(是随机命名文件)

方式一:没有做任何的过滤,上传jsp文件

(修改成符合要求的后缀名,在通过bp进行改包)

1
2
1.1 改filename后縀名为 .jsp
1.2 Content-Type: text/plain

获取文件路径:

getshell:


Java代码审计之文件上传
http://example.com/2025/06/07/Java代码审计之文件上传/
作者
XCDH
发布于
2025年6月7日
许可协议