为什么80%的码农都做不了架构师?>>> ![hot3.png](https://www.oschina.net/img/hot3.png)
struts2
的taglib设计缺陷(并不是所有输出标签都做了默认的htmlescape)
有几个标签是不做htmlescape的,比如
这其实是一个严重陷阱,因为只要提到struts2,前辈们都会告诉你,放心使用,它默认做了htmlescape。那是什么原因导致一些标签没有做默认的escape呢?作者翻了下源码,也没有找出具体原因,不知道那些人是怎么想的。
并且,经过简单的fuzz,发现在特定环境下,那些做了输出转义的标签也会出现问题。
我们知道默认的htmlescape是不转义单引号的,所以,当struts标签库的源码中,出现一些标签属性的输出时,如果标签属性的周围使用的是单引号,而攻击者又能控制标签属性内容的时候,就会出现xss漏洞。如下:
当这个xss的内容可以由攻击者控制,即使对xss的内容作了htmlescape,依然可以被攻击者bypass。
基于这个原理,作者搜索了struts标签库源码,那些“XXX.ftl”文件中搜索“}'”符号,找到N多,测试其中一个如下:
-------------
标签,在正常使用的时候,他会放到一个标签内,最终输出html后,会变成一个输入框。
它有个属性叫“tooltip”,如果这个标签为用户可控制,比如从数据库中读取用户输入,而这个标签所在的开启了:
的时候,用户输入的tooltip的值,会出现以下情况:
struts2.0
-->
caption
内容就是tooltip的值,从数据库查出
struts2.1.6&struts2.1.8
-->
onmouseover
生成一个domTT_activate函数调用,参数中其中一个值,是tooltip的内容。这里被bypass了。
------------
这些搜出的几个个地方实际上根本没有做任何escape,就直接输出了数据。下面那个即使做了默认的htmlescape,还是会出问题,除非它默认做了javascriptEscape。struts2默认有地方做javascriptEscape么?答案是“没有”。所以,它们全都能被XSS!
struts2
的这些escape,其实是一个很太监的安全方案,安全工程师最恨的就是这种方案,做了安全方案,还不做完全,留下一堆问题。
struts2
的HTTP Parameter Pollution处理缺陷
webwork
和struts2都有这个问题,当用户给web应用提交:
http://www.inbreak.net/app/test!redirect.action?redir=kxlzx&redir=aaad61
时,如果我们在action中定义了
private String redir;
public String getRedir() {
return redir;
}
public void setRedir(String redir) {
this.redir = redir;
}
Action就会取到redir的值为“kxlzx, aaad61”注意中间是有空格的。
这种数据是由webwork(struts2)把两个参数合并而成的,但是如果我们request.getParameter("redir");拿到的值,却只是第一个(值为kxlzx)。
我们知道struts2提倡使用拦截器做一些事情,他可以在action的execute方法执行之前和之后做一些操作。那就有一些开发,想当然的在这里防御一下url跳转、SQL注入、XSS等攻击。我们看看他们会怎么做:
@Override
public String intercept(ActionInvocation arg0) throws Exception {
……
String name = request.getParameter("name");
if(name!=null&&name.indexOf("'")>-1){
System.out.println("find sql injection");
request.getSession().setAttribute("msg", "find sql injection");
return "falseuser";
}
String redir = request.getParameter("redir");
if(redir!=null&&!redir.equals("http://www.b.com")){
System.out.println("find url redirect");
request.getSession().setAttribute("msg", "find url redirect");
return "falseuser";
}
return arg0.invoke();
}
在这段代码中,作者仅仅示例了在拦截器中防御sql注入和url跳转漏洞,sql注入的防御规则是检查“’”单引号,而url跳转漏洞规则是检查必须跳转到”http://www.b.com”去。作者知道没有完全防御,所以大家先不要在这里追究防御方案,仅仅是一个示例。
而开发人员在业务代码如下:
String sql = "select book_name,book_content from books";
if (name != null) {
sql += " where book_name like '%" + name + "%'";
}
很明显能注入。
public String redirect() {
return "redir";
}
也明显存在url跳转漏洞。
但是由于拦截器在action之前执行,所以如果我们输入了
http://www.inbreak.net/app/test!findUserByName.action?name=a'
拦截器当然就会返回错误“find sql injection”;
因为执行到了
String name = request.getParameter("name");
if(name!=null&&name.indexOf("'")>-1){
发现name的值确实有单引号。
但是如果我们输入了
http://www.inbreak.net/app/test!findUserByName.action
?name=aaaaa&name=a' union select name,pass from user where ''<>'
就直接绕过了拦截器的判断。因为拦截器获取的request.getParameter("name"),是第一个参数的值aaaaa,抛弃了第二个参数的值,但是action中的name的值,却是
“
aaaaa, a' union select name,pass from user where ''<>' ”所以被注入了
大多数拦截器都是这样做的防御,包括一些filter等。
这件事情发生在url跳转漏洞时,却不明显,因为攻击者顶多构造一个:
http://www.inbreak.net/app/test!redirect.action?redir=http://www.b.com&redir=www.inbreak.net
抓包看看
它跳到了http://www.b.com, www.inbreak.net去了。所以IE直接报错,说打不开这个地址。但是我们还有别的浏览器,总是喜欢给大家友好信息的浏览器,看看chrome给用户什么提示:
Chrome
也认为这是一个错误的链接,所以给出了“正确”的链接地址。这不是刚好被钓鱼网站利用么?
struts2
的官方漏洞公告和修补后引发的安全缺陷
从有struts2,到现在为止,官方一共发布了4个漏洞,在
http://struts.apache.org/2.x/docs/security-bulletins.html
* S2-001 — Remote code exploit on form validation error
* S2-002 — Cross site scripting (XSS) vulnerability on and tags
* S2-003 — XWork ParameterInterceptors bypass allows OGNL statement execution
* S2-004 — Directory traversal vulnerability while serving static content
从名字上,可以看出漏洞的内容,作者仅仅对其中两个做了源码级别的漏洞修补评估,发现了很多悲剧的事情。同学们有兴趣可以去研究剩下两个漏洞,算是练习作业吧。
struts2
的官方漏洞公告和修补后引发的安全缺陷(S2-002)
先看看“S2-002 — Cross site scripting (XSS) vulnerability on and tags”这个漏洞。
顾名思义是对和的xss漏洞修补,但是前文提到,这里有XSS漏洞,难道是在忽悠大家?我们看看这帮工程师是怎么修补的,来到这个svn地址:
http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/java/org/apache/struts2/views/util/UrlHelper.java?r1=614814&r2=615103&diff_format=h
注意这两行:
看到这两行代码的时候,作者笑了,因为作者仿佛看到了至少两件悲剧的事情,现在把它们写成故事:
第1件悲剧的事情
,某年某月某日,一个脚本小子给官方报告漏洞,说在使用标签的时候,代码为:
之后他输入了
http://www.inbreak.net/app/test!testpro.action?url=
并告诉官方这里是一个XSS漏洞,希望官方修补掉。
官方很重视,一个开发就去修补,添加如下判断:
if (result.indexOf("
结果并没有在页面执行xss脚本。后来那脚本小子也测试了一下,发现没问题,这事情就过去了,瞒着人民大众,悄悄的修补了。
第2件悲剧的事情
,又过了某人某月某日,某另一个脚本小子又发了漏洞,还是那段代码,但是url改成了:
http://www.inbreak.net/app/test!testpro.action?url=<
注意,这里是<
并进行了冒烟测试、功能测试、黑盒测试、白盒测试。这次还发了公告出来,说这里没问题了,我们很重视安全漏洞,已经修补了。
作者看到这里,测试新的bypass官方修补代码的url为:
http://www.inbreak.net/app/test!testpro.action?url=
于是XSS脚本又被执行了,因为这里是