VELOCITY本地代码执行漏洞

by 空虚浪子心 http://inbreak.net
velocity是J2EE的MVC架构最常用的展示层模板文件,由于性能优秀,极多的J2EE应用,都使用了这个模板。通常在使用的时候,会和其他框架结合,最常见的框架是struts2、spring mvc等框架。
模板的扩展名为“vm”,开发人员在配置时,经常需要让框架解析“vm”扩展名。velocity官方,给出了标准配置,就在showcase中,指导大家配置vm文件的servlet为VelocityLayoutServlet。
如果按照velocity的官方标配,就会产生这个漏洞(velocity-tools-2.0大家可以下载它的showcase,直接跑起来)。

漏洞原理:
在使用velocity框架的时候,开发往往会配置URL中,请求文件扩展名为vm时,就解析对应的velocity模板,这时就需要一个servlet。velocity给出了自己的servlet,供大家使用,一共提供了两个,其中最为推荐的,就是VelocityLayoutServlet,因为官方showcase中就使用了这个。
这个servlet配合几个技巧,可以做到执行任意java代码。
漏洞入口:
漏洞在于VelocityLayoutServlet允许用户提交layout参数,指定模板位置。
在这个servlet寻找layout模板时,可以允许url参数提交过来。

protected String findLayout(HttpServletRequest request)
{
// check if an alternate layout has been specified
// by way of the request parameters
String layout = request.getParameter(KEY_LAYOUT);
// also look in the request attributes
if (layout == null)
{
layout = (String)request.getAttribute(KEY_LAYOUT);
}
return layout;
}

从代码中可以看到,参数中指定了layout,servlet之后的代码,就去解析模板了。
相关代码

mergeTemplate(template, context, response);

利用技巧1:
这段代码,不会去管模板的扩展名是否为vm,都去解析。因为velocity本身就具备配置文件扩展名功能,你可以在配置中指定velocity解析html文件为模板文件。
所以,从框架的角度讲,官方只会说这是个必备的功能。
利用技巧2:
虽然可以在velocity配置文件中,指定模板位置必须在layout文件夹中,但是可以使用“../”绕过。

tools.view.servlet.layout.directory = /layout/

这是一个悲剧的点,如果限制死目录,漏洞就会影响很小。
利用技巧3:
算了,暂时不提了,下一个框架漏洞会说到这里的一个大家很熟悉,但是也很猥琐的东西。
利用技巧4:
velocity模板解析时,是允许访问很多东西的,你可以认为他其实就是jsp的升级版,其中就包括执行系统命令。
是的,这个事情,我在google没看到有人提到过,是我去年偶然发现的(也许牛人从不说出来)。
我写一个简单的demo,利用velocity可以执行java代码的特性,执行系统命令。

#set ($exec = "kxlzx")
$exec.class.forName("java.lang.Runtime").getRuntime().exec("calc")

原理是,定义一个变量叫$exec,变量其实是继承了Object,所以可以调用Object的方法。其中一个属性叫class,可以反射类,我喜欢这个功能,他被无数次应用在java框架漏洞中。这样一步一步来到执行系统命令的地方,执行掉。
利用限制1(必须上传文件):
很明显,这不是大家愿意看到的,它所能执行的本地文件,必须在web目录下,因为velocity从很早的版本起,就可以配置把目录限制的死死的,vm模板只能在web目录下。
所以必须上传文件上来,无论什么扩展名。
利用限制2(如何从外部发现):
这一点比较难,因为如果找不到layout,也就是攻击者随便指定不存在的layout,就会把错误日志记录下来,但是并不返回给用户。
用户看到的,是一个200正常页面。在错误的layout的情况下,就会用默认的layout,这是从外部看到的结果,是和没有输入这个参数,一样的页面。唯一能确定的,就是url中有很大的肯定扩展名为vm(前文提到可以配置其他扩展名)。
其他的不想在这里多说,回头会发布一篇web框架指纹的文章,专门讨论这个问题。

攻击示例:
比如velocity的官方showcase
如果攻击者可以传文件到web目录下,比如
z.gif:

#set ($exec = "kxlzx")$exec.class.forName("java.lang.Runtime").getRuntime().exec("calc")
hacked by kxlzx<br>
<a href="http://inbreak.net/">http://inbreak.net/</a>

然后访问:http://localhost:8080/showcase/context.vm?layout=../z.gif
就可以看到下图:

ps:谁帮忙申请个CVE。。。我不会鸟语,这个没申请过,当然,你用自己的名字申请也无所谓,只要留个链接就好。
by 空虚浪子心 http://inbreak.net

发表评论?

0 条评论。

发表评论