弱类型比较
php中一些相等的值:
>> ''== 0 == false
>> '123' == 123
>> 'abc' == 0
>> 123a == 123
>> '0x01' == 1
>> '0e12345' == '0e98765'
>> [false] == [0] == [NULL] == [' ']
>> NULL == false == 0
>> true == 1
在php语言中,比较两个值是否相等可以用 '==' 和 '===' 两种符号。
前者往往会在比较的时候自动进行类型转换而不改变原来的值。所以漏洞
出现的位置往往是“==”。
我们来看下面一道题:
if($_GET['a']!=$_GET['b'] && md5($_GET['a'])==md5($_GET['b'])){
ehco flag;
}
如何才能满足这样的if判断条件呢?需要使两个变量不相等而md5值相等。这样的思路可以通过MD5碰撞来解决。让我们思路回到php语言,==存在弱类型比较,而md5函数返回值是一个32位的字符串,如果字符串以"0e"开头的话,类型转换机制会将它识别为一个科学计数法表示的数字“0”。从而满足条件。下面的字符串为md5加密后是0e开头:
240610708 0e462097431906509019562988736854 QNKCDZO 0e830400451993494058024219903391 s878926199a 0e545993274517709034328855841020 s155964671a 0e342768416822451524974117254469
从中选取两个提交即可绕过判断。
让我们再来看一下上面题目的2.0版本:
if($_GET['a']!=$_GET['b'] && md5($_GET['a'])===md5($_GET['b'])){
ehco flag;
}
当“==”变为“===”之后,刚才的两个字符串就不能成功了。但是,我们可以继续利用PHP语言函数错误处理上的特性,在URL栏提交a[]=1&b[]=2成功绕过。因为当我们令MD5函数的参数为一个数组时,函数会报错并返回NULL值。虽然函数的参数是两个不同的数组,但是函数的返回值是相同的NULL,在这里就是利用这一点巧妙的绕过了判断。
同样在程序返回值中容易判断错误的函数还有很多,如strpos,见PHP手册:
(PHP4,PHP5,PHP7)
strpos(string,find,start) -- 查找字符串首次出现的位置
if(strpos($str1,$str2) == false){ // 当str1 中不包含 str2 的时候
敏感操作;
}
这也是一种经常能见到的写法,当str1 在 str2 开头时,函数的返回值是0,而0 == false 是成立的,这就会造成开发者逻辑之外的结果。
例题:
[NSSCTF 2022 Spring Recruit]babyphp
要想得到flag。
第一关,首先要满足:
isset($_POST['a'])&&!preg_match('/[0-9]/',$_POST['a'])&&intval($_POST['a'])
preg_match()漏洞:存在数组绕过。preg_match绕过总结 - MustaphaMond - 博客园
preg_match只能处理字符串,当传入的subject是数组时会返回false、
因此我们POST传入a[]=1
之后第二关,还要满足$_POST['b1']!=$_POST['b2']&&md5($_POST['b1'])===md5($_POST['b2'])
根据上文写的数组绕过方法,我们再POST传入b1[]=1&b2[]=2 实现绕过。
之后第三关,还要满足$_POST['c1']!=$_POST['c2']&&is_string($_POST['c1'])&&is_string($_POST['c2'])&&md5($_POST['c1'])==md5($_POST['c2'])
根据上文写的满足条件方法(0e开头弱类型比较),POST传入c1=
QNKCDZO&c2=s878926199a。
得到flag。