CTF中有几个MD5绕过的技巧
这里总结一下,顺便记录一下MD5碰撞的一些工具和脚本(春节鸽了好久
MD5函数漏洞
$str1 = $_GET['str1'];
$str2 = $_GET['str2'];
if (md5($str1) == md5($str2)) {
die('OK');
}
这个其实不是MD5函数的锅,而是php弱类型比较产生的漏洞
想要满足这个判断只需要构造出MD5值为0e
开头的字符串,这样的话弱类型比较会认为是科学技术法,0的多少次方都是0,因此可以绕过
有一些字符串的MD5值为0e开头,这里记录一下
- QNKCDZO
- 240610708
- s878926199a
- s155964671a
- s214587387a
还有MD5和双MD5以后的值都是0e
开头的
- CbDLytmyGm2xQyaLNhWn
- 770hQgrBOjrcqftrlaZk
- 7r4lGXCH2Ksu2JNT3BYM
脚本贴上
# -*- coding: utf-8 -*-
import multiprocessing
import hashlib
import random
import string
import sys
CHARS = string.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()
PHP特性
比如这段
$str1 = $_GET['str1'];
$str2 = $_GET['str2'];
if (md5($str1) === md5($str2)) {
die('OK');
}
因为是强类型比较,用0e
开头的字符串是没办法绕过的了,但是PHP自身的特性使得可以提交一个数组
而md5函数传入数组的返回值都是NULL,这样就可以绕过强类型比较了
所以这里用GET传入?str1[]=1&str2[]=2
就行了
MD5碰撞
比如这个程序
$str1 = (string)$_GET['str1'];
$str2 = (string)$_GET['str2'];
if (md5($str1) === md5($str2)) {
die('OK');
}
由于强制类型转换,传数组就不可行了,这里就需要MD5碰撞
对于需要两个内容不同但是MD5值相同的文件,使用Fastcoll就可以了
macOS编译各种error,实在搞不来了,只好用win虚拟机跑了
./fastcoll -o file1 file2
可以看到MD5值完全相同,但是文件并不一样
但是当需要三个MD5值相同的文件怎么办
这里bdwms找到了个13年的ctf题的WP,是需要5个相同MD5值的可执行文件,这里照着做就可以得到5个不同但MD5值相同的文件了
原理没有看太懂,大致就是在base文件尾部附加内容使得MD5值相同
MD5(file + col1_a + col2_a) === MD5(file + col1_a + col2_b) === MD5(file + col1_b + col2_a) === MD5(file + col1_b + col2_b)
照着做,生成几个文件,然后用python脚本拼接一下
base = open('a').read()
file_1 = open('b').read()
coll_1 = file_1[len(base):]
file_2 = open('c').read()
coll_2 = file_2[len(base):]
file_1_1 = open("e").read()
coll_1_1 = file_1_1[len(file_1):]
file_1_2 = open("f").read()
coll_1_2 = file_1_2[len(file_2):]
file_1_1_1 = open("g").read()
file_1_1_2 = open("h").read()
coll_1_1_1 = file_1_1_1[len(file_1_1):]
coll_1_1_2 = file_1_1_2[len(file_1_2):]
def w(fn, data):
f = open("out/" + fn, "w")
f.write(data)
f.close()
w("file1", base + coll_1 + coll_1_1 + coll_1_1_1)
w("file2", base + coll_1 + coll_1_1 + coll_1_1_2)
w("file3", base + coll_1 + coll_1_2 + coll_1_1_1)
w("file4", base + coll_1 + coll_1_2 + coll_1_1_2)
w("file5", base + coll_2 + coll_1_1 + coll_1_1_1)
这里就不放出两两文件的比较结果了
这样就可以了,注意一下要用url编码
import binascii
file1 = open('file1', 'rb').read()
file2 = open('file2', 'rb').read()
file3 = open('file3', 'rb').read()
def urlencode(bstr):
encoded = ''
for i in bstr:
encoded = encoded + '%' + binascii.b2a_hex(i)
return encoded
print urlencode(file1)
print urlencode(file2)
print urlencode(file3)
然后GET传进去就可以了
发表评论
沙发空缺中,还不快抢~