MD5 绕过,MD5 语言
第一题


第二题

首先看过改代码后,发现这只是一个简单的MD5问题,对于该问题它只有俩个量·,一个a一个b,然后下面说a不等于b,但是a和b的MD5值要相等,在MD5的比较中,都是用0e进行绕过,所以总共俩种方法进行绕过
第一种是通过科学计数法进行绕过,一般方法就是构造俩个MD5都为0e的字符串,下面我已经找到俩个常用的,平时有网的话可以用AI进行找到。最后用URL即可得到flag。
第二种方法通过数组进行绕过,这是一个简单暴力的方法。由于MD5()函数无法处理数组,如果传入一个数组的话,MD5()会返回null并警告,所以可以构造URL:?a[]=1&b[]=2 (这里a是数组[1],b是数组[2],他们本身不相同,但是·MD5的结果都是null,所以最后是相等的)
a = QNKCDZO (MD5: 0e830400451993494058024219903391) b = s878926199a (MD5: 0e545993274517709034328855841020)

第三题

这个题没什么好说的,根据代码判断,其a和b依旧相等,MD5的值也要相等,但是题目中限制了不能通过0e的方式绕过,我在题目二中讲出了可以使用数组绕过,所以直接用数组绕过就行了。 如果不用数组的话只能使用MD5的强碰撞.
通常我们不会手工计算(这需要极大的计算量),而是利用现成的工具。最常用的是 Fastcoll。
准备一个原始文件(比如一个简单的文本文件
prefix.txt)。运行工具:
1
fastcoll -p prefix.txt -o msg1.bin msg2.bin
第二步:转换为 URL 编码
由于强碰撞生成的是二进制数据,直接复制粘贴到浏览器地址栏会损坏数据。你需要将这些二进制数据转换成 URL 编码(%形式)。
你可以使用 Python 来快速获取编码后的 Payload:
1
2
3
4
5
6
7
8
9
10import urllib.parse
# 假设你已经生成了两个文件
with open("msg1.bin", "rb") as f:
a = f.read()
with open("msg2.bin", "rb") as f:
b = f.read()
print("a=" + urllib.parse.quote(a))
print("b=" + urllib.parse.quote(b))如果你决定硬碰硬,不使用数组绕过,而是利用MD5 强碰撞(Strong Collision),你的目标是找到两个内容不同但 MD5 值完全一致的二进制字符串。
既然代码限制了 MD5 值不能以
0e开头,强碰撞是完美的解决方案,因为强碰撞产生的 MD5 值通常是随机的十六进制字符,极大概率不会以0e开头。1. 核心原理
MD5 强碰撞是指找到两段不同的数据 $M_1$ 和 $M_2$,使得 $MD5(M_1) = MD5(M_2)$。
在 PHP 中:
$a != $b条件成立(因为数据内容不同)。$md5_a == $md5_b条件成立(因为哈希值完全一样)。
2. 具体操作步骤
第一步:生成碰撞对
通常我们不会手工计算(这需要极大的计算量),而是利用现成的工具。最常用的是 Fastcoll。
准备一个原始文件(比如一个简单的文本文件
prefix.txt)。运行工具:
1
fastcoll -p prefix.txt -o msg1.bin msg2.bin
这会生成两个文件
msg1.bin和msg2.bin,它们的内容在前一部分是一样的,但在末尾会有几处微小的位差异,而它们的 MD5 哈希值将完全相同。
第二步:转换为 URL 编码
由于强碰撞生成的是二进制数据,直接复制粘贴到浏览器地址栏会损坏数据。你需要将这些二进制数据转换成 URL 编码(%形式)。
你可以使用 Python 来快速获取编码后的 Payload:
1
2
3
4
5
6
7
8
9
10import urllib.parse
# 假设你已经生成了两个文件
with open("msg1.bin", "rb") as f:
a = f.read()
with open("msg2.bin", "rb") as f:
b = f.read()
print("a=" + urllib.parse.quote(a))
print("b=" + urllib.parse.quote(b))第三步:提交 Payload
将生成的两段长字符串拼接在 URL 后面:
1
http://.../?a=[编码后的a]&b=[编码后的b]
参数 a: %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%43%36%58%e1%ff%7b%30%ac%27%ca%af%cc%de%db%a1%d8%50%ed%bf%72%b8%ad%70%fa%f2%10%70%3b%1f%46%a3%3c%d0%00%11%af%02%1b%a5%9a%43%f1
参数 b: %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%43%36%58%e1%ff%7b%30%ac%27%ca%af%cc%de%db%a1%d8%50%ed%bf%72%b8%ad%70%fa%f2%12%70%3b%1f%46%a3%3c%d0%00%11%af%02%1b%a5%9a%43%f1
验证:
- 这两段数据的 MD5 值均为:
008ee33a9d58b51cfeb425b0959121c9 - 该哈希值不以
0e开头,满足代码中substr(..., 0, 2) !== '0e'的限制。 - 由于 MD5 完全相同,
==比较必然通过。

第四题

该题分析后得知a和b的值不同,但是MD5的值严格相等,所以还是用数组直接拿到flag。1

第五题

本题并没有向上面题一样使用MD5弱类型的比较,而是让我们去找QC它的MD5的值最后六位为d54e23的字符串,我们可以通过ai或者自己编写一个python脚本找到这么一个值。输入拿到flag。
1 | import hashlib |

第六题

通过对代码的分析
1 | $admin_hash = '0e830400451993494058024219903391'; |
看到该代码hash后面为0e+一堆数字,并且只有一个等号,php代码中这个值就为0了,qc的值为0,即可得到true,所以只要找一个字符串,下面为几个常用的字符串,代入找到flag。
| 原始字符串 (QC) | MD5 结果 (hp) |
|---|---|
QNKCDZO |
0e830400451993494058024219903391 |
s878926199a |
0e545993274517709034328855841020 |
s155964671a |
0e342768416822451524974117254469 |

第七题

这里涉及到一个新的函数sha1() 是 PHP 中的一个内置函数,全称是 Secure Hash Algorithm 1(安全哈希算法 1)。
它的作用和 md5() 非常相似:将任意长度的字符串“粉碎”并转化成一个固定长度(40位十六进制字符)的哈希值(指纹)。
SHA-1 的特点
- 输出长度:MD5 输出 32 位,而 SHA-1 输出 40 位。
- 不可逆性:你不能从哈希值反推出原始数据。
- 碰撞性:虽然理论上不同输入对应不同输出,但由于输出长度有限,存在“碰撞”的可能(即两个不同输入产生相同输出)。
该题可以直接用数组绕过,但是它涉及了sha1我们可以找到其中的值,下面是一组常用的payload,当然也可以用脚本找到值,或者让AI帮你,喵喵喵。
常用 Payload:
a = aaroZmOk(SHA-1:0e66507019969427134894567494305185566735)b = aaK1STpo(SHA-1:0e76658526655756207688271159624026011393)

