CTF中的md5
- 第一种情况,md5弱类型比较
1 2 | if(md5($_GET['a'])==md5($_GET['b'])) var_dump($flag); |
因为是if的判断条件是两个数弱类型相等,就可以利用hash比较缺陷去绕过
比如
1 2 | var_dump("0e12345"=="0e66666");//true var_dump(md5('240610708')==md5('QNKCDZ0'));//true |
也就是只要两个数的md5加密后的值以0e开头就可以绕过,因为php在进行弱类型比较(即==)时,会现转换字符串的类型,在进行比较,而在比较是因为两个数都是以0e开头会被认为是科学计数法,0e后面加任何数在科学计数法中都是0,所以两数相等,在进行严格比较(===)时才会先判断字符串类型是否相等,在比较。
想这样特殊的md5值还有
1
2
3
4
5
6
7
8 240610708:0e462097431906509019562988736854
QLTHNDT:0e405967825401955372549139051580
QNKCDZO:0e830400451993494058024219903391
PJNPDWY:0e291529052894702774557631701704
NWWKITQ:0e763082070976038347657360817689
NOOPCJF:0e818888003657176127862245791911
MMHUWUV:0e701732711630150438129209816536
MAUXXQC:0e478478466848439040434801845361
除了这些还有很多参考:https://github.com/spaze/hashes/blob/master/md5.md
- 第二种情况,md5强类型比较
1 2 3 4 | if(md5((string)$_GET['a'])===md5((string)$_GET['b'])) {<!-- --> var_dump($flag); } |
此时两个md5后的值采用严格比较,没有规定字符串如果这个时候传入的是数组不是字符串,可以利用md5()函数的缺陷进行绕过
1 2 3 4 | var_dump(md5([1,2,3])==md5([4,5,6]));//true var_dump(md5($_GET['a'])==md5($_GET['b'])); ?a[]=1&b[]=1//true |
md5()函数的描述是string md5(string $str[,bool $raw_output=false])
md5中需要的是一个string参数,但是当你传入一个array(数组)是,md5()是不会报错的,只是无法求出array的md5的值,这样就会导致任意的2个array的md5的值都会相等
- 第三种情况,md5碰撞
1 2 3 4 | if($_GET['a']!==$_GET['b'] && md5($_GET['a'])===md5($_GET['b'])) {<!-- --> echo 'ok'; } |
真实md5碰撞,因为此时不能输入数组了,只能输入字符串
a=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&b=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碰撞1
md5碰撞2
- 第四种情况
1 | $query = "SELECT * FROM flag WHERE password = '" . md5($_GET["hash4"],true) . "'"; |
这需要一个极其特殊的md5的值 ffifdyop
这个字符串进行md5后恰好结果是’or’6?]??!r,??b,他的前四位为’or’正好满足sql注入查询的条件,因此可以完美绕过
- 其他特殊的hash值(md4、crc32…)
https://github.com/spaze/hashes
感谢各位大神的整理