MD5弱类型比较 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <?php highlight_file (__FILE__ );error_reporting (0 );$a = $_GET ['a' ];$b = $_GET ['b' ];if (isset ($_GET ['a' ]) and isset ($_GET ['b' ])) { if ($_GET ['a' ] != $_GET ['b' ]) { if ((md5 ($_GET ['a' ]) == md5 ($_GET ['b' ]))) echo "ok" ; else echo "nonono" ; } }?>
方法一:数组绕过
由于md5不能加密数组,在加密数组的时候会返回NULL,所以我们可以传入两个数组来绕过
方法二:科学计数法绕过
可以传入两个md5加密后是0e开头的字符串,需要注意的地方是,这个以0e开头的字符串只能是纯数字,这样php在进行科学计算法的时候才会将它转化为0
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 s878926199a 0e545993274517709034328855841020 s155964671a 0e342768416822451524974117254469 s214587387a 0e848240448830537924465865611904 QLTHNDT 0e405967825401955372549139051580 QNKCDZO 0e830400451993494058024219903391 EEIZDOI 0e782601363539291779881938479162 240610708 0e462097431906509019562988736854
MD5强类型比较 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <?php highlight_file (__FILE__ );error_reporting (0 );$a = $_GET ['a' ];$b = $_GET ['b' ];if (isset ($_GET ['a' ]) and isset ($_GET ['b' ])) { if ($_GET ['a' ] != $_GET ['b' ]) { if ((md5 ($_GET ['a' ]) === md5 ($_GET ['b' ]))) echo "ok" ; else echo "nonono" ; } }?>
在===
的情况下如果没有加类似is_numeric
的函数进行过滤还是可以使用数组绕过,但是不能使用科学计数法绕过了
方法三:MD5强碰撞
可以使用fastcoll
来碰撞出一组内容不同但md5值相同的值
1 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 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
双MD5 MD5和双MD5以后的值都是0e开头的
1 2 3 CbDLytmyGm2xQyaLNhWn 770hQgrBOjrcqftrlaZk 7r4lGXCH2Ksu2JNT3BYM
$md5==md5($md5) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 $md5 md5($md5) 0e00275209979 0e551387587965716321018342879905 0e00506035745 0e224441551631909369101555335043 0e00540451811 0e057099852684304412663796608095 0e00678205148 0e934049274119262631743072394111 0e00741250258 0e899567782965109269932883593603 0e00928251504 0e148856674729228041723861799600 0e01350016114 0e769018222125751782256460324867 0e01352028862 0e388419153010508575572061606161 0e01392313004 0e793314107039222217518920037885 0e01875552079 0e780449305367629893512581736357 0e01975903983 0e317084484960342086618161584202 0e02042356163 0e335912055437180460060141819624 0e02218562930 0e151492820470888772364059321579 0e02451355147 0e866503534356013079241759641492 0e02739970294 0e894318228115677783240047043017 0e02760920150 0e413159393756646578537635311046 0e02784726287 0e433955189140949269100965859496 0e03298616350 0e851613188370453906408258609284 0e03393034171 0e077847024281996293485700020358
爆破脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import hashlib payload = "0123456789" def calcMd5 (s ): MD5 = hashlib.md5(s).hexdigest() if MD5[0 :2 ] == "0e" and MD5[2 :32 ].isdigit(): print s,MD5def getStr (payload,s,slen ): if len (s) == slen: calcMd5(s) return s for j in xrange(len (payload)): sl= s+payload[j] getStr(payload,sl,slen)if __name__ == '__main__' : getStr(payload,'0e' ,13 )
截断比较(暴力破解) 1 2 3 4 5 6 7 8 <?php highlight_file (__FILE__ );if (substr (md5 ($_POST ['auth' ]),0 ,6 ) == "666666" ) { echo "1" ; } else { echo "2" ; }?>
代码中需要md5后前6位为666666
可以通过脚本进行爆破 脚本如下
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 import multiprocessingimport hashlibimport randomimport stringimport sys CHARS = string.letters + string.digitsdef 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) if md5.hexdigest()[start: start+str_len] == substr: 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_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()
运行脚本 第一个参数是需要的字符串,第二个参数是从哪一位开始 验证
补充一个升级版脚本,支持尾部添加字符串 例子: 假设字符串是随机的(指12ba
和91e0c
)
1 2 3 4 5 6 7 <?php if (substr (md5 ($_POST ['auth' ]."12ba" ),0 ,5 ) == "91e0c" ) { echo "1" ; } else { echo "2" ; }?>
1 2 >python2 md5.py "91e0c" 0 12 ba1 KVErD6VijQCd9BrkPEl // 跑出的值,已经去除结尾
脚本如下
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 import multiprocessingimport hashlibimport randomimport stringimport sys CHARS = string.letters + string.digitsdef cmp_md5 (substr, stop_event, str_len,off, start=0 , size=20 ): global CHARS while not stop_event.is_set(): rnds = '' .join(random.choice(CHARS) for _ in range (size)) rnds1 =rnds+ off md5 = hashlib.md5(rnds1) if md5.hexdigest()[start: start+str_len] == substr: 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 off=sys.argv[3 ] str_len = len (substr) cpus = multiprocessing.cpu_count() stop_event = multiprocessing.Event() processes = [multiprocessing.Process(target=cmp_md5, args=(substr, stop_event, str_len,off, start_pos)) for i in range (cpus)] for p in processes: p.start() for p in processes: p.join()
不同文件相同md5 linux使用md5collgen碰撞生成两个md5值相同但内容不同的文件
1 md5collgen -o 1 .bin 2 .bin
windows可以下载fastcoll,碰撞生成两个md5值相同但内容不同的文件
1 2 fastcoll.exe -p 123 .txt -o 1 .txt 2 .txt fastcoll.exe a .jpg -o 1 .jpg 2 .jpg
php中md5($str,true)注入 1 2 3 4 5 6 7 8 9 10 <?php $password = $_POST ['password' ]; $sql = "SELECT * FROM admin WHERE username = 'admin' and password = '" .md5 ($password ,true )."'" ; $result = mysqli_query ($link ,$sql ); if (mysqli_num_rows ($result )>0 ){ echo 'Success' ; }else { echo 'Failure' ; }?>
我们只需要找md5加密后字符串中是否存在'or'
字符串
比如经典的ffifdyop
,经过md5加密后276f722736c95d99e921722cf9ed621c
,转字符串后就包含了'or'
其他的例子和exp
1 2 3 4 5 ffifdyop 4SV7p bJm4aG bNas5p ckHAEb
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 <?php $payload = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" ;function calc_md5_true ($s ) { $md5_true = md5 ($s ,true ); if (strpos ($md5_true ,"'or'" ) !== false ){ echo $s .PHP_EOL; } }function getstr ($payload , $s , $slen ) { if (strlen ($s ) == $slen ) { calc_md5_true ($s ); return $s ; } for ($i = 0 ; $i < strlen ($payload ); $i ++) { $sl = $s . $payload [$i ]; getstr ($payload , $sl , $slen ); } }for ($i = 3 ; $i < 30 ; $i ++) { getstr ($payload , '' , $i ); }
HASH长度扩展攻击 在$hash = md5($salt.$data)
中已知$hash
和$data
以及$salt
的长度时 可以找到另一个$_hash
和$_data
使得$_hash = md5($salt.$_data)
成立
已知salt长度 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <?php highlight_file (__FILE__ );include "./secret_key.php" ;include "./salt.php" ; @$username = urldecode ($_POST ["username" ]); @$password = urldecode ($_POST ["password" ]);if (!empty ($_COOKIE ["digest" ])) { if ($username === "admin" && $password != "root" ) { if ($_COOKIE ["digest" ] === md5 ($salt .$username .$password )) { die ("The secret_key is " . $secret_key ); } else { die ("Your cookies don't match up! STOP HACKING THIS SITE." ); } } else { die ("no no no" ); } }
使用hashpump
进行计算
第一行是得到的hash值,即hash(salt+’adminroot’) 第二行是已知数据,即’adminroot’ 第三行是salt长度 第四行是要添加的数据(这个随意,至少1位以上)
\x
替换为%
hashpump的作者删库了,可以使用hash-ext-attack 或者hexpand代替
未知salt长度 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 攻击代码import hashpumpyimport urllibimport requestsfor i in range (1 ,30 ): m=hashpumpy.hashpump('3a4727d57463f122833d9e732f94e4e0' ,';\"tseug\":5:s' ,';\"nimda\":5:s' ,i) print i url='http://120.26.131.152:32778/' digest=m[0 ] message=urllib.quote(urllib.unquote(m[1 ])[::-1 ]) cookie='role=' +message+'; hsh=' +digest headers={ 'cookie' : cookie, 'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:55.0) Gecko/20100101 Firefox/55.0' , 'Accept' : 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' , 'Accept-Language' : ':zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3' , 'Accept-Encoding' : 'gzip, deflate' } print headers re=requests.get(url=url,headers=headers) print re.text if "Welcome" in re.text: print re; break
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 使用说明>>> import hashpumpy>>> help (hashpumpy.hashpump) Help on built-in function hashpump in module hashpumpy: hashpump(...) hashpump(hexdigest, original_data, data_to_add, key_length) -> (digest, message) Arguments: hexdigest(str ): Hex-encoded result of hashing key + original_data. original_data(str ): Known data used to get the hash result hexdigest. data_to_add(str ): Data to append key_length(int ): Length of unknown data prepended to the hash Returns: A tuple containing the new hex digest and the new message.>>> hashpumpy.hashpump('ffffffff' , 'original_data' , 'data_to_add' , len ('KEYKEYKEY' )) ('e3c4a05f' , 'original_datadata_to_add' )