PHP缺陷函数

强等于与弱等于

在PHP中,=代表赋值,==代表弱等于,===代表强等于,强等于和弱等于区别就在于是否比较类型

===:比较的不仅仅是值相等,而且类型也必须相等,只有当值和类型都相等的时候,才会返回ture
例如 var_dump(1==="1");返回的是false

image-20240605114211356

==:弱比较只要求比较两个值在转化类型之后相等即可,如果两个值的类型不同,会尝试将其中一个值转化为另一个值的类型
例如 var_dump(1=="1");返回的是true

image-20240605114412890

综上,php比较运算符===在进行比较时,会先比较两种字符串的类型是否相等,再比较值是否相等,一般md5弱等于比较常考

具体例子可以参考这一篇:PHP强相等&弱相等(附带科学计数法)_php 科学计数法-CSDN博客

intval函数

intval()函数可以获取变量的整数值,常用于强制类型转换,常见语法int intval($var,$base),其中$var为需要转化的变量,$base为转换所需要的进制,当base为空时,默认值为0,会根据$var的格式来调整转化进制,如果$var以0开头,就使用8进制,如果$var以0x开头,就使用16进制,否则使用10进制

intval()遇上数组的时候,不关系数组的内容,只判断数组内有没有元素,如果是空数组就返回0,如果是非空数组就返回1,但是当传入的$var是数组中的某个值时,则当作变量来进行转换,而不是当作数组类型

$arr = array(8,6);
var_dump(intval($arr[0]));
返回的是 int(8)

当进行字符串转化时,会先判断字符串是否已数字开头,如果以数字开头,就会返回1个或多个连续的数字,如果以字母开头,就返回0

var_dump(intval('12abc'));     int(12)
var_dump(intval("12abc")); int(12)
var_dump(intval('abc123')); int(0)
var_dump(intval('1a2b3c')); int(1)
var_dump(intval('0101')); int(101)
var_dump(intval("0x2b")); int(0)

另外,intval()支持算术运算,即intval(5*5)会返回25

strpos函数

strpos函数用于查找一个字符串在另一个字符串中首次出现的位置(区分大小写),如果找到了匹配的字符串,strpos函数就会返回匹配的第一个字符的索引值,否则就返回false

$str1 = "Hello, world!";
$str2 = "world";

// 查找 $str2 在 $str1 中首次出现的位置
$pos = strpos($str1, $str2);

if ($pos !== false) {
echo "找到了 $str2,它在 $str1 中的位置是 $pos";
} else {
echo "$str2 不在 $str1 中";
}

输出结果

image-20240605132739685

当我们使用strpos函数的时候,如果被匹配字符串开头就是我们要匹配的目标字符串,那么strpos就会返回0,此时如果采用弱比较,那么0==false返回的是true,那么就会和没找到相关字符串情况相同,这个时候我们就可以成功绕过strpos函数

同时,如果加上换行符%0a时,strpos是检测不出来的,这也是这种函数的一种绕过思路

image-20240605134026638

in_array

在PHP中,可以使用in_array()函数直接确定某元素是否在数组中,如果数组中存在该元素,则会返回true,如果不存在,则返回false

语法in_array(search,array,type)

当type设置为strict时,就会判断类型,和强等于一致,但是如果不设置type,就不会判断类型,和弱等于一样,故其绕过方式可以参考强等于和弱等于

preg_match

preg_match是检查是否匹配的函数,经常用在正则表达式的匹配中,其语法为preg_match($pattern,$subject,$matches,$flags,$offset),前两个参数是必须的,后三个参数不填写的话会有自己的默认值

通常preg_match有以下几种方式绕过

数组绕过

由于preg_match只能处理字符串,如果不按规定传入一个字符串,通常传入一个数组进去,就会使preg_match失效,从而进行绕过

<?php
$a='flag.php'; //目标是输入flag.php
if(!preg_match("/flag/",$a)==false){ //如果匹配中出现了flag
die('这样子是不行的~'); //绕过失败,输出:这样子是不行的~
}
echo '成功啦~'; //绕过成功
?>

此时我们通常有三种绕过数组形式,如下所示

$a[] = 'flag.php';
$a=array('flag.php');
$a = ['flag.php'];

str_replace

str_replace函数的作用是替换字符串中的一些字符(区分大小写),其缺陷在于无法迭代过滤,只过滤一次,所以我们通常通过双写进行绕过

image-20240605174943563

接下来进行双写flag进行绕过,将$a改成flflagag.php

image-20240605175053228

成功绕过,同时,由于preg_replace对大小写不敏感,所以我们也可以大写绕过

image-20240605175158065

CMS实例

MetInfo 任意文件读取

考点:str_replace无法迭代过滤

f8ac8250bcfee65b8af089e9b59a37bc

通过实现../和./的过滤,防止用户实现路径穿越,由于$dir是可控的,我们可以通过绕过str_replace来实现任意文件读取,故对应的payload为../http\..\config\config_db.php,可以读到数据库配置文件

image-20240605180223578

piwigo SQL注入

考点:使用in_array函数但未使用第三个参数,导致过滤不严,造成代码的注入,进而引起sql注入

ff97380da602a8dd3bbf5d8c1e1cfc86

故payload为1,1 and if(ascii(substr((select database(),1,1))=112,1,sleep(3)));