3rsh1
/single dog/college student/ctfer
3rsh1's Blog

用MD5实现hash长度扩展攻击

MD5实现hash长度拓展攻击

md5算法

这里再补充一下。
一个字节有八个二进制位,而四个二进制位可以转化为十六进制的一位,因此,一个字节由两个十六进制位组成。

大小端模式:
大端模式:指数据的高字节,保存在内存的低地址中,而数据的低字节,保存在内存的高地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放;
小端模式:指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中,这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低,和我们的逻辑方法一致。
例子:

0x1234
大端序:0x1234
小端序:0x
<?php
echo hexdec('\x1000')."\n"; //4096
echo hexdec('\x0010');  //16
?>

我们可以看出上述两行代码的最后结果是不同的,就是因为端序不同。而小端序是自左向右由小到大,大端序是自左向右由大到小(粗略)。
md5在存储的时候就是小端序。因此在将md5值转化为十六进制的时候需要进行一些转化,通常十六进制是以2位为一个单位进行转化。

echo md5('test');
//098f6bcd4621d373cade4e832627b4f6
//098f6bcd 4621d373 cade4e83 2627b4f6
//0xcd6b8f09 .......
https://www.3rsh1.cool/wp-content/uploads/2020/04/wp_editor_md_9e9eddd4d9e195fb9d4743c35fdf78ce.jpg

对于一串需要md5加密的字符串,系统会先将其按64个字节为一组分成若干组,未达到64个字节即512二进制位的组进行填充处理,填充部分包括:

二进制:10000000...+字符串长度(64二进制位)
十六进制:8000000.....+字符串长度(16个十六进制位)
填充部分为小端序。

md5值的长度一般为32个十六进制位,128个二进制位。
填充完成后会将分组再次分为16个以四个字节为单位的子分组,进行以链接变量为默认ABCD的神奇运算,每次计算最终得出来的为32位十六进制数。之后再对得出来的32位数进行转化,即四等分,得出的四部分作为下一个子分组的链接变量进行计算。算到最后得到的结果就是整个字符串的md5值。

若是需要加密字符串的长度大于64个字节,即分组之后得到分组1,分组2…. 这样的话,分组1的md5值会作为分组2的初始链式变量进行计算。最后得出来的md5值即为整个字符串的md5值。

以上便是md5值的计算过程。

长度拓展攻击原理

if (COOKIE["getmein"] === md5(secret . urldecode($key)))

假设需要绕过以上语句。
且已知:sercet变量的长度为15位和md5值(098f6bcd4621d373cade4e832627b4f6)。可控变量key,getmein。

getmein通过cookie传递给服务端,key通过post传值传递给服务端。
需要我们构造key值的形式,以及算出全等左边的md5值。

因为sercet的长度为15位不妨假设sercet值为aaaaabbbbbccccc。构造如下形态:

$a='aaaaabbbbbccccc'+"\x80"+"\x00"*40+"\x78"+"\x00"*7   //512个二进制位,128个16进制位,64个字节,其中15个字节为sercet长度,一个字节为特殊补充,8个字节表示字符串长度。
$b=$a+'balabala';
$key=$b[15:];

如此构造的话,服务端在接受到key值的时候,先分为两个64字节的组,并自动补全第二个组的剩余部分。
然后会先计算第一个组的md5值,计算完成后利用第一个组的md5值作为链接变量计算第二个组的md5值作为最终的md5值。
而我们则是已经掌握了第一个组的md5值,利用第一个组的md5值我们可以计算出来最终的md5值。作为getmein的值传递给客户端,同时构造的key值作为sercet的值post给客户端。
具体流程:

md5(secret.key)

secret  长度,md5值
构造:key=填充部分1+key+填充部分2      //填充部分1包含secret的长度+\x00

根据secret的md5值,确定下一个分组的ABCD值。
攻击者:利用修改md5源码的方式修改ABCD的值,来算出md5(secret.key)的值
服务端:根据传输过来的key值,计算md5值。

因此攻击者可以计算md5值。

相关工具

hashpump工具

    -s --signature来自已知消息的签名。
    -d --data来自已知消息的数据。
    -a --additional您要添加到已知消息的信息。
    -k --keylength 用于对原始消息进行签名的密钥的长度(以字节为单位)。

    -s 是指知道的哈希值
    -k 是进行签名的长度
    -d 已知的数据
    -a 添加上去的已知数据

用法:
直接拿实验吧的例题来讲:

http://ctf5.shiyanbar.com/web/kzhan.php

源码如下:

<?php

flag = "flag{flag is here}";secret = "aaaaabbbbbccccc"; // 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
    }
}
?>
bp抓包,source改为1得到源码。
sample_hash:571580b26c65f306376d4f64e53cb5c7
sercet为15位,加上后面的admin为20位。第二个admin看作已知数据。
hashpump -s 571580b26c65f306376d4f64e53cb5c7 -d admin -k 20 -a pcat
得到:
3e67e8f0c05e1ad68020df30bbc505f5
admin\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc8\x00\x00\x00\x00\x00\x00\x00pcat

第一行为计算出来的最后的md5值。
第二行为passwd值。
\x换为%即可。

参考链接:

https://www.cnblogs.com/pcat/p/5478509.html
https://blog.csdn.net/qq_35078631/article/details/70941204
https://www.cnblogs.com/p00mj/p/6288337.html

发表评论

textsms
account_circle
email

3rsh1's Blog

用MD5实现hash长度扩展攻击
MD5实现hash长度拓展攻击 md5算法 这里再补充一下。 一个字节有八个二进制位,而四个二进制位可以转化为十六进制的一位,因此,一个字节由两个十六进制位组成。 大小端模式: 大端模式…
扫描二维码继续阅读
2020-04-22