Struts 2.2.3 DOS漏洞

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

  在struts2和webwork中,曾出现了远程代码执行漏洞,但是后来因为补丁会导致部分应用出现BUG,所以官方又给出了2次补丁。这次的修补,重新开启一个小小的功能,也同时开启了一个必杀dos炸弹。这个炸弹需要结合java浮点漏洞使用。

  该漏洞会覆盖所有最新版本的struts2:
  Struts 2.2.3 (GA)
  Struts 2.0.14 (GA)
  只有打了“java浮点漏洞官方补丁”,才能逃过一劫。

  这是作者对该漏洞的一篇分析文:http://inbreak.net/archives/212,《Java浮点值拒绝服务漏洞危害分析》,后文会用到。

  Struts2为了修补漏洞,首先推出了补丁:

  private String acceptedParamNames = "[a-zA-Z0-9\\.\\]\\[_'\\s]+";

  只允许“字母、数字、.、[、]、_、’、空格”出现在参数名称中,然而这个限制,
  也同时直接禁止了(引自
http://www.sunxin.org/forum/thread/19682.html):

  这导致开发人员本身定义的数据类型Set,本来可以提交

    Persons(1).name=空虚浪子心

  赋值的,打了这个补丁后,这种用法直接被拦截了。所以struts2官方也意识到这个这个补丁过于严格,导致正常业务不能通行,必须要把圆括号放开,同时圆括号也不会重现漏洞,所以再次补丁:
  http://svn.apache.org/viewvc/struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/interceptor/ParametersInterceptor.java?r1=956389&r2=956397&diff_format=h


  private String acceptedParamNames = "[a-zA-Z0-9\\.\\]\\[\\(\\)_'\\s]+";

  最新版本的struts2也是这样的代码。从作者的调查上看,大多数开发都不会直接使用官方补丁,特别是有经验的开发,他们只会过滤掉补丁中的“exp特征码”(官方补丁误杀太多),允许小括号的出现。那么不管怎样,现在允许小括号了。

  看过我分析struts2远程代码执行文章的同学们(http://inbreak.net/archives/167),都知道这个漏洞和ognl的关系,本文不再叙述,只是引用一篇OGNL官方文给大家看:

  http://www.opensymphony.com/ognl/html/LanguageGuide/constructors.html

  OGNL的LanguageGuide中,写明自己是允许“new Object”的,而OGNL的代码,实际意义上,是先编译,后执行。就是说,我们提交了一个ognl语句后,引擎会负责转换为java代码,之后编译、执行。注意,前文提到了“编译”这个词。

  那么再次引用上一篇文章的话:

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

  那时的作者,其实也发现了编译的漏洞,只是不愿意发出来,所以使用了“而编译中挂掉,几乎不可能存在,很难有正常的业务需要用户提交代码,让服务器编译执行。”这样的话来误导大家。具体原因大家懂得。

  提醒过大家,会有更加直接的利用发出来的。上次讲过,只要action的方法中,存在DOUBLE类型的属性,就可以直接攻击,利用的是“运行时挂掉”原理。

  在ognl语句中,执行“new Double(2.2250738585072012e-308)”,就会直接在编译中挂掉,现在struts2允许用户提交用于编译的代码,又允许了小括号,就可以直接提交:


  http://inbreak.net/app/secTest.action?new java.lang.Double(2.2250738585072012e-308)

  经过测试,可以直接CPU跑满了。请注意实际上这里的”new java.lang.double”根本没有真的“new”,而是挂在了编译的时候。

  刚发邮件,就被KJ牛鄙视了:“里面有短横线”,会被struts2补丁过滤掉。还好,作者复习了一遍“科学计数法”,绕过了struts2的补丁执行,才没有丢人:


  http://inbreak.net/app/secTest.action?(new java.lang.Double(0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022250738585072012))

  这段东西,也可以直接在eclipse中跑,请测试时,提前打开“任务管理器”,你会用到的。

  对这种数字转换形式,不懂的自己百度一下“0.xxxE-xx”的含义,学习一下“科学计数法”。最终没有“短横线”了,同时也把测试环境跑挂。

  如果看了上一篇分析文,你没有老老实实的打官方补丁,而是采用了“by pass exp特征码”的方法,过滤了字符串中的“2.2250738”,那么看了这串数字,相信你会比作者更激动的。

发表评论?

0 条评论。

发表评论