Velocity模板的漏洞

山哥 发布于 2012/03/02 10:24
阅读 1K+
收藏 5

今天在网上搜Velocity的资料,发现了下面的一个关于Velocity的漏洞报告,先贴出来给大家看下:

简要描述:

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://www.inbreak.net/">http://www.inbreak.net/</a>
然后访问:http://localhost:8080/showcase/context.vm?layout=../z.gif

漏洞证明:

修复方案:

    暂无

加载中
0
山哥
山哥
??怎么不能显示 jpg 图片啊?
0
红薯
红薯

关于 layout :velocity 有限使用 $layout 变量,例如你在页面上通过 #set($layout = "oschina.vm") 来指定模板布局,这样通过请求传递过来的 layout 就不起作用。

另外最好将 vm 放在无法直接通过请求访问的位置,例如 oschina 是放在 /WEB-INF/templates 目录下,然后自己做一层Filter来调用

山哥
山哥
我也是放到/WEB-INF/下的,呵呵 对了,问下红薯哥,oschina的模板数据都缓存了吗?还是默认的velocitylayout处理?默认处理每次页面展示都要加载解析一次模板。
0
红薯
红薯
oschina的模版没有缓存哦,修改立即生效
山哥
山哥
哦,呵呵。 oschina的页面展示都是使用vm的吧,这样每次都读取磁盘文件展示,感觉会有性能影响。但是osc好像并没有所影响,呵呵,可以不用太在意了。 velocity有一个配置支持缓存:xx.resource.loader.cache = true
0
Heroin
Heroin
留个名
0
罪恶的花生
罪恶的花生
我一直都吧vm、jsp和html文件放在/WEB-INF/jsp目录下,根目录清爽~
返回顶部
顶部