Java浮点值拒绝服务漏洞危害分析

By 空虚浪子心 http://inbreak.net/

JAVA出了漏洞,CVE-2010-4476,会导致拒绝服务攻击。大家能从公告上,看到这样一段代码,挺长的。意思是只有开发人员写出这样的代码,才会对服务器造成影响。

我们肯定会首先考虑,这么长的代码,究竟有多少开发会傻乎乎的写出来?而我们究竟打不打补丁呢?其实作者知道,目前还有很多公司没有打补丁,不过没关系,等会儿你就要打了。

先看看官方给出的代码。


Send a Java Program Into An Infinite Loop
Compile this program and run it; the program will hang (at least it does on a 32-bit system with the latest JRE/JDK):
class runhang {
public static void main(String[] args) {
System.out.println(“Test:”);
double d = Double.parseDouble(“2.2250738585072012e-308″);
System.out.println(“Value: ” + d);
}
}
—————————————————————————————————————-
Send the Java Compiler Into An Infinite Loop
Try to compile this program; the compiler will hang:
class compilehang {
public static void main(String[] args) {
double d = 2.2250738585072012e-308;
System.out.println(“Value: ” + d);
}
}

以上代码,其实举了两个例子,首先简化一下代码:


这段代码会在编译时挂掉:
double d = 2.2250738585072012e-308;
这段代码会在运行时挂掉:
double d = Double.parseDouble(“2.2250738585072012e-308″);

作者很奇怪后面的System.out是啥意思,按照实际测试以及官方原理,这句压根不会执行,楼上都已经“无限循环”了,怎么可能走下来呢?不过这个不重要。
下文所说的漏洞,是指假设我们的开发人员写了“XXX”的代码,攻击者就可能攻击我们服务器。
我们来逆推攻击过程,从漏洞的角度上说,只有程序传入的值,由用户控制,才会导致漏洞触发,毕竟开发不会直接写这个值。而编译中挂掉,几乎不可能存在,很难有正常的业务需要用户提交代码,让服务器编译执行。所以,漏洞的产生只会出在这一句上:

这段代码会在运行时挂掉:
double d = Double.parseDouble(“2.2250738585072012e-308″);

那么再次逆推,要求这个值有用户控制,如果环境是java web application,开发想写出有漏洞的代码,必须这样搞:

这段代码会在运行时挂掉:
double d = Double.parseDouble(request.getParameter(“double”));

当开发人员写出这样的代码,攻击者可以提交:
http://inbreak.net/double.do?double=2.2250738585072012e-308
于是,程序就”hang!”(其实我不知道这个词的意思),挂了,从表面上看不出来,但是实际上你的CPU会立刻100%,当前线程走不下去,页面卡死,不给你任何响应。当然,其他页面也许会好,因为web容器是多线程的,可惜已经有人100%CPU了,页面速度可想而知。
很多人,就考虑到了这段,除非开发人员真的写了这样的代码,否则很难出现漏洞,所以没有打补丁。
Java web在很多年前,都已经开始走框架路线了,我们熟知的spring mvc、struts2、webwork等等,甚至还有一些公司自己实现框架,比如阿里巴巴公司的开源框架webx(宣传一下http://code.taobao.org/project/view/401/)。在这样的框架中,开发人员更不可能自己去做转义,这都是框架自己负责的。是不是意味着,漏洞不可能存在呢?
这恰恰是最可怕的地方,这些框架没有让开发人员参与类型转义,用户本来提交的是一个String的2.2250738585072012e-308,框架会自动转义类型为Double,经测试,所有的框架都有自动类型转义(否则框架意义何在啊)。
开发什么都不需要做,只要在action中有一个对象,对象中有一个字段类型为double,或许他都不需要定义对象,其他开发早定义好了,他只需要写一个action。比如:

//订单处理action
public class OrderAction extends ActionSupport{
//订单对象
public Order order;
public String execute(){
return SUCCESS;
}
}
//Order对象的内容
Public class Order{
//前面还有其他字段,这里只说Double类型的。
Double money;
}


这是很常见的写法,只要Order对象中,有一个字段是Double的。我们就可以对此action提交:
http://inbreak.net/order.do?order.money=2.2250738585072012e-308
这就“hang”了。
我们可以写个扫描器,那么会有哪些字段通常被定义为double呢?扫描器自己去抓页面,抓回来的input,如果为user.name,我们就猜测user对象中可能存在money,可能存在score、point等,然后让它们等于那个值,自动提交。这等于挂字典,猜测对象中可能存在的double类型字段。
有没有线上的例子呢?
163的网易宝单日支付金额限制:

正常的情况,填入1元,看看效果:

立刻来到了
但是我们填上:2.2250738585072012e-308

等啊等,等啊等。。。等到花儿也谢了,还是不响应!
你猜猜它们的服务器怎样了?
Java web框架化以后,开发人员和架构师都忘记了转义类型的事情,也不需要自己做转义,代码变得越来越简单。作者为了研究漏洞,去询问有些资深架构师时,甚至以为“开发不会写这样的代码”,所以我们的程序不会受到影响。最终还是作者亲手用现有框架搭建了环境,把CPU真的跑到100%,才开始相信这个漏洞对框架的危害。
作者相信,J2EE框架对这个漏洞的完美支持,足以使很多门户网站沦陷。而这只是刚刚开始,你可以抱有侥幸心理,不过下一篇和这个漏洞有关的文章,会让你彻底打消这个念头。

发表评论?

0 条评论。

发表评论