zoukankan      html  css  js  c++  java
  • 浅谈HASH长度拓展攻击

    前言

    最近在做CTF题的时候遇到这个考点,想起来自己之前在做实验吧的入门CTF题的时候遇到过这个点,当时觉得难如看天书一般,现在回头望去,仔细琢磨一番感觉也不是那么难,这里就写篇文章记录一下自己的学习的过程。

    正文

    何为HASH长度拓展攻击?

    简单的说,由于HASH的生成机制原因,使得我们可以人为的在原先明文数据的基础上添加新的拓展字符,使得原本的加密链变长,进而控制加密链的最后一节,使得我们得以控制最终结果。

    这里我们以MD5加密算法为例子。

    MD5长度拓展攻击

    下面是个简单的PHP例子。

    <?php
    include "flag.php";
    $secretKey = 'xxxxxx'; #xxx为未知内容,但长度已知为6。
    $v1 = $_GET['str'];
    $sign = $_GET['sign'];
    $token = md5($secretKey.$v1);
    if($v1 === 'test') {
        die($token); #token=2df51a84abc64a28740d6d2ae8cd7b16
    } else {
        if($token === $sign) {
            die($flag);
        }
    }
    ?>
    

    在这个例子中,我们需要使得变量$token与我们输入的sign参数满足一致才会输出flag。

    而由于我们无法知道变量$secretKey的内容,所以无法得到$token的值,故而看似是没有办法获取到flag的死局,而这时便轮到我们的拓展攻击来大显身手了。

    MD5算法流程

    若想搞清楚原理,其算法的流程是必须了解的。不过我们无需去关心那些复杂的运算,只需要知道的大概的一个流程就OK了。

    这里借一张神图:

    MD5加密流程

    摘自:哈希长度拓展攻击(Hash Length Extension Attacks)

    看不懂也没关系,相信你看完我这篇文章后再返回来看这张图就很清晰明了了。

    我们还是举个例子,对于字符串aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbb(64个a、3个b)。长度为19个字符,且根据ASCII表,字符a、b的十六进制分别为0x61、0x62。

    而我们知道,1位十六进制相当于4位二进制表示(16=2^4)。所以对于64个字符a的长度来说,其二进制长度为:字符长度*二进制位数2*十六进制转二进制位数拓展4=64*2*4=512

    对于MD5算法来说,我们需要将原数据进行分块处理,以512位个二进制数据为一块。”最后“一块的处理分为以下几种情况:

    • 明文数据的二进制数据长度<=448,填充padding(无意义占位)数据使其长度为448,再添加原始明文数据的二进制长度信息(64位)使其长度为512位即可。
    • 448<明文数据的二进制数据长度<=512,填充padding数据至下一块的448位,而后再添加原始明文数据的二进制长度信息(64位)使其长度为512位即可。

    两种情况如下图:

    第一种情况

    第二种情况

    注意:每块数据的长度均为512位二进制,图中的数据我没有全都用二进制来表示,将明文数据分块之后就可以与向量进行运算了。

    对于padding数据(长度不定)来说:首位二进制位1,其余位为0.

    对于长度信息位(长度8Byte=64bit)来说,从低位向高位数,如上图的长度信息:f0 03 00 00 00 00 00 00即代表0x03f0,其对应的十进制为1008,即为64+62=126个字符的二进制位数(一个字符1Byte即8bit)。

    对于MD5算法来说,有一串初始向量如下:

    A=0x67452301
    B=0xefcdab89
    C=0x98badcfe
    D=0x10325476
    

    这串初始向量的值是固定的,作为与第一块数据运算的原始向量。

    当这串向量与第一块数据块运算之后,得到了一串新的向量值,这串新的向量值接着与第二块数据块参加运算,直到最后一块数据块。

    如下图所示:

    向量运算

    而最后的MD5值就是这最后的向量串经过如下转换的结果。

    如向量串:

    A=0xab45bc01
    B=0x6a64bb53
    C=0x23ba8afe
    D=0x46847a62
    

    先两两为一组进行组合,得到如下数据:

    ab 45 bc 01
    6a 64 bb 53
    23 ba 8a fe
    46 84 7a 62
    

    再进行高低位互换,得到如下数据:

    01 bc 45 ab
    53 bb 64 6a
    fe 8a ba 23
    62 7a 84 46
    

    最终拼接得到MD5值:01bc45ab53bb646afe8aba23627a8446

    现在,让我们回到开始的那个例子。

    对于MD5值:2df51a84abc64a28740d6d2ae8cd7b16。我们可以根据MD5与向量互转规则,将MD5转成md5($secretKey + "test")的最终向量值(A'、B'、C'、D'):

    A'=0x841af52d
    B'=0x284ac6ab
    C'=0x2a6d0d74
    D'=0x167bcde8
    

    过程如图:

    例子向量运算过程

    这时候我们修改$v1变量的内容为:

    "test" + [0x80 + (0x0)*45] + [0x50 + 0x0*7] + "abc"
    相当于:
    "test" + padding数据 + 长度数据 + "abc"
    

    则上述过程则被延续成下图所示:

    延续运算过程

    而对于上述运算过程来说,我们知道了倒数第二个向量串的内容和最后一个数据块,这样一来,最终的MD5值我们也可以自己通过MD5算法计算出来了。

    拓展

    如同MD5算法那般分组后与向量运算的流程被统称为Merkle–Damgård结构。

    而同样使用此结构的HASH算法还有:SHA1、SHA2等

    hashpump

    hashpump是一个专门生成MD5长度拓展攻击payload的工具。

    Github仓库:https://github.com/bwall/HashPump

    安装方法:

    #Linux
    git clone https://github.com/bwall/HashPump.git
    apt-get install g++ libssl-dev
    cd HashPump
    make
    make install
    

    安装好之后在终端里输入hashpump,回车即可:

    hashpump

    以之前的例子为例,使用hashpump生成payload:

    生成payload

    故我们的EXP即为(x%代替):

    /?str=test%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%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00P%00%00%00%00%00%00%00abc&sign=bac6cb2d585d2de3f5f48f2759d2e5a7
    

    成功读取FLAG:

    成功读取FLAG

    CTF

    相关CTF题可供练习:

    • [De1CTF2019]SSRFMe
    • 实验吧-让我进去

    后记

    其实这个知识点确实不难,但是回看两年前的自己,那时候是真的完完全全看不懂看不明白,但是现在只花了十几分钟就可以说是掌握这个知识点了。原来我们不知不觉间也对知识的认知又提升了一个台阶,原先难如天书的内容现在看来也不过尔尔,原先看不到、接触不到的知识,现在也有信心能够去尝试去学习、去理解并掌握。学习本该如此,如攀登高山一般,只有开始攀登,才有机会看得到山脚下看不到的风景,也唯有不断攀登,才能看到更多更多风景。

    参考

  • 相关阅读:
    C/C++中0xcccccccc...
    函数指针定义
    Visual C++的DLL
    RGB
    链接指示:extern "C"
    for_each用法
    漫画 | 夜深了,程序员的电脑却没关,发生了这样的故事…
    漫画 | 小公司卧薪尝胆三年,意外拿到美团offer
    Java 可变参数
    使用程序往Neo4j导入CSV报错
  • 原文地址:https://www.cnblogs.com/yunen/p/13624595.html
Copyright © 2011-2022 走看看