简介
PHP是一种弱类型语言,这意味着变量的类型是根据上下文自动推断的,不需要强调声明(如c语言),带来方便的同时,也带来了许多安全隐患
PHP的比较也分为弱类型(==
)比较和强类型(===
)比较,还有(!=
)和(!==
)
md5比较绕过
在ctf赛题中,经常会出现类似于这样的一段代码,要求我们传入两个参数的值不同,而md5()
后的值相同
1 | $a=$_GET['a']; |
0e等于0绕过
一个字符串经过md5处理后如果是以0e
开头的,那么在php中就会被认为是科学计数法表示的数字(在科学计数法中,e
或E
用于表示指数。例如,数字300可以表示为3e2
或3E2
,意思是3 × 10^2
同样,数字0.003可以表示为 3e-3
或 3E-3
,意思是 3 × 10^-3
),也就是说0e
开头的表示的数字为0 × 10^n
都为0,这样一来,就可以成功绕过比较
下面是常见的md5后为0e
开头的字符串QNKCDZO
=>md5 0e830400451993494058024219903391
s878926199a
=>md5 0e545993274517709034328855841020
0e215962017
=>md5 0e291242476940776845150308577824
需要注意的是,这种绕过手法只适用于弱类型比较,强类型比较是不能使用这种方式的
还有一种题目,是上面题目的变种,希望传入参数的值与其本身md5()
处理过的值相同
1 | $a=$_GET['a']; |
这里只要一个字符是以0e
开头,md5
后还是0e
开头即可0e215962017
=>md5 0e291242476940776845150308577824
数组绕过
md5()
函数期望的得到的是一个字符串,但是如果传入一个数组的话,函数会报出一个警告,并返回NULL
值
当我们传入两个不同的数组,参数值必然不相等,而经过md5处理后,其值为NULL
, **payload**
?a[]=1&b[]=2`
原生类绕过
如果在类中进行比较一般是无法通过数组进行绕过的,这时候可以配合反序列化中的原生类技巧绕过,原生类绕过
哈希冲突绕过
MD5 是一种哈希算法,它将任意长度的输入数据映射到固定长度(128 位)的输出。由于 MD5 算法的输出长度是固定的,而输入数据的长度是任意的,所以理论上必然存在两个不同的输入数据,它们的 MD5 哈希值相同。
但是一般这些字符中都有一些不可见字符,所以这里采用url编码$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
这两个字符串即是哈希冲突的两个字符串
字符串与数字之间的弱类型
字符强转为数字
php在做匹配和比较时候,会根据匹配的类型做类型转换,例如比较数字和字符串是否相等,就会进行转换,转换规则是前面的数字不变后面字母被当成字符型舍去
简单来说,在php中123
==123a
6asdijbsujy
==6
后面的字符会被舍去,只比较最前面的数字
字符串被解析成十六进制
本来应该输入的是字符串,但是以0x
开头的字符串在进行一些比较或运算时,就被php当做16进制数进行解析了
1 |
|
ps:在php中使用dechex()
将十进制数转换为十六进制数,使用hexdec()
将十六进制数转换为十进制数
对字符串进行十六进制编码解码可以用下面的脚本,hex2bin
将十六进制数转化为二进制字符串
1 |
|