S2-045 漏洞学习笔记
Problem It is possible to perform a RCE attack with a malicious Content-Type value. If the Content-Type value isn’t valid an exception is thrown which is then used to display an error message to a user.
描述中说明了,漏洞是通过 content-type
注入的,关键在于对错误信息并没有做妥善的处理。
又看到概述中说
Summary Possible Remote Code Execution when performing file upload based on Jakarta Multipart parser.
我有个疑问就是这不是文件上传的过程中出现的问题吗?那为什么 POC 直接使用 GET 请求,也不用上传文件就搞定了呢。
因为不熟悉 Struts 框架,所以我找文档简单的了解了一下。Big Picture
从这图来看所有请求都会在 Filter
和 Interceptor
间流转,最终到达相应的 Action
来处理。
大致流程
请求首先在 StrutsPrepareAndExecuteFilter
中被进一步封装:
request = prepare.wrapRequest(request);
wrapRequest
出自 PrepareOperations
:
然后进一步观察 request = dispatcher.wrapRequest(request);
中的 dispatcher
:
然后我明白了我之前的疑问,因为 POC 开头那句 #nike='multipart/form-data'
就是针对 content_type.contains("multipart/form-data")
的。而之前也提及了所有请求都会在 Filter
和 Interceptor
间流转,最终到达相应的 Action
来处理。所以 GET 请求也会经过文件上传的 Filter
。
然后是 MultiPartRequest mpr = getMultiPartRequest();
这个方法就是选择文件上传解析类用的了。如果没有配置默认就是
org.apache.struts2.dispatcher.multipart.JakartaMultiPartRequest
了。
回到 Dispatcher
中的 wrapRequest
方法。看到 request = new MultiPartRequestWrapper(mpr, request, getSaveDir(), provider, disableRequestAttributeValueStackLookup);
进一步查看 MultiPartRequestWrapper
类:
进一步查看 MultiPartRequestWrapper
调用的 JakartaMultiPartRequest
:
MultiPartRequestWrapper
会通过调用JakartaMultiPartRequest.java的parse进行解析请求,
一旦出错了就会调用 53 行的 buildErrorMessage
方法:
然后查看官方的修改记录https://github.com/apache/struts/commit/b06dd50af2a3319dd896bf5c2f4972d2b772cf2b
主要是去掉了 LocalizedTextUtil
的 findText
方法。查看了这个方法的注释,发现关键点:
于是乎最终在 FileUploadInterceptor
中调用 LocalizedTextUtil
的 findText
方法,该方法获取了 buildErrorMessage
中生成的内容,并最终执行了恶意的ONGL表达式。