• MD5碰撞


    前言:

    CTF中可以说是经常碰到md5加密了,一般都是进行强比较抑或是弱比较,考法非常多,但是万变不离其中。只要我们掌握了原理,一切问题便迎刃而解了。

    文章首发于 我的博客 ,格式可能比较清晰,有兴趣了解CTF中MD5碰撞的伙伴可以移步查看

    简单了解MD5:

    • md5是一种加密算法,并且不能防止碰撞破解
    • md5加密是不可逆的,这就意味着有两串不同的字符串加密出来的内容却是相同的
    • 加密过程简单,碰撞还原字符难

    PHP的弱比较:

    先提两个例子:

    var_dump("123a"==123)

    var_dump("123a"=="123")

    在没有认真总结前,完全不知道弱比较还要区分字符串类型比较还是与int类型比较

    上述实例的结果是:

    True

    False

    字符串与int类型比较:

    PHP规定当进行字符串与数字的弱比较时,会进行如下步骤

    先看字符串开头是否为数字,如果为数字,则截止到连续数字的最后一个数字,即"123abc456"=>123

    如果开头不为数字,则判断为false,即0。因此

    ("aaa123"==0) =>true

    ("123a"==123) =>true

    思维导图:

    字符串与字符串比较:

    正如上面所言:

    var_dump("123a"=="123"); //False

    因为这个是字符串之间进行比较,想要绕过这个弱比较只能用0e的方式。

    在PHP中"0e"判断为科学计数法,0e123就是0的10123次方

    不难推出:0e123456789==0e1 // 因为0的任意次方都为0

    不过有一个注意点:

    "0e123456"=="0e345" //True

    "0e12adfc"=="0e345" //False

    在0e后面不能含有字母!!!

    在0e后面不能含有字母!!!

    在0e后面不能含有字母!!!

    否则判断为False

    #实例

    if("0e23253"=="0e2345")

    {

    echo 'yes';

    }

    ?>

    输出:

    yes

    CTF的MD5弱比较

    在CTF中,会遇到如下的MD5弱比较题目

    1.md5($a)==md5($b) & $a != $b

    这个时候就要利用0e的形式来解题,找到两个不同字符,md5加密后却都是0e324234的形式。如何寻找这样的字符串?

    1.脚本寻找

    # -*- coding: utf-8 -*-
    import multiprocessing
    import hashlib
    import random
    import string
    import sys
    
    CHARS = string.ascii_letters + string.digits
    
    
    def cmp_md5(substr, stop_event, str_len, start=0, size=20):
        global CHARS
        while not stop_event.is_set():
            rnds = ''.join(random.choice(CHARS) for _ in range(size))
            md5 = hashlib.md5(rnds)
            value = md5.hexdigest()
            if value[start: start + str_len] == substr:
                # print rnds
                # stop_event.set()
    
                # 碰撞双md5
                md5 = hashlib.md5(value)
                if md5.hexdigest()[start: start + str_len] == substr:
                    print rnds + "=>" + value + "=>" + md5.hexdigest() + "\n"
                    stop_event.set()
    
    
    
    if __name__ == '__main__':
        substr = sys.argv[1].strip()
        start_pos = int(sys.argv[2]) if len(sys.argv) > 1 else 0
        str_len = len(substr)
        cpus = multiprocessing.cpu_count()
        stop_event = multiprocessing.Event()
        processes = [multiprocessing.Process(target=cmp_md5, args=(substr,
                                                                   stop_event, str_len, start_pos))
                     for i in range(cpus)]
        for p in processes:
            p.start()
        for p in processes:
            p.join()

    用法:

    输入命令

    python md5.py "0e" 0

    "0e" =>要跑的字符

    0 =>要跑的字符的起始位置

    脚本寻找要浪费大概十分钟左右的时间才能找出一个,可以用网上现成的,如果题目要求比较特殊的话,再利用自己的脚本跑

    2.百度

    MMHUWUV 0e701732711630150438129209816536

    MAUXXQC 0e478478466848439040434801845361

    IHKFRNS 0e256160682445802696926137988570

    GZECLQZ 0e537612333747236407713628225676

    GGHMVOE 0e362766013028313274586933780773

    GEGHBXL 0e248776895502908863709684713578

    EEIZDOI 0e782601363539291779881938479162

    DYAXWCA 0e424759758842488633464374063001

    这样子就出flag了

    2.$a==md5($a)

    这一类题型要求满足$a是0e开头,且加密后也是0e开头

    在网上收集了这些结果:

    0e215962017 0e291242476940776845150308577824

    0e1284838308 0e708279691820928818722257405159

    0e1137126905 0e291659922323405260514745084877

    0e807097110 0e318093639164485566453180786895

    0e730083352 0e870635875304277170259950255928

    弱比较主要就是以上两种类型。

    CTF的MD5强比较

    1.md5($a)===md5($b) & $a != $b

    方法一:

    数组绕过

    md5_1[]=1&md5_2[]=2

    因为PHP对无法md5加密的东西不加密,结果为NULL,虽然会报错,但是null=null,逻辑关系为True。所以可以输出flag

    方法二:

    两串不一样的字符,加密结果却相同:

    $a=M%C9h%FF%0E%E3%5C%20%95r%D4w%7Br%15%87%D3o%A7%B2%1B%DCV%B7J%3D%C0x%3E%7B%95%18%AF%BF%A2%02%A8%28K%F3n%8EKU%B3_Bu%93%D8Igm%A0%D1%D5%5D%83%60%FB_%07%FE%A2

    $b=M%C9h%FF%0E%E3%5C%20%95r%D4w%7Br%15%87%D3o%A7%B2%1B%DCV%B7J%3D%C0x%3E%7B%95%18%AF%BF%A2%00%A8%28K%F3n%8EKU%B3_Bu%93%D8Igm%A0%D1U%5D%83%60%FB_%07%FE%A2

    这个我的脚本就跑不出来了,是网上收集的。

    题目实战:

    1.[BJDCTF2020]Easy MD5

     
    

    这题也是两个解法:

    法一:

    param1[]=1¶m2[]=2

    法二:

    param1=M%C9h%FF%0E%E3%5C%20%95r%D4w%7Br%15%87%D3o%A7%B2%1B%DCV%B7J%3D%C0x%3E%7B%95%18%AF%BF%A2%02%A8%28K%F3n%8EKU%B3_Bu%93%D8Igm%A0%D1%D5%5D%83%60%FB_%07%FE%A2¶m2=M%C9h%FF%0E%E3%5C%20%95r%D4w%7Br%15%87%D3o%A7%B2%1B%DCV%B7J%3D%C0x%3E%7B%95%18%AF%BF%A2%00%A8%28K%F3n%8EKU%B3_Bu%93%D8Igm%A0%D1U%5D%83%60%FB_%07%FE%A2

    2.强网杯2020——Funhash

    query($query);
    $row = $result->fetch_assoc(); 
    var_dump($row);
    $result->free();
    $mysqli->close();
    ?> 
    

    levle 1

    很明显,这种是要md4加密,并且是"0e"+"数字" 加密后还是"0e"+"数字"的形式,上脚本:

    import multiprocessing
    import hashlib
    import random
    import string
    import sys
    
    CHARS = string.digits
    
    
    def cmp_md4(substr, stop_event, str_len, start=0, size=18):
        global CHARS
        while not stop_event.is_set():
            rnds = ''.join(random.choice(CHARS) for _ in range(size))
            rnds = "0e"+rnds
            md4 = hashlib.new('md4', rnds.encode("utf-8"))
            value = md4.hexdigest()
            if value[start: start + str_len] == substr:
                print(value)
                if value[2:].isdigit():
                    print(rnds)
                    stop_event.set()
                    
    if __name__ == '__main__':
        substr = sys.argv[1].strip()
        start_pos = int(sys.argv[2]) if len(sys.argv) > 1 else 0
        str_len = len(substr)
        cpus = multiprocessing.cpu_count()
        stop_event = multiprocessing.Event()
        processes = [multiprocessing.Process(target=cmp_md4, args=(substr,
                                                                   stop_event, str_len, start_pos))
                     for i in range(cpus)]
        for p in processes:
            p.start()
        for p in processes:
            p.join()                

    测试一下,可行

    level 2

    法一:

    hash2[]=1&hash3[]=2

    法二:

    hash2=M%C9h%FF%0E%E3%5C%20%95r%D4w%7Br%15%87%D3o%A7%B2%1B%DCV%B7J%3D%C0x%3E%7B%95%18%AF%BF%A2%02%A8%28K%F3n%8EKU%B3_Bu%93%D8Igm%A0%D1%D5%5D%83%60%FB_%07%FE%A2&hash3=M%C9h%FF%0E%E3%5C%20%95r%D4w%7Br%15%87%D3o%A7%B2%1B%DCV%B7J%3D%C0x%3E%7B%95%18%AF%BF%A2%00%A8%28K%F3n%8EKU%B3_Bu%93%D8Igm%A0%D1U%5D%83%60%FB_%07%FE%A2

    level 3

    结果:

    只要构造 xx 'or xxxx 的形式就可以了

    具体可以看这篇文章

    3.构造特定字符串

    这个是我觉得以后为了避免大家都用现有的收集字符串解题而出的,比如:

    要构造一个开头是123且后面是字母的字符串:

    脚本:

    import multiprocessing
    import hashlib
    import random
    import string
    import sys
    
    CHARS = string.ascii_letters + string.digits
    
    
    def cmp_md5(substr, stop_event, str_len, start=0, size=20):
        global CHARS
        while not stop_event.is_set():
            rnds = ''.join(random.choice(CHARS) for _ in range(size))
            md5 = hashlib.md5(rnds)
            value = md5.hexdigest()
            if value[start: start + str_len] == substr:
                print rnds
                print value
                stop_event.set()
                
                
                if __name__ == '__main__':
                    substr = sys.argv[1].strip()
                    start_pos = int(sys.argv[2]) if len(sys.argv) > 1 else 0
                    str_len = len(substr)
                    cpus = multiprocessing.cpu_count()
                    stop_event = multiprocessing.Event()
                    processes = [multiprocessing.Process(target=cmp_md5, args=(substr,
                                                                               stop_event, str_len, start_pos))
                                 for i in range(cpus)]
                    for p in processes:
                        p.start()
                        for p in processes:
            p.join()

    终端输入python .\MD5碰撞.py "123" 0

    实践试一下:

    注意点:跑出来的123后面第一个字符要是字母,如果不是多跑几次,概率还是挺大的。

    尾言

    还有关于双md5的题目等等,只要掌握了这些思想,看到题目就能想到解法了。这个脚本也是面向百度编程找到的,有一个脚本能跑是比较好的,可以应对各种新情况。使用python脚本是因为有多线程模式,速度更快。

    如果代码有不清晰的可以移步 我的博客,因为是直接搬过来的,可能有些地方有点不太好看

  • 相关阅读:
    VVC系列(三)xCompressCTU、xCompressCU和xCheckModeSplit解析
    使用Delaunay三角剖分进行数据分析与可视化
    Django框架之介绍与启动
    OFD文件WEB前端展示-easyofd(1.0.6)
    千亿级大数据如何存储的?
    自学(黑客)技术方法————网络安全
    程序员究竟是搞技术的,还是做工程的?
    Node.js操作MySQL8.0数据库无法连接
    腾讯云88,阿里云99,现在都这么卷了吗?!
    论文投稿前需要检查下参考文献
  • 原文地址:https://blog.csdn.net/qq_64201116/article/details/126493091