Hash Collision DoS事件及影响

Hash Collision DoS能让受攻击的服务器变得巨慢无比。

这不是因为服务器的编码原因或是疏忽造成的,而是程序语言自身的问题,Hash Collision DoS利用了各语言中Hash算法的“非随机性”可以制造出N多不一样的value,但是key一样数据,然后让Hash表成为一张单向链表,从而导致整个网站或是程序的运行性能以级数下降。有数据说,10kb的数据量就会导致一个i7的CPU马上占用率飙升100%,这真是恐怖。不幸的是,除了Perl之外,这个漏洞使得包括Java, JRuby, PHP, Python在内的以下各种开发语言和许多常用软件都纷纷中招:

  • Java, 所有版本
  • JRuby <= 1.6.5 (目前fix在 1.6.5.1)
  • PHP <= 5.3.8, <= 5.4.0RC3 (目前fix在 5.3.9,  5.4.0RC4)
  • Python, all versions
  • Rubinius, all versions
  • Ruby <= 1.8.7-p356 (目前fix在 1.8.7-p357, 1.9.x)
  • Apache Geronimo, 所有版本
  • Apache Tomcat <= 5.5.34, <= 6.0.34, <= 7.0.22 (目前fix在 5.5.35,  6.0.35,  7.0.23)
  • Oracle Glassfish <= 3.1.1 (目前fix在mainline)
  • Jetty, 所有版本
  • Plone, 所有版本
  • Rack <= 1.3.5, <= 1.2.4, <= 1.1.2 (目前fix 在 1.4.0, 1.3.6, 1.2.5, 1.1.3)
  • V8 JavaScript Engine, 所有版本
  • ASP.NET 没有打MS11-100补丁

事实上,Hash Collision DoS 漏洞并不是突然出现,早在2003年的一篇论文《通过算法复杂性进行拒绝式服务攻击》中就有相关报告进行了预警,但好像并没有引起当时正蓬勃发展的Java和其它开发语言的注意。以上不幸中招开发语言的列表还在继续更新之中,最新情况可查看: oCERT的2011-003报告。

更详细的内容,可参考这里。

原理及解决方法:Java相关

这些语言使用的Hash算法都是“非随机的”,比如Java和Oracle使用的Hash函数:

staticinthash(inth)

{

h ^= (h >>> 20) ^ (h >>> 12);

returnh ^ (h >>> 7) ^ (h >>> 4);

}

所谓“非随机的” Hash算法,就可以猜。比如:

1)在Java里, Aa和BB这两个字符串的hash code(或hash key) 是一样的,也就是Collision 。

2)于是,可以通过这两个种子生成更多的拥有同一个hash key的字符串。如:”AaAa”, “AaBB”, “BBAa”, “BBBB”。这是第一次迭代。其实就是一个排列组合,写个程序就搞定了。

3)然后,可以用这4个长度的字符串,构造8个长度的字符串,如下所示:

"AaAaAaAa", "AaAaBBBB", "AaAaAaBB", "AaAaBBAa",

"BBBBAaAa", "BBBBBBBB", "BBBBAaBB", "BBBBBBAa",

"AaBBAaAa", "AaBBBBBB", "AaBBAaBB", "AaBBBBAa",

"BBAaAaAa", "BBAaBBBB", "BBAaAaBB", "BBAaBBAa",

4)同理,就可以生成16个长度的、以及256个长度的字符串,总之,很容易生成N多的这样的值。

在攻击时,只需要把这些数据做成一个HTTP POST 表单,然后写一个无限循环的程序,不停地提交这个表单。用浏览器就可以实现。当然,如果做得更精妙一点的话,把这个表单做成一个跨站脚本,然后找一些网站的跨站漏洞,放上去,于是能过SNS的力量就可以找到N多个用户从不同的IP来攻击某服务器。

要防守这样的攻击,有下面几招:

打补丁,把hash算法改了。

限制POST的参数个数,限制POST的请求长度。

最好还有防火墙检测异常的请求。

不过,对于更底层的或是其它形式的攻击,可能就有点麻烦了。

原理及解决方法:PHP相关

下面再结合PHP内核源码,聊一聊这种攻击的原理及实现。

PHP是使用单链表存储碰撞的数据,因此实际上PHP哈希表的平均查找复杂度为O(L),其中L为桶链表的平均长度;而最坏复杂度为O(N),此时所有数据全部碰撞,哈希表退化成单链表。下图PHP中正常哈希表和退化哈希表的示意图。

哈希表碰撞攻击就是通过精心构造数据,使得所有数据全部碰撞,人为将哈希表变成一个退化的单链表,此时哈希表各种操作的时间均提升了一个数量级,因此会消耗大量CPU资源,导致系统无法快速响应请求,从而达到拒绝服务攻击(DoS)的目的。

攻击者可以通过一些方法间接构造哈希表来进行攻击。例如PHP可利用POST方式进行攻击,针对这种方式的哈希碰撞攻击,目前PHP的防护措施是控制POST数据的数量。另外的防护方法是在Web服务器层面进行处理,例如限制http请求body的大小和参数的数量等,这个是现在用的最多的临时处理方案。这些方法只是限制POST数据的数量,而不能彻底解决这个问题。彻底的解决方案要从Zend底层HashTable的实现动手。

一般来说有两种方式,

一是限制每个桶链表的最长长度;

二是使用其它数据结构如红黑树取代链表来保存碰撞了数据。

(并不解决哈希碰撞,只是减轻攻击影响,将N个数据的操作时间从O(N^2)降至O(NlogN),代价是普通情况下接近O(1)的操作均变为O(logN))。

目前使用最多的仍然是POST数据攻击,因此建议生产环境的PHP均进行升级或打补丁。

至于从数据结构层面修复这个问题,目前还没有任何方面的消息。

更多详细内容可参考原文。

原理及解决方法:Nodejs相关

以 connect 为示例说明在Nodejs防御此问题。

使用 connect.limit 限制 request-body-size,直接上 connect.limit 模块解决:

connect()

.use(connect.limit('1mb'))

.use(handleRequest)

修改 qs 模块,让其支持 keys-limit 和 allow-keys

querystring.js

PS: 提了pull request,但是估计在没有真实攻击示例放出来之前,是不会被接受的。

/**

* Parse the given str.

*/

function parseString(str, options) {

var limit = options && options.limit;

var keys = options && options.keys;

if (keys && Array.isArray(keys)) {

keys = {};

for (var i = 0, l = options.keys.length; i < l; i++) {

keys[options.keys[i]] = 1;

}

}

return String(str)

.split('&', limit)

.reduce(function(ret, pair){

try{

pair = decodeURIComponent(pair.replace(/\+/g, ' '));

} catch(e) {

// ignore

}

var eql = pair.indexOf('=')

, brace = lastBraceInKey(pair)

, key = pair.substr(0, brace || eql);

if (keys && !keys[key]) {

return ret;

}

var val = pair.substr(brace || eql, pair.length)

val = val.substr(val.indexOf('=') + 1, val.length);

// ?foo

if ('' == key) key = pair, val = '';

return merge(ret, key, val);

}, { base: {} }).base;

}

/**

* Parse the given query `str` or `obj`, returning an object.

*

* Options: (only effect on parse string)

*

*  - `limit` parse string split limit.

*  - `keys`  which keys need to be parse.

* @param {String} str | {Object} obj

* @param {Object} options

* @return {Object}

* @api public

*/

exports.parse = function(str, options) {

if (null == str || '' == str) return {};

return 'object' == typeof str

? parseObject(str)

: parseString(str, options);

};

还需要让 connect.query 模块 传递options参数给 qs.parse()

module.exports = function query(options){

return function query(req, res, next){

req.query = ~req.url.indexOf('?')

? qs.parse(parse(req.url).query, options)

: {};

next();

};

};

同样 connect.urlencoded 模块也需要将options参数传递给 qs.parse()

req.on('end', function(){

try {

req.body = buf.length

? qs.parse(buf, options)

: {};

next();

} catch (err){

next(err);

}

});

全部组合起来

var qsOptions = { limit: 100 };

connect()

.use(connect.limit('1mb'))

.use(connect.query(qsOptions))

.use(connect.bodyParser(qsOptions))

.use(handleRequest)

防范 http header 攻击

请求的 http header 也会导致hash冲突,在V8层面未修复hash算法之前,可以通过简单的 http_patch.js 修复此问题:

var http = require('http');

var IncomingMessage = http.IncomingMessage;

var _addHeaderLine = IncomingMessage.prototype._addHeaderLine;

// limit http header number

IncomingMessage.prototype._addHeaderLine = function(field, val) {

if (!this.__headerCount__) {

this.__headerCount__ = 0;

} else if (this.__headerCount__ >= 100) {

return;

}

_addHeaderLine.apply(this, arguments);

this.__headerCount__++;

};

业界人士看法

@Laruence:今天尝试了随机增长Hashtable大小来克服Hash Ddos, 不过, 后来证明, 这种方法只能防止Number Key, 而对于String Key,

攻击者总能找到一些特殊的Key, 他们在DJB Hash以后的结果相同.

目前新的修复方案进度搁置. 5.3.9可能只能发布包含限制max_input_vars的修复措施.

@beyondme37 :问题是出在计算key的hash函数。比如我们的存入一个哈希表的数据为整数,我们计算key的hash函数如下:

int hash(int x)

{

return (x % 5);

}

那我x输入6, 11, 16, 21, 26 … 返回的计算出的key都是1,都会存在哈希表1位置,即1位置冲突,而一般解决哈希表冲突的方法为拉链法,即数据全部存在1位置成单链表了,所以查找速度会下降为O(n)级别。

@wenbo :可以简单理解为,tomcat 之类给你做了一个基础框架,这个框架会事先把提交的请求解析并装载在某个hash_map里——那些会冲突的KEY可以理解为参数名,KEY=后面的值则是该参数的取值。然后,你的脚本不再需要解析http请求,而是直接从容器中用参数名取出各个参数的实际值即可。这个攻击针对的是第一步,即底层架构”预先解析请求并将解析出的内容存储在某个容器内”这个步骤。底层架构并不知道上层应用要如何解释这些参数,所以它只能把所有参数缓存起来等待处理;至于上层应用,此时并未被唤起,所以也无法对此决策。至多可以在部署时通过配置声明“在我的所有网页里,最多会用到1000个参数”,或者“在我的应用里,参数及其内容加起来最多10K字节”。

目前暂无完美解决之道

虽然半个多月前Tomcat就紧急发布安全漏洞通知,同时微软也发布了相应的安全漏洞通知,但他们都是通过变通的方式来解决此拒绝服务漏洞:就是告知大家,将请求参数据缓存值设小,也就是说,一次性的请求量不会导致CPU被全部占满——这真是无奈之举。除此之外,就是设计好HASH算法,一定要保证必然碰撞事件的概率降低,也就是说提高生产位数,带来的痛苦就是请求效率降低。防御之法是做好异常检测,理性区分正常与恶意的数据请求。

资料参考:

Hash Collision DoS 问题

浅析 HashTable 碰撞拒绝服务漏洞

Defense hash algorithm collision 防御hash算法冲突导致拒绝服务器

PHP哈希表碰撞攻击原理

Multiple programming languages vulnerable to DoS via hash algorithm collision

Hash Collision DoS 攻击相关推荐

  1. 转帖:对linux中半增加半连接数量和防止服务器被dos攻击

    .增大队列SYN最大半连接数 在Linux中执行命令"sysctl -a|grep net.ipv4.tcp_max_syn_backlog",在返回的"net.ipv4 ...

  2. DOS攻击与网络溯源技术

    1.DoS攻击 DoS攻击(Denial of Service,拒绝服务攻击)通过消耗计算机的某种资源,例如计算资源.网络连接等,造成资源耗尽,导致服务端无法为合法用户提供服务或只能提供降级服务.在S ...

  3. 如何防止因哈希碰撞引起的DoS攻击

    如何防止因哈希碰撞引起的DoS攻击 理解哈希 什么是哈希 哈希和数组 哈希算法 哈希碰撞 鸽巢原理 为什么不能避免哈希碰撞 哈希算法的特点 如何解决哈希碰撞 开放寻址法 线性探测 线性探测法适用场景 ...

  4. HTTP POST慢速DOS攻击初探

    1. 关于HTTP POST慢速DOS攻击 HTTP Post慢速DOS攻击第一次在技术社区被正式披露是今年的OWASP大会上,由Wong Onn Chee 和 Tom Brennan共同演示了使用这 ...

  5. python dos攻击_利用SMB漏洞DoS攻击任何Windows系统

    原标题:利用SMB漏洞DoS攻击任何Windows系统 近日微软报出SMB V1存在漏洞,安全研究员并将此漏洞称作 " SMBLoris ",解释其能够发动拒绝服务(Dos)攻击, ...

  6. Dos攻击工具(ZAmbIE)

    简介 ZAmbIE是一款DOS攻击工具,支持各种状态的DOS攻击,用Python编写,还没有完成,但是可以使用 首先说明一下DDOS才是分布式拒绝服务攻击,DOS是拒绝服务攻击,DOS是单机操作的 下 ...

  7. Avahi DOS攻击broadcast-avahi-dos

    Avahi DOS攻击broadcast-avahi-dos Avahi是Linux下常用的类DNS服务.它可以帮助主机在没有DNS服务的局域网中,发现基于Zeroconf协议的设备和服务.该工具工作 ...

  8. DOS攻击之详解--转载

    源地址没有找到,间接引用地址:http://wushank.blog.51cto.com/3489095/1156004 DoS到底是什么?接触PC机较早的同志会直接想到微软磁盘操作系统的DOS--D ...

  9. TCP协议三次握手连接四次握手断开和DOS攻击

    转载: http://hi.baidu.com/xgdcisco/blog/item/60da65f70fd8145d342acc28.html: http://blog.csdn.net/losty ...

最新文章

  1. 网页静态化技术Freemarker
  2. Altium Designer 09 使用要点:电气连接工具
  3. vue基础知识(一)
  4. 应用数学软件测试题,高等数学第六章定积分应用综合测试题
  5. 分享几个接口自动化的实战练手项目
  6. Java讲课笔记02:Java集成开发环境
  7. web报表工具FineReport最经常用到部分函数详解
  8. [JSOI2016]病毒感染[dp]
  9. QT学习小结之信号与槽
  10. Luogu P5201 [USACO19JAN]Shortcut 最短路树???
  11. 【大数据部落】用R语言挖掘Twitter数据
  12. CorelDRAW哪个版本好用实用强x4/X8/2019/2020/2021
  13. 暑期作息时间表模板_小学生暑假作息时间表模板范例
  14. 论文阅读 [TPAMI-2022] Deep Visual Odometry With Adaptive Memory
  15. Vue3.0项目——打造企业级音乐App(二)图片懒加载、v-loading指令的开发和优化
  16. 赛程表 (递归调用, 非递归调用)
  17. Python复习 基础知识
  18. redis 3.0.7 cluster 集群部署
  19. C# ASP.NET.Web大学课堂登入注册界面实验
  20. 关于收音机的一些问题

热门文章

  1. python async socket_Python开发中常用的标准库,这些都是你应该掌握的
  2. android design包控件,Android Design包之TextInputLayout和TextInputEditText的组合使用【原创】...
  3. 如何设置ftp服务器上传文件夹至不同路径,设置ftp服务器上传文件夹
  4. mui-scroll-wrapper mui-scroll 内容增多不出滚动条
  5. wrieshark 指令
  6. 钉钉机器人自动推送股票信息
  7. WM_QUERYENDSESSION与WM_ENDSESSION
  8. Unity枚举和字符串的相互转换
  9. LightOJ 1013 LCS+记忆化搜索
  10. 计算SharePoint两个日期和时间字段之间的时间差值