PHP常用过滤函数
一、== 与 ===
- 松散比较:使用两个等号 == 比较,只比较值,不比较类型。
- 严格比较:用三个等号 === 比较,除了比较值,也比较类型。
<?php if(42 == "42") { echo '1、值相等'; } echo PHP_EOL; // 换行符 if(42 === "42") { echo '2、类型相等'; } else { echo '3、类型不相等'; } ?>
以上实例输出结果为:
1、值相等 3、类型不相等
二、MD5函数缺陷绕过 ==弱对比 ===强类型对比
2.1 使用和进行变量比较:md5()==
md5 0e绕过: 0e开头的字符串在参与比较时,会被当做科学计数法,结果转换为0
比如将两个md5值进行弱类型比较:
md5('QNKCDZO') == md5(240610708)
MD5加密后会变成这个样子:
0e830400451993494058024219903391 == 0e462097431906509019562988736854
由于0e开头的字符串会转换为0,所以真正比较的过程会变成下面这样
0 == 0
返回结果为true,也就是说0e开头的md5值进行弱类型比较时,结果相等
if($_GET['name'] != $_GET['password']){ if(MD5($_GET['name']) == MD5($_GET['password'])){ echo $flag; } echo '?'; } ?name=QNKCDZO&password=240610708
2.2 当使用md5()和进行变量对比的时候===
数组绕过: md5不能加密数组,传入数组会报错,但会继续执行并且返回结果为null
比如将两个md5值进行强类型比较:
md5(name[]=1) === md5(passwd[]=2)
由于md5函数无法处理数组,会返回null,所以md5加密后的结果是下面这样
null === null
结果返回true,也就是说数组的md5值进行比较时,结果相等
if($_GET['name'] != $_GET['password']){ if(MD5($_GET['name']) === MD5($_GET['password'])){ echo $flag; } echo '?'; } ?name[]=1&password[]=23
需要注意的是0e绕过只能绕过弱类型比较(==),而数组绕过不只可以绕过弱类型比较,还可以绕过强类型比较(===)
三、intval缺陷绕过
int intval( $var, $base )
函数作用:intval() 函数用于获取变量的整数值。 intval() 函数通过使用指定的进制 base 转换(默认是十进制),返回变量 var 的 integer 数值。
- 如果 $var 以 0 开头,就使用 8进制
- 如果 $var 以0x开头,就使用 16进制
- 否则,就使用 10进制
intval()函数漏洞的绕过思路:
1)当某个数字被过滤时,可以使用它的 8进制/16进制来绕过;比如过滤10,就用012(八进制)或0xA(十六进制)。
if(10 != $_GET['i']){ if(10 == intval($_GET['i'],0)){ echo '漏洞利用成功'; } }else{ echo 'NONONO'; }
2)对于弱比较(a==b),可以给a、b两个参数传入空数组,使弱比较为true。
if($_GET['a']!=$_GET['b']) { if (intval($_GET['a']) == intval($_GET['b'])) { echo '漏洞利用成功'; } }else echo 'NONONO';
3)当某个数字被过滤时,可以给它增加小数位来绕过;比如过滤3,就用3.1。
4)当某个数字被过滤时,可以给它拼接字符串来绕过;比如过滤3,就用3ab。(GET请求的参数会自动拼接单引号)
intval()函数转换字符串时,会判断字符串是否以数字开头; //当字符串以数字开头,就会返回1个或多个连续的数字; //当字符串以字母开头,就会返回0;
5)当某个数字被过滤时,可以两次取反来绕过;比如过滤10,就用~~10。
6)当某个数字被过滤时,可以使用算数运算符绕过;比如过滤10,就用 5+5 或 2*5。
四、strpos()函数,我们可以利用换行进行绕过(%0a)
strpos(string,find,start)
函数作用:strpos() 函数查找字符串在另一字符串中第一次出现的位置。(区分大小写)
函数语法: string必需。规定要搜索的字符串。 find 必需。规定要查找的字符串。 start可选。规定在何处开始搜索。
五、in_array第三个参数安全
bool in_array ( mixed $needle , array $haystack [, bool $strict = FALSE ] )
in_array --- 检查数组中是否存在某个值
说明: 在 haystack 中搜索 needle ,如果没有设置 strict 则使用宽松的比较(相当于 == 判断)
<?php $id =3 and 1=1; // 定义变量 $id 为 3 并且判断 1=1(永远为 true) $whitelist = range(1, 5); // 声明一个从 1 到 5 的白名单数组 if (!in_array($id, $whitelist)) { // 如果 $id 不在白名单中 echo "你想搞事"; // 输出 "你想搞事" } else { echo "你通过了"; // 输出 "你通过了" } ?> 这里in_array()也是没有设置第三个参数,会进行弱类型比较,会将3 and 1=1转化为3从而绕过了白名单,输出你通过了。 <?php $id =3 and 1=1; // 定义变量 $id 为 3 并且判断 1=1(永远为 true) $whitelist = range(1, 5); // 声明一个从 1 到 5 的白名单数组 if (!in_array($id, $whitelist,true)) { // 如果 $id 不在白名单中 echo "你想搞事"; // 输出 "你想搞事" } else { echo "你通过了"; // 输出 "你通过了" } ?> 当我设置第三个参数为true时,此时会进行强类型检查。所以我们将上文第三行代码修改为:if (!in_array($id, $whitelist,true)),再执行就会输出:“你想搞事”。//由于$id被赋值为true,而不是预期的3,所以$id的类型不是整数,而是布尔值。由于true不在范围为$whitelist的整数数组中,因此in_array()函数会返回false,导致代码输出"你想搞事"而不是"你通过了"
六、preg_match
preg_match 函数用于执行一个正则表达式匹配
preg_match 只能处理字符串,如果不按规定传一个字符串,通常传一个数组进入,就会使 preg_match 失效,从而绕过该函数的检测。
<?php if(isset($_GET['num'])){ //如果存在名为num的GET参数,则执行后续的代码。 $num = $_GET['num']; //将num参数的值赋给变量$num。 if(preg_match("/[0-9]/", $num)){ //然后通过正则表达式检查num是否包含数字,如果包含数字就输出"no no no!" die("no no no!"); } if(intval($num)){ ////如果$num能转换为整数,则输出"你通过了"。 echo '你通过了'; } } ?> ?num[]=1 //你通过了
七、str_replace 无法迭代过滤
str_replace() 函数用于替换字符串中指定字符(区分大小写)
//简单的sql过滤 $sql=$_GET['s']; //接收名为's'的GET参数,并将其赋值给变量$sql $sql=str_replace('select','',$sql); //然后,使用str_replace函数将$sql中的'select'字符串替换为空字符串,然后将结果输出。 echo $sql; //这样的话,如果's'参数中包含'select'字符串,它会被删除,然后输出结果。 //?s=sselectelect
Comments NOTHING