0240-Spring框架标签EL表达式执行漏洞分析(CVE-2011-2730)

# Spring框架标签EL表达式执行漏洞分析(CVE-2011-2730)

0x00 前言
=======

* * *

这个漏洞已经出来很久了,以前简单分析过,但是由于时间关系,没能深入研究原理,网上对这个漏洞的分析也不太多,最近由于工作原因,深入分析了一下这个漏洞的原理,这里重点将漏洞调试过程,以及一些之前遇到的一些奇怪问题的原因记录下来。

首先来看一下官方对这个漏洞的描述,如下图:

![enter image description here](http://drops.javaweb.org/uploads/images/27393c2f84e112fb35a5f0f422e8e7a144861899.jpg)

可以看到,这个漏洞的形成,是因为在早于JSP2.0的版本上,由于没有EL表达式的支持,Spring标签为了兼容这部分版本,Spring的一部分标签独立于Servlet/JSP容器添加了对EL表达式的支持。但这样做引起了一个问题,就是当这部分标签在支持EL表达式的容器中运行的时候,Spring标签的属性会被当做EL表达式执行两次,第一次是被容器当做EL执行,第二次是被Spring标签自身执行。所以,如果攻击者可以控制标签属性的内容,就可以执行自己提交的EL表达式,会造成信息泄露、代码执行等风险。

0x01 漏洞原理
=========

* * *

首先编写一段测试JSP代码,并且引入存在漏洞的Spring标签,我这里使用的是Tomcat 7.0.57和Spring 3.0.5

“`
<%@ taglib uri="http://www.springframework.org/tags" prefix="spring"%>

“`

这里使用message标签,text属性用el表达式从请求参数中取值,这样当访问

“`
http://localhost/tag.jsp?a=${applicationScope}

“`

${applicationScope}这个字符串,就会被当做EL表达式执行,如下图

![enter image description here](http://drops.javaweb.org/uploads/images/41b68ba7464e22c8a33a41efa2da8b7de4fa8c2a.jpg)

下面我们就从代码中,研究一下这个漏洞的原理。

首先,${param.a}这个EL表达式要在JSP里面执行,这里有必要简单说一下JSP的执行原理,tag.jsp在执行的时候,会先通过规则变成tag_jsp.java,这个文件可以在tomcatRoot/ work/Catalina/localhost/项目名称/org/apache/jsp/路径下找到,这个类其实是一个servlet,通过查看这个文件的代码,我们可以发现${param.a}这个EL表达式,其实是被转化成了这样的代码org.apache.jasper.runtime.PageContextImpl.proprietaryEvaluate(“${param.a }”, …….),这行代码调用了Tomcat的一个专用方法来执行EL表达式,这段代码执行了之后,我们通过请求参数提交的${applicationScope}就被容器获取,并且传入了Spring标签,如下图:

![enter image description here](http://drops.javaweb.org/uploads/images/bb72b3dde100fe1f37f08e391cde849fdeddf43f.jpg)

还需要说一下关于标签的一些内容,标签都有一个tld文件,这个文件里面有标签的各种信息,包括标签实现类、属性信息等等,这个标签对应的spring.tld文件可以在Spring的jar包中找到,打开这个文件搜索message,就可以定位到如下图的位置:

![enter image description here](http://drops.javaweb.org/uploads/images/d2d8fb36dd74ac8475e649ae9a80ebe9f66fb7f7.jpg)

从上面可以看到org.springframework.web.servlet.tags.MessageTag就是这个标签的实现类,关于标签的规范,我就不多说了,有兴趣的朋友可以去翻翻相关的规范。

Debug程序,在doStartTagInternal方法下断点,如下图:

![enter image description here](http://drops.javaweb.org/uploads/images/4c91ffe8f98d3a016b73a34a916cb6b15e89ee7d.jpg)

然后跟进resolveMessage方法,因为程序执行到这里,容器已经第一次执行了EL表达式${parm.a},将参数值${applicationScope}取了出来,可以看到text变量,这时候就是我们传入的${applicationScope},如下图:

![enter image description here](http://drops.javaweb.org/uploads/images/3d16dca744c8486b339400e0aa8281cee747a4b2.jpg)

最后跟踪到org.springframework.web.util.ExpressionEvaluationUtils类的evaluateExpression方法,在这里可以看到Spring的代码调用了getExpressionEvaluator方法获取了容器执行El表达式求值对象,并执行了EL表达式,到这里可以看到我们通过请求参数提交的字符串,被当做EL表达式执行了,如下图:

![enter image description here](http://drops.javaweb.org/uploads/images/e1fd2b5aef272797fb815c2799efb26eca5f06d3.jpg)

从上面的过程可以看到,容器第一次执行EL表达式${param.a}获得了我们输入的${applicationScope},然后Spring标签获取容器的EL表达式求值对象,把${applicationScope}再次执行掉,形成了漏洞。

0x02 Tomcat不能远程代码执行研究
=====================

* * *

这个漏洞既然能执行攻击者提交的EL表达式,那么获取敏感信息、XSS等攻击自然不是问题,我这里主要说一下代码执行的一些问题。 这个漏洞之所以能造成远程代码执行,是因为从JEE6开始,EL(EL2.2)表达式不仅支持获取对象属性,还加入了对方法调用的支持,而Tomcat、Resin等容器都加入了EL表达式对方法调用的支持,之前知识库里面已经有大牛公布的针对Resin和GlassFish的代码执行POC,虽然由于容器对EL表达式的执行实现上有差异,每个容器POC有所差异,但是都可以成功实现方法调用,我这里就不多说了,而我在最初测试这个漏洞的时候,发现Tomcat始终没法调用方法,当时没有深入研究,通过前面的分析,其实原因已经可以看出来了,这里还是测试一下,先写一段JSP测试代码:

“`

${“aaa”.replace(‘a’,’b’)}

“`

打开这个页面,发现a都已经被b替换,说明replace方法被成功调用:

![enter image description here](http://drops.javaweb.org/uploads/images/6a0110107aae9c90e0a00eb46a58ee2be234a03e.jpg)

但是当我们通过之前的tag.jsp尝试提交http://localhost/tag.jsp?a=${“aaaa”.replace(‘a’,’b’)}的时候却爆出了错误,如下图:

![enter image description here](http://drops.javaweb.org/uploads/images/31dce767b712292738f15ff113a1311d900b0e35.jpg)

从Tomcat 7开始已经支持EL表达式方法调用,为什么第二次会失败呢?

其实前面的分析中已经看到,在JSP中直接写EL表达式,Tomcat调用了org.apache.jasper.runtime.PageContextImpl.proprietaryEvaluate方法,这个方法已经加入了对EL表达式方法调用的支持,而通过Spring标签执行EL表达式,前面已经看到是通过pageContext的getExpressionEvaluator方法,而在EL表达式的新标准中这个方法已经“废弃”,Tomcat并没有在这个方法的实现中加入对方法调用的支持,所以造成执行失败,这也让这个漏洞在Tomcat上显得有点鸡肋了,谁能保证Tomcat哪天不会抽风,改变代码呢?说不定到时候,这个漏洞,就可以在Tomcat上造成代码执行了。

参考

http://support.springsource.com/security/cve-2011-2730

http://drops.wooyun.org/tips/2892

© 版权声明
THE END
喜欢就支持一下吧
点赞0赞赏 分享
评论 抢沙发

请登录后发表评论

    请登录后查看评论内容