s2-045分析

前提需要了解下Struts2的运行机制

(1) Struts2的核心是一个Filter,Actionfff可以脱离web容器,那么是什么让http请求和action关联在一起的?

(2)Struts2默认使用的是StrutsPrepareAndExecuteFilter类来替代FilterDispatcher类

(3)创建一个Struts2工程,默认使用这个过滤器,并生成如下配置
f1. <* filter *>
2. <* filter-name *> struts2 </* filter-name *>
3. <* filter-class *> apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter </* filter-class *>
4. </* filter *>
5. <* filter-mapping *>
6. <* filter-name *> struts2 </* filter-name *>
7. <* url-pattern *> /\ </* url-pattern **>
8. </* filter-mapping *>

上面扯一堆皮的意思总的来说也就是:Struts2使用StrutsPrepareAndExecuteFilter来进行请求的识别和分发,而StrutsPrepareAndExecuteFilter里面负责对请求解析,并根据Struts.xml配置文件的配置转发到不同的action,注意问题就出在了对"请求解析"上面

看代码

代码位置:package org.apache.struts2.dispatcher.ng.filter;

类名:StrutsPrepareAndExecuteFilter

这个类实现了Filter接口,这个接口有个关键回调doFilter,每一个http请求都会最先被投放到这里,所以这个东西拿到的是第一手最新鲜的http请求

如图这里开始对原始request请求进行解析,跟进wrapRequest()函数:

package org.apache.struts2.dispatcher.ng;

类名:PrepareOperations

没啥好说的,接着跟进dispatcher.wrapRequest():

package org.apache.struts2.dispatcher;

类名:Dispatcher

这里就有开始出现有意思的了,校验content_type是否包含"multipart/form-data"如果包含就有两个函数会被先后执行:

MultiPartRequest mpr = this.getMultiPartRequest();

会获取默认配置的解析插件实例,即JakartaMultiPartRequest类,这个类是Struts2默认的处理解析上传文件的插件

然后在request1 = new MultiPartRequestWrapper(mpr, request, this.getSaveDir(), provider);中进行解析工作,继续跟进MultiPartRequestWrapper()

package org.apache.struts2.dispatcher.multipart;

类名:MultiPartRequestWrapper

multiPartRequest就是JakartaMultiPartRequest类的实例,接着调用了JakartaMultiPartRequest的parse()方法,跟进之,这里由于JakartaMultiPartRequest实现的是MultiPartRequest的接口实现类,所以我们要跟进到JakartaMultiPartRequest的parse()方法中:

package org.apache.struts2.dispatcher.multipart;

类名:JakartaMultiPartRequest

这里的两个函数setLocal和processUpload如果出现异常就会跳入下面的异常处理语句,一般setLocal不会出错,processUpload承载的是对上传的数据流的解析之类的工作,这里出问题的可能比较大,在这次公布的poc文件中,可以发现是构造了错误的Content-Type导致了processUpload中的异常中断,跳入了catch语句中,这里还有一个SizeLimitExceededException的异常,也接着执行了下面的关键函数buildErrorMessage方法,但是SizeLimitExceededException异常中的处理并不能携带导致ognl注入的payload字符串,所以那个异常分支是不能利用的,接着看buildErrorMessage方法(万恶之源):

findText方法会导致最终的ognl注入,参数中的e.getMessage()会传递包含payload的字符串,特殊字符串最终导致ognl注入产生,payload中的java代码得到执行。。。

官方打的补丁:

有个老哥在下面回复:

意思是说:你也可以在解析Request之前再加一个Filter,在这个Filter里面检查Content-Type里面是不是有不合法的字符啥的,如果有就丢弃不再继续解析

额~,这只能说是个不是办法的办法。。。

猜你喜欢

转载自blog.csdn.net/u014021893/article/details/70332637