双重md5加密弱等于

当前做过几道php反序列化题目中含有md5双重加密的判断

发现有两个小知识点

科学计数法弱等于

msedge_h6OmdU0Xrz

比如说这道极客大挑战2025的题目,要求两个值弱等于且不强等于。

由于弱等于可以把字符串转化为数字比较,而强等于限制了二者不能完全相同

所有用到科学计数法,当双重md5后字符串为0e开头后面全是数字,则可以通过弱比较,二者都等于0,且强比较不同,符合题意。这里给出一个python脚本,可以拿来爆破

import hashlib
import string
import multiprocessing

def double_md5(s):
    first_md5 = hashlib.md5(s.encode()).hexdigest()
    second_md5 = hashlib.md5(first_md5.encode()).hexdigest()
    return second_md5

def is_magic_hash(md5_hash):
    return md5_hash.startswith('0e') and md5_hash[2:].isdigit()

def worker_task(args):
    charset, length, start_idx, batch_size, max_results_left = args
    results = []
    count = 0
    for i in range(start_idx, start_idx + batch_size):
        if i >= len(charset) ** length or count >= max_results_left:
            break
        candidate_str = ''
        temp = i
        for j in range(length):
            candidate_str += charset[temp % len(charset)]
            temp //= len(charset)
        hash_result = double_md5(candidate_str)
        if is_magic_hash(hash_result):
            results.append((candidate_str, hash_result))
            count += 1
    return results

def parallel_brute_force(max_results, charset, desc=""):
    max_length = 6
    batch_size = 100000

    found = []
    print(f"\n开始并行暴力破解“{desc}”集,目标找到 {max_results} 个...")

    for length in range(4, max_length + 1):
        print(f"\n搜索长度 {length} 的字符串...")
        total_combinations = len(charset) ** length

        with multiprocessing.Pool(processes=multiprocessing.cpu_count()) as pool:
            tasks = []
            for start_idx in range(0, total_combinations, batch_size):
                left_to_find = max_results - len(found)
                if left_to_find <= 0:
                    break
                tasks.append((charset, length, start_idx, batch_size, left_to_find))

            for i, result_batch in enumerate(pool.imap_unordered(worker_task, tasks)):
                if result_batch:
                    for string_val, hash_val in result_batch:
                        print(f"找到匹配! 字符串: {string_val}, 哈希: {hash_val}")
                        found.append((string_val, hash_val))
                        if len(found) >= max_results:
                            print("已达到目标数量,提前结束")
                            pool.terminate()
                            break
                    if len(found) >= max_results:
                        break
                if i % 10 == 0:
                    progress = min((i + 1) * batch_size, total_combinations)
                    print(f"进度: {progress}/{total_combinations} ({progress/total_combinations*100:.1f}%)")
        if len(found) >= max_results:
            break

    print(f"\n全部找到的魔术hash({desc})如下:")
    for idx, (s, h) in enumerate(found, 1):
        print(f"{idx:02d}. 字符串: {s}, 哈希: {h}")

    return found

if __name__ == "__main__":
    num = int(input("请输入要找到的魔术hash数量: "))
    print("-" * 30)
    # 先用纯字母集爆破
    results_alpha = parallel_brute_force(num, string.ascii_letters, desc="字母")
    print("-" * 30)
    # 再用字母+数字集爆破(不会重复已找到的结果)
    results_alphanum = parallel_brute_force(num, string.ascii_letters + string.digits, desc="字母+数字")

然后这里再给出几个爆破结果

全部找到的魔术hash(字母)如下:
01. 字符串: mBeSja, 哈希: 0e210860082616560753197903773939
02. 字符串: RleoIb, 哈希: 0e165155735388603862205760323672
03. 字符串: IKsHGc, 哈希: 0e022289409330782264224545582392
04. 字符串: LOhlKc, 哈希: 0e852429040529624829369802171953
05. 字符串: iQAwXc, 哈希: 0e999179829757837097870506517663
06. 字符串: KtnAJe, 哈希: 0e787639518490550583554438466566
07. 字符串: LejvIf, 哈希: 0e111484964175819120956442834140
08. 字符串: rjvJNf, 哈希: 0e736903779667020579552711625557
09. 字符串: RwOOei, 哈希: 0e800236998473922397186801398019
10. 字符串: KWMDli, 哈希: 0e081194590188158636719044384199
全部找到的魔术hash(字母+数字)如下:
01. 字符串: iv2Cn, 哈希: 0e759070535261955870964738616588
02. 字符串: O5KIA, 哈希: 0e844204234135990947908741466581
03. 字符串: f2WfQ, 哈希: 0e997766059721689977306698103413
04. 字符串: mBeSja, 哈希: 0e210860082616560753197903773939
05. 字符串: 3cXHka, 哈希: 0e958555339178072545376428935878
06. 字符串: D8Urza, 哈希: 0e238311354792814154407054340292
07. 字符串: WWbd4a, 哈希: 0e749455434249576441309004609713
08. 字符串: RleoIb, 哈希: 0e165155735388603862205760323672
09. 字符串: 4FiJIb, 哈希: 0e301452408972530419353168017689
10. 字符串: iS4XRb, 哈希: 0e161587431976517563275813980840

数字前缀弱等于

如果出现条件:if (md5(md5(“x”)) == 114)

如果我们的字符串x的双重md5加密值为114开头且后面一位是字母(除e加数字外),或者后面的两位是e+字母,则可以通过弱等于(PHP7)

这里给出一个python脚本用于爆破

import hashlib

def double_md5(s):
    h1 = hashlib.md5(s.encode()).hexdigest()
    h2 = hashlib.md5(h1.encode()).hexdigest()
    return h2

def brute_force(prefix, max_count=1, start=0):
    found = 0
    i = start
    prefix_len = len(prefix)
    while found < max_count:
        candidate = str(i)
        result = double_md5(candidate)
        if result.startswith(prefix):
            # 第x+1位
            if len(result) > prefix_len:
                nxt1 = result[prefix_len]
                # 满足:不是数字
                if not nxt1.isdigit():
                    print(f"第{found+1}个: 明文={candidate}, 双md5={result}")
                    found += 1
                # 如果第x+1位是e,则第x+2位不能是数字
                elif nxt1.lower() == 'e' and len(result) > prefix_len + 1:
                    nxt2 = result[prefix_len + 1]
                    if not nxt2.isdigit():
                        print(f"第{found+1}个: 明文={candidate}, 双md5={result}")
                        found += 1
        i += 1

if __name__ == "__main__":
    prefix = input("请输入你想要的双md5前缀:")   # 比如 '1145'
    max_count = int(input("请输入最多爆破多少个:")) # 比如 2
    brute_force(prefix=prefix, max_count=max_count)

因为“数字e数字”会被当成科学计数法解析,比如114e3会被解析为114000(114x10^3)