CVE-2023-24998 Apache Commons FileUpload 拒绝服务漏洞分析

渗透技巧 10个月前 admin
770 0 0

1

1

概要


Apache Commons FileUpload是Java中用来解析文件上传请求的基础库。在Servlet3.0之前的版本中,Servlet规范中并未定义获取multipart/form-data请求文件内容的API,因此一般会使用Commons FileUpload来解析上传的文件。从Servlet 3.0开始提供了getPart方法来获取上传的文件,在Tomcat7.0及以上版本对getPart的实现中(org.apache.catalina.connector.Request#parseParts),也是使用了Apache Commons FileUpload(修改Package后复制到Tomcat的项目中使用)。


近期Apache Commons FileUpload爆出CVE-2023-24998拒绝服务漏洞,该漏洞同样影响Tomcat,并且在Spring web项目下该漏洞更容易被利用,因此CVE-2023-24998影响非常广泛,本期对该漏洞进行分析。

2

漏洞简介


Apache Commons FileUpload在解析上传文件时,为了防止出现DOS漏洞,已经支持通过org.apache.commons.fileupload.FileUploadBase#setSizeMax方法限制Request body总大小。也支持通过org.apache.commons.fileupload.FileUploadBase#setFileSizeMax方法限制上传的单个文件大小。


但因为Commons FileUpload把上传请求解析为FileItem对象时,会额外占用不少的内存(例如DiskFileItem中的dfos里会创建一个1024大小的ByteArrayOutputStream)。所以上传空文件会十多倍的放大内存占用,并且可以在sizeMax内(Spring boot下默认10M)上传大量空文件(构造上传请求时因filename、Content-Disposition等原因,一个空文件需要74Byte,10M可以上传14空文件),Commons FileUpload对大量空文件循环解析时需要较多的时间,会耗费很多内存(10M的请求需要服务端几百M的内存)。当发送多个攻击请求时,会占满内存且GC无法释放,导致拒绝服务。


3

环境搭建


使用Spring Initializr 创建基础的Spring应用。Spring boot版本选择2.7.X,Packaging选择Jar,依赖中选择Spring Web和Spring Security(为了模拟业务应用有的认证鉴权)。点击Generate下载下来应用。

CVE-2023-24998 Apache Commons FileUpload 拒绝服务漏洞分析

解压下载的zip包后,把pom.xml中spring-boot-starter-parent的版本修改为2.7.7(该版本依赖的Tomcat是未修复漏洞的9.0.70。还可以不修改spring boot版本,直接在pom.xml中添加9.0.70版本Tomcat的依赖)

在IDEA中打开该项目即可。

CVE-2023-24998 Apache Commons FileUpload 拒绝服务漏洞分析

4

漏洞复现

为方便复现,在启动Spring boot应用时,先配置下启动时的VM options,添加-Xmx512M,限制该应用最多使用512M内存

CVE-2023-24998 Apache Commons FileUpload 拒绝服务漏洞分析

接着启动Spring boot应用。因为没有任何业务代码,所以启动后只有Spring security的登陆页面。并且因为有Spring security的认证,访问任意url时,都会被重定向到/login页面

CVE-2023-24998 Apache Commons FileUpload 拒绝服务漏洞分析

此时使用代码构造上传14空文件的请求(boundary设置为单个字符,节省空间。Content-Disposition、name、filename、Content-Type均不能省略),5个线程并发向8080端口的任意路径发送该上传请求,在请求中不需要携带登录后的cookie,几分钟后发现Spring boot应用出现异常

CVE-2023-24998 Apache Commons FileUpload 拒绝服务漏洞分析

此时刷新页面时,一直转圈,没有响应

CVE-2023-24998 Apache Commons FileUpload 拒绝服务漏洞分析


成功复现漏洞

5

漏洞分析
在上述漏洞利用过程中有3个值得分析的点
1:向一个不存在的接口上传文件,为什么Spring boot应用会解析上传文件导致拒绝服务?
2:明明已经有Spring security的认证鉴权了,为什么进行攻击时依然不需要认证就可以成功攻击?
3:为什么上传大量空文件会导致拒绝服务?

1漏洞分析 – 向一个不存在的接口上传文件,为什么Spring boot应用会解析上传文件导致拒绝服务?

在常规的Servlet应用中,若要在Servlet中调用getPart方法获取到上传的文件,需要先给该Servlet配置multipart-config(也可以通过MultipartConfig注解),所以若业务的Servlet中没有上传接口时,无法使用该漏洞进行攻击。


但在Spring boot应用中,会把所有的请求通过DispatcherServlet进行处理,在该Servlet中再根据请求URL的不同转发到不同的Controller。并且Spring为了在业务的Mapping接口中支持上传文件,自动给DispatcherServlet配置了multipart-config。也就是经过Spring boot包装后,每一个Spring boot业务从Servlet层面看来,都有一个ServletMapping为/的DispatcherServlet,并且该Servlet还配置了multipart-config。因此向任意url上传文件时都会解析上传的文件触发漏洞。


以下是相关代码的截图及说明:


下图是在spring-boot-autoconfigure中的MultipartAutoConfiguration,初始化了multipartConfigElement bean。

CVE-2023-24998 Apache Commons FileUpload 拒绝服务漏洞分析

下图是在spring-boot-autoconfigure中的DispatcherServletAutoConfiguration,会创建DispatcherServlet,并通过DispatcherServletRegistrationBean(extends ServletRegistrationBean)来自动把该Servlet注册到Servlet容器中。并且在创建registration时,还会把上面的multipartConfig设置到当前Servlet上

CVE-2023-24998 Apache Commons FileUpload 拒绝服务漏洞分析


2漏洞分析 – 明明已经有Spring security的认证鉴权了,为什么进行攻击时依然不需要认证就可以成功攻击

在FileUploadBase的parseRequest方法中下断点后,再次发送攻击请求,通过断点的调用栈可以看到是Spring security的CsrfFilter中调用getParameter时触发解析上传的文件

CVE-2023-24998 Apache Commons FileUpload 拒绝服务漏洞分析

org.apache.catalina.connector.Request#parseParts中可以看到,当Servlet中没有配置MultipartConfigElement时,如果allowCasualMultipartParsing配置为true,依然会生成新的mce来解析上传文件。否则就抛异常或者返回emptyList了。

CVE-2023-24998 Apache Commons FileUpload 拒绝服务漏洞分析

CsrfFilter中,查看filterChain的内容,可以发现CsrfFilter是在认证鉴权的FilterSecurityInterceptor之前的,因此在认证鉴权之前,CsrfFilter在getParameter时就触发了文件上传的解析。

CVE-2023-24998 Apache Commons FileUpload 拒绝服务漏洞分析

综上,只要在认证鉴权逻辑处理之前,有Filter调用到了getParameter方法,就会触发文件解析操作,最终造成拒绝服务漏洞。


3漏洞分析 – 为什么上传大量空文件会导致拒绝服务?

先讲空间原因,在恶意构造上传空文件时,单个空文件最小可以构造成如下内容,花费的请求流量为74Byte
--brnContent-Disposition:form-data;name=f;filename=arnContent-Type:arnrnrn
而Commons FileUpload把上述内容解析为DiskFileItem对象时,dfos属性的类型是DeferredFileOutputStream,而DeferredFileOutputStream中有一个大小为1024的比特数组,也就是说一个DiskFileItem对象至少占用1KB。
因此可以把请求流量至少放大14倍(1024/74)用来占用服务端的内存,1个10M大小的上传空文件请求,服务端在解析成
List<FileItem>时需要耗费至少140M内存。

CVE-2023-24998 Apache Commons FileUpload 拒绝服务漏洞分析


如果只是临时的new一些byte数组,快速使用后又被GC回收掉的话,也无法造成拒绝服务(各种GC算法的吞吐量都不会低)。但叠加时间原因后,就会真正造成拒绝服务了。


因为一个10M上传空文件的请求中可以包含14个空文件。Commons FileUpload在解析时会循环14次来创建DiskFileItem对象,一般也需要0.X秒才能完成。


在这0.X秒解析过程中,前面已经生成的DiskFileItem对象因后续还需使用(add到List中作为结果返回到外面),无法被GC回收。当并发的多个请求都在循环中new byte数组来创建DiskFileItem对象时,内存就不够了,并且此时多次Full GC也无法释放出内存。因此导致JVM抛出 “Java heap space”、“GC overhead limit exceeded”等异常。最终导致Tomcat服务挂掉。

6

漏洞修复
Apache Commons FileUpload的修复在参考链接[1],修复逻辑是在FileUploadBase中增加setFileCountMax,当调用该方法设置了单个请求允许上传的文件数量后,在循环解析成DiskFileItem时,若已解析的文件数量等于设置的值时,不再解析上传的文件,直接抛出FileCountLimitExceededException异常。但如果未调用setFileCountMax方法的话,依然会受该漏洞的影响。

Apache Tomcat的修复在参考链接[2],修复逻辑除了像Commons FileUpload一样添加了setFileCountMax方法外,还复用了Tomcat的maxParameterCount配置,把maxParameterCount – parameters.size()作为setFileCountMax的参数传入。因此升级Tomcat到9.0.71及以上版本后,就不会因为Tomcat中的FileUploadBase而触发该漏洞。

从业务角度来看该漏洞的修复

1:无论是外置还是内置的Tomcat,均需要升级到无漏洞版本(9.0.71及以上、8.5.85及以上、10.1.5及以上)

2:若依赖了Apache Commons FileUpload(无论主动还是被动),需要升级到1.5版本

3:若主动依赖了Apache Commons FileUpload,并且通过ServletFileUpload/FileUpload/FileUploadBase/PortletFileUpload/DiskFileUpload或其他继承了FileUploadBase的类来调用parseRequest/parseParameterMap/getItemIterator方法,则需要在调用这些方法之前先调用setFileCountMax方法来限制文件数量(调用isMultipartContent方法不会触发漏洞)

4:若主动依赖了Apache Commons FileUpload,并把multipartResolver bean配置为Spring的CommonsMultipartResolve,则在Spring中会使用Apache Commons FileUpload进行上传文件的解析(Spring的multipartResolver默认值为StandardServletMultipartResolver,会使用Servlet容器提供的方法去解析上传文件),因CommonsMultipartResolve并未提供方法/配置来给FileUpload配置fileSizeMax,因此要么弃用CommonsMultipartResolve,要么继承CommonsMultipartResolve后重写相关方法来调用setFileCountMax。

5:若因二方件或三方件引入了Apache Commons FileUpload,需要根据二方件/三方件使用Apache Commons FileUpload的代码来决定修复方式,总原则和上面的第三点一样,调用parseRequest/parseParameterMap/getItemIterator方法前需要调用setFileCountMax方法。已知的一些三方件的情况如下:


Struts:Struts中默认使用Commons FileUpload来解析上传的文件(struts.multipart.parser=jakarta),且不支持调用setFileCountMax方法。可以通过实现org.apache.struts2.dispatcher.multipart.MultiPartRequest接口来自定义上传文件的解析逻辑。

7

参考链接


[1]:Apache Commons FileUpload官方修复:(https://github.com/apache/commons-fileupload/commit/e20c04990f7420ca917e96a84cec58b13a1b3d17)

[2]: Apache Tomcat 9 修复:(https://github.com/apache/tomcat/commit/cf77cc545de0488fb89e24294151504a7432df74)

本公众号发布、转载的文章所涉及的技术、思路、工具仅供学习交流,任何人不得将其用于非法用途及盈利等目的,否则后果自行承担!

贴心提醒!
六、七月份终端云漏洞奖励翻倍活动近半,大家努力冲冲冲!
戳次条或下方链接获得活动详情
大家记得别忘了参与转发抽奖哦!
原文链接:终端云漏洞奖励翻倍活动 夏日冰爽到来!挖呀挖呀挖!

推荐阅读
终端云漏洞奖励翻倍活动 夏日冰爽到来!挖呀挖呀挖!
[漏洞分析] 使用chatGPT分析CVE-2023-0386 overlay内核提权
华为安全奖励计划介绍
Git CVE-2022-39253 漏洞分析与复现

点这里CVE-2023-24998 Apache Commons FileUpload 拒绝服务漏洞分析关注我们,一键三连~


原文始发于微信公众号(华为安全应急响应中心):CVE-2023-24998 Apache Commons FileUpload 拒绝服务漏洞分析

版权声明:admin 发表于 2023年6月28日 下午6:11。
转载请注明:CVE-2023-24998 Apache Commons FileUpload 拒绝服务漏洞分析 | CTF导航

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...