Hed9eh0g

前进的路上总是孤独的

Hash Length Padding Attack

本文共计有3266个字

前言

哈希长度扩展攻击(Hash Length Extension Attacks)有时会出现在于web相关的密码题中,借鉴了相关文章,我将在本文中尽量详细的介绍其攻击原理和相关应该了解的知识。

预备知识

哈希值

所谓哈希,其实是英文hash音译过来的,其英文原意是散列的意思。因此哈希值其实就是散列值。哈希值的作用等同于现实生活中“指纹”的作用,每个人指纹是独一无二的,因此通过类比可知哈希值的作用就是对消息的取证。比如你如何判断你从非官方的地方下载的软件是否为盗版?很简单,官方网站在发布软件的同时会提供一个哈希值和计算该值所用的算法,你只需要拿你软件进行相同的算法,得到的哈希值与官方的标准哈希值比对是否相同即可。

哈希函数

又称为单向散列函数,顾名思义,哈希函数就是用于生成哈希值的函数。哈希函数的算法包括MD4、MD5、SHA-1、SHA-2、SHA-3等。为了确保其生成的哈希值能够如同指纹般独一无二,哈希函数必须要求具有很强的抗碰撞性(包括强抗碰撞性和弱碰撞性)。

弱抗碰撞性

已知一条确切的消息及其哈希值,如果能够找到另外一条具有相同哈希值的消息,那么就说此哈希函数不具备弱碰撞性。

强抗碰撞性

如果能够找到两条不同的消息,使他们的哈希值是相同的,那么就说此哈希函数不具备强碰撞性。

哈希长度扩展攻击

由于此攻击类型与CTF相关,实战性更强,所以本文的重点便是它。

Merkle–Damgård结构

Merkle–Damgård简称为MD结构,他是用于处理哈希函数加密对象是较长字符时的一种方案,也是导致存在长度扩展攻击的原因。下图就是维基百科对该结构的展示图:

《Hash Length Padding Attack》

分块

对所要加密的消息(message)每个字符进行十六进制的转化,当消息长度较短时(小于或等于448bit),则直接写入消息块(message block)中。当消息长度大于448bit时,则要对消息进行分块处理,即每448bit分一块。

补位(padding)

分块完成之后,往往最后一个分块的长度小于448bit,这个时候必须通过补位直到达到448bit。补位的规则是在补位的第一位的第一个字节写入1,然后其字节都写入0,(注意:1位=8bit)。补位完成后,还要再添加8个字节(即64bit)用于标明该消息块有效信息的长度。

对于分块和补位的规则我们不必去记,上面的记录只是为了让大家知道个所以然(为了凑字数),接着读下去你就知道为什么不必去记了。

对消息块加密

首先有一个规定的初始化向量IV(initialization vector),他会与第一个消息块进行复杂的算法运算(我们不必理会是什么算法)得到一个新的值,然后再用这个新的值与第二个消息块去进行与第一次一样的算法运算再次得到一个新的值……如此重复下去直到最后一个代码块加密完成,即可得到hash值。

攻击原理

我们来看实验吧的一道题目:

$flag = "XXXXXXXXXXXXXXXXXXXXXXX";
$secret = "XXXXXXXXXXXXXXX"; // This secret is 15 characters long for security!
$username = $_POST["username"];
$password = $_POST["password"];
if (!empty($_COOKIE["getmein"])) {
      if (urldecode($username) === "admin" && urldecode($password) != "admin") {
             if ($COOKIE["getmein"] === md5($secret . urldecode($username . $password))) {
                      echo "Congratulations! You are a registered user.\n";
                      die ("The flag is ". $flag);
                  }
      else {
             die ("Your cookies don't match up! STOP HACKING THIS SITE.");
       }
}
else {
die ("You are not an admin! LEAVE.");
       }
}
setcookie("sample-hash", md5($secret . urldecode("admin" . "admin")), time() + (60 * 60 * 24 * 7));
if (empty($_COOKIE["source"])) {
setcookie("source", 0, time() + (60 * 60 * 24 * 7));
}
else {
        if ($_COOKIE["source"] != 0) {
             echo ""; // This source code is outputted here

这段代码的意思就是:secret 首先通过GET的方式连接变量username和password去进行url解码之后的值,成为一个新的字符串S,然后对S进行md5加密,再与md5($secret.”adminadmin”)得到的值进行比对(hash值的”指纹”作用),如果两个值相等则可以得到flag。如果我们所传的两个变量username和password都能够赋值为admin的url编码值,那么直接就可以得到flag,但是代码要求urldecode($password)不能为admin。

此时我们就要利用secret的长度已知cookie=md5($secret.”adminadmin”)已知,根据我们前面所说的补位过程,如果我们让username为urlencode(“admin”),然后故意传入password经过urldecode后结果为“admin\x80\x00\x00……(直到448bit,接下来为补位之后的标明消息长度的8个字节,16进制的c8就是10进制的200,也即(15+5+5)*8的结果)\xc8\x00\x00\x00\x00\x00\x00\x00(接下来进入第二个消息块)hed9eh0g….(第二消息块内容可随意构造)”的字符串那么根据分块规则可以知道$secret.”adminadmin”这个字符串将处在第一个消息块中,接下来再进行md5(第一个消息块)的运算的结果其实就是我们已知的cookie的值!

既然cookie的值已知,那么直接拿他作为新的初始变量,与第二个消息块的内容再次进行md5运算,所得到的新的hash1值也是就是已知的。而根据运算原理我们就可以得知:

hash1=md5($secret.urldecode($username.$password))=md5($secret.”adminadmin”)

这意味着我们并不需要知道secret的值是什么,只需要知道screct的长度length是多少和对某个已知的字符串的哈希值。而关键就是在于data(本题中即为password)的值的构造,如果每次都要根据补位规则来构造data的值还是很困难的,而工具hashpump(主角终于登场了)就很好的解决data的构造操作,所以我们是不必去记补位规则的。

hashpump

首先要知道hashpump要求传入的值,包括:

-s:对某个已知字符串的哈希值(本题的cookie)

-d:已知消息(本题的”admin”)

-a:要添加的数据(本题的”hed9eh0g”)

-k:secret的长度(本题为15+5=20)

将对应的值传入得到:

《Hash Length Padding Attack》

hashpump将返回两个值,第一个值为扩展长度之后的md5值,第二个值就是构造完成之后的data值。

因此最终的payload为:

username=admin&password=admin%80%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%c8%00%00%00%00%00%00%00hed9eh0g

getmein=3d0496d16729aa9b1eaa56be5383e112

参考文章

1、csdn某博客

2、维基百科-哈希长度扩展攻击

 

点赞

发表评论

电子邮件地址不会被公开。 必填项已用*标注