MD5绕过

1
2
3
对于:(string)$_GET['md5_1'] !== (string)$_GET['md5_2'] && md5($_GET['md5_1']) === md5($_GET['md5_2'])
● md5_1=%af%13%76%70%82%a0%a6%58%cb%3e%23%38%c4%c6%db%8b%60%2c%bb%90%68%a0%2d%e9%47%aa%78%49%6e%0a%c0%c0%31%d3%fb%cb%82%25%92%0d%cf%61%67%64%e8%cd%7d%47%ba%0e%5d%1b%9c%1c%5c%cd%07%2d%f7%a8%2d%1d%bc%5e%2c%06%46%3a%0f%2d%4b%e9%20%1d%29%66%a4%e1%8b%7d%0c%f5%ef%97%b6%ee%48%dd%0e%09%aa%e5%4d%6a%5d%6d%75%77%72%cf%47%16%a2%06%72%71%c9%a1%8f%00%f6%9d%ee%54%27%71%be%c8%c3%8f%93%e3%52%73%73%53%a0%5f%69%ef%c3%3b%ea%ee%70%71%ae%2a%21%c8%44%d7%22%87%9f%be%79%6d%c4%61%a4%08%57%02%82%2a%ef%36%95%da%ee%13%bc%fb%7e%a3%59%45%ef%25%67%3c%e0%27%69%2b%95%77%b8%cd%dc%4f%de%73%24%e8%ab%66%74%d2%8c%68%06%80%0c%dd%74%ae%31%05%d1%15%7d%c4%5e%bc%0b%0f%21%23%a4%96%7c%17%12%d1%2b%b3%10%b7%37%60%68%d7%cb%35%5a%54%97%08%0d%54%78%49%d0%93%c3%b3%fd%1f%0b%35%11%9d%96%1d%ba%64%e0%86%ad%ef%52%98%2d%84%12%77%bb%ab%e8%64%da%a3%65%55%5d%d5%76%55%57%46%6c%89%c9%5f%b2%3c%85%97%1e%f6%38%66%c9%17%22%e7%ea%c9%f5%d2%e0%14%d8%35%4f%0a%5c%34%d3%f3%a5%98%f7%66%72%aa%43%e3%bd%a2%cd%62%fd%e9%1d%34%30%57%52%ab%41%b1%91%65%f2%30%7f%cf%c6%a1%8c%fb%dc%c4%8f%61%a5%13%40%1a%13%d1%09%c5%e0%f7%87%5f%48%e7%d7%b3%62%04%a7%c4%cb%fd%f4%ff%cf%3b%74%a8%1b%96%8e%09%73%3a%9b%a6%2f%ed%b7%99%d5%39%05%39%95%ab
● md5_2=%af%13%76%70%82%a0%a6%58%cb%3e%23%38%c4%c6%db%8b%60%2c%bb%90%68%a0%2d%e9%47%aa%78%49%6e%0a%c0%c0%31%d3%fb%cb%82%25%92%0d%cf%61%67%64%e8%cd%7d%47%ba%0e%5d%1b%9c%1c%5c%cd%07%2d%f7%a8%2d%1d%bc%5e%2c%06%46%3a%0f%2d%4b%e9%20%1d%29%66%a4%e1%8b%7d%0c%f5%ef%97%b6%ee%48%dd%0e%09%aa%e5%4d%6a%5d%6d%75%77%72%cf%47%16%a2%06%72%71%c9%a1%8f%00%f6%9d%ee%54%27%71%be%c8%c3%8f%93%e3%52%73%73%53%a0%5f%69%ef%c3%3b%ea%ee%70%71%ae%2a%21%c8%44%d7%22%87%9f%be%79%6d%c4%61%a4%08%57%02%82%2a%ef%36%95%da%ee%13%bc%fb%7e%a3%59%45%ef%25%67%3c%e0%27%69%2b%95%77%b8%cd%dc%4f%de%73%24%e8%ab%66%74%d2%8c%68%06%80%0c%dd%74%ae%31%05%d1%15%7d%c4%5e%bc%0b%0f%21%23%a4%96%7c%17%12%d1%2b%b3%10%b7%37%60%68%d7%cb%35%5a%54%97%08%0d%54%78%49%d0%93%c3%b3%fd%1f%0b%35%11%9d%96%1d%ba%64%e0%86%ad%ef%52%98%2d%84%12%77%bb%ab%e8%64%da%a3%65%55%5d%d5%76%55%57%46%6c%89%c9%df%b2%3c%85%97%1e%f6%38%66%c9%17%22%e7%ea%c9%f5%d2%e0%14%d8%35%4f%0a%5c%34%d3%73%a5%98%f7%66%72%aa%43%e3%bd%a2%cd%62%fd%69%1d%34%30%57%52%ab%41%b1%91%65%f2%30%7f%cf%c6%a1%8c%fb%dc%c4%8f%61%a5%93%40%1a%13%d1%09%c5%e0%f7%87%5f%48%e7%d7%b3%62%04%a7%c4%cb%fd%f4%ff%cf%3b%74%28%1c%96%8e%09%73%3a%9b%a6%2f%ed%b7%99%d5%b9%05%39%95%ab

MD5值相等的字符串

1
2
●  %4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%00%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%55%5d%83%60%fb%5f%07%fe%a2 
● %4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%02%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%d5%5d%83%60%fb%5f%07%fe%a2

MD5值为0e开头的字符

1
2
3
4
5
6
7
8
9
10
11
12
s878926199a
s155964671a
s214587387a
s214587387a
2406107080e462097431906509019562988736854
QLTHNDT:0e405967825401955372549139051580
QNKCDZO:0e830400451993494058024219903391
PJNPDWY:0e291529052894702774557631701704
NWWKITQ:0e763082070976038347657360817689
NOOPCJF:0e818888003657176127862245791911
MMHUWUV:0e701732711630150438129209816536
MAUXXQC:0e478478466848439040434801845361

sha1值相等的字符串

1
2
● array1=%25PDF-1.3%0A%25%E2%E3%CF%D3%0A%0A%0A1%200%20obj%0A%3C%3C/Width%202%200%20R/Height%203%200%20R/Type%204%200%20R/Subtype%205%200%20R/Filter%206%200%20R/ColorSpace%207%200%20R/Length%208%200%20R/BitsPerComponent%208%3E%3E%0Astream%0A%FF%D8%FF%FE%00%24SHA-1%20is%20dead%21%21%21%21%21%85/%EC%09%239u%9C9%B1%A1%C6%3CL%97%E1%FF%FE%01%7FF%DC%93%A6%B6%7E%01%3B%02%9A%AA%1D%B2V%0BE%CAg%D6%88%C7%F8K%8CLy%1F%E0%2B%3D%F6%14%F8m%B1i%09%01%C5kE%C1S%0A%FE%DF%B7%608%E9rr/%E7%ADr%8F%0EI%04%E0F%C20W%0F%E9%D4%13%98%AB%E1.%F5%BC%94%2B%E35B%A4%80-%98%B5%D7%0F%2A3.%C3%7F%AC5%14%E7M%DC%0F%2C%C1%A8t%CD%0Cx0Z%21Vda0%97%89%60k%D0%BF%3F%98%CD%A8%04F%29%A1
● &array2=%25PDF-1.3%0A%25%E2%E3%CF%D3%0A%0A%0A1%200%20obj%0A%3C%3C/Width%202%200%20R/Height%203%200%20R/Type%204%200%20R/Subtype%205%200%20R/Filter%206%200%20R/ColorSpace%207%200%20R/Length%208%200%20R/BitsPerComponent%208%3E%3E%0Astream%0A%FF%D8%FF%FE%00%24SHA-1%20is%20dead%21%21%21%21%21%85/%EC%09%239u%9C9%B1%A1%C6%3CL%97%E1%FF%FE%01sF%DC%91f%B6%7E%11%8F%02%9A%B6%21%B2V%0F%F9%CAg%CC%A8%C7%F8%5B%A8Ly%03%0C%2B%3D%E2%18%F8m%B3%A9%09%01%D5%DFE%C1O%26%FE%DF%B3%DC8%E9j%C2/%E7%BDr%8F%0EE%BC%E0F%D2%3CW%0F%EB%14%13%98%BBU.%F5%A0%A8%2B%E31%FE%A4%807%B8%B5%D7%1F%0E3.%DF%93%AC5%00%EBM%DC%0D%EC%C1%A8dy%0Cx%2Cv%21V%60%DD0%97%91%D0k%D0%AF%3F%98%CD%A4%BCF%29%B1

使用ffifdyop万能密码绕过。ffifdyop的MD5加密结果是276f722736c95d99e921722cf9ed621c,经过MySQL编码后会变成'or'6xxx,使SQL恒成立,相当于万能密码,可以绕过md5()函数的加密。关键参数为md5(xx,true)。

MD5弱比较和强比较都可以利用数组绕过

1
2
3
4
5
6
7
8
9
// 弱比较
$param1 != $param2 && md5($param1) == md5($param2)

// 强比较
$param1 != $param2 && md5($param1) === md5($param2)
// payload

param1[]=1
param2[]=2

null

如果加入了 (string) 进行比较

1
2
3
4
5
6
7
(string)$param1 !== (string)$param2 && md5($param1) === md5($param2)

(string)$param1 !== (string)$param2 && md5((string)$param1) === md5((string)$param2)
// payload

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%00%A8%28K%F3n%8EKU%B3_Bu%93%D8Igm%A0%D1U%5D%83%60%FB_%07%FE%A2
param2=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

要用bp传,hackbar不行,这个payload也可以绕过前面的不加(string)

测试代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
highlight_file(__FILE__);
error_reporting(0);

$param1 = $_POST['param1'];
$param2 = $_POST['param2'];

$a = ($param1 !== $param2 && md5($param1) == md5($param2));
$b = ($param1 !== $param2 && md5($param1) === md5($param2));
$c = ((string)$param1 !== (string)$param2 && md5($param1) === md5($param2));
$d = ((string)$param1 !== (string)$param2 && md5((string)$param1) === md5((string)$param2));

var_dump($a);
var_dump($b);
var_dump($c);
var_dump($d);

?>

null

两次MD5加密

跑这个脚本看人品)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
import hashlib
import threading
import random
import string
import time
import sys
import os

# 配置参数
CHARSET = string.ascii_lowercase + string.digits # 小写字母+数字
MIN_LENGTH = 10 # 最小字符串长度
MAX_LENGTH = 12 # 最大字符串长度
NUM_THREADS = os.cpu_count() * 4 # 线程数量(根据CPU核心数调整)
PRINT_INTERVAL = 10000 # 每处理多少字符串打印一次进度
SMART_MODE = True # 是否使用智能模式(基于已知模式生成字符串)

# 全局变量
found_count = 0
processed_count = 0
start_time = time.time()
lock = threading.Lock()
running = True


def is_valid_hash(hash_str):
"""检查哈希是否以'0e'开头且后面全是数字"""
return hash_str.startswith("0e") and hash_str[2:].isdigit()


def generate_random_string(length):
"""生成随机字符串"""
return ''.join(random.choices(CHARSET, k=length))


def generate_smart_string():
"""生成智能模式字符串(基于已知有效字符串模式)"""
# 已知有效字符串通常以's'开头,以'a'结尾
length = random.randint(MIN_LENGTH, MAX_LENGTH)
if length < 3:
return generate_random_string(length)

# 中间部分随机生成
middle = ''.join(random.choices(CHARSET, k=length - 2))
return 's' + middle + 'a'


def worker():
"""工作线程函数"""
global found_count, processed_count

while running:
# 生成字符串
if SMART_MODE and random.random() > 0.3: # 70%概率使用智能模式
s = generate_smart_string()
else:
length = random.randint(MIN_LENGTH, MAX_LENGTH)
s = generate_random_string(length)

# 计算两次MD5
try:
first_md5 = hashlib.md5(s.encode()).hexdigest()
second_md5 = hashlib.md5(first_md5.encode()).hexdigest()
except:
continue

# 检查是否满足条件
if is_valid_hash(second_md5):
with lock:
found_count += 1
print(f"\n🔥 发现有效字符串 #{found_count}: {s}")
print(f" 第一次MD5: {first_md5}")
print(f" 第二次MD5: {second_md5}")
print("-" * 60)

# 更新计数
with lock:
processed_count += 1


def print_progress():
"""打印进度信息"""
global processed_count, found_count

while running:
elapsed = time.time() - start_time
speed = processed_count / elapsed if elapsed > 0 else 0

# 每处理一定数量打印一次进度
if processed_count % PRINT_INTERVAL == 0:
sys.stdout.write(
f"\r已处理: {processed_count} | 发现: {found_count} | "
f"速度: {speed:.2f} 字符串/秒 | 运行时间: {elapsed:.0f}秒"
)
sys.stdout.flush()

time.sleep(0.1)


def main():
global running

print("=" * 60)
print("🔥 两次MD5后为0e开头的字符串爆破工具")
print("=" * 60)
print(f"配置:")
print(f" 字符集: {CHARSET}")
print(f" 长度范围: {MIN_LENGTH}-{MAX_LENGTH}")
print(f" 线程数: {NUM_THREADS}")
print(f" 智能模式: {'启用' if SMART_MODE else '禁用'}")
print("=" * 60)
print("开始爆破... (按 Ctrl+C 停止)")
print("-" * 60)

# 启动工作线程
threads = []
for i in range(NUM_THREADS):
t = threading.Thread(target=worker, daemon=True)
t.start()
threads.append(t)

# 启动进度打印线程
progress_thread = threading.Thread(target=print_progress, daemon=True)
progress_thread.start()

# 主线程等待键盘中断
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
print("\n\n🛑 用户中断,停止爆破...")
running = False

# 等待所有线程结束
for t in threads:
t.join(timeout=1.0)
progress_thread.join(timeout=0.5)

# 打印最终结果
elapsed = time.time() - start_time
print("\n" + "=" * 60)
print("💡 爆破完成!")
print("-" * 60)
print(f" 总共处理字符串: {processed_count}")
print(f" 发现有效字符串: {found_count}")
print(f" 总运行时间: {elapsed:.2f}秒")
print(f" 平均速度: {processed_count / elapsed:.2f} 字符串/秒")
print("=" * 60)

# 如果找到了结果,打印提示
if found_count > 0:
print("\n💡 提示: 您可以使用这些字符串来测试MD5比较漏洞")
else:
print("\n⚠️ 未找到有效字符串,建议:")
print(" - 增加字符串长度范围")
print(" - 增加运行时间")
print(" - 扩展字符集(如添加大写字母)")


if __name__ == "__main__":
main()


# 发现有效字符串#1:hzn3ei1zvn
# 第一次MD5:2f33b58832dc2d2a59892617f9cd5c2c
# 第二次MD5:0e004457213733467269598504313421
1
2
hzn3ei1zvn
sqxxdebuqra

MD5绕过
https://yschen20.github.io/2025/04/25/MD5绕过/
作者
Suzen
发布于
2025年4月25日
更新于
2025年11月6日
许可协议