php函数绕过总结

前言

函数绕过的前提是对应的php版本

intval()

1
int intval ( mixed $var [, int $base = 10 ] )

函数作用:获取变量的整数值

0x:16 0:8 0b:2 默认10

科学计数法绕过

当函数中用字符串方式表示科学计数法时,函数的返回值是科学计数法前面的一个数,而对于科学计数法加数字则会返回科学计数法的数值

1
2
3
echo intval(1e10);              // 1410065408
echo intval('1e10'); // 1
echo intval('1e10'+1); // 1410065409

应用场景:

1
if (intval($_GET['lover']) < 2023 && intval($_GET['lover'] + 1) > 2024)

进制绕过

当某个数字被过滤时,可以使用它的 8进制/16进制来绕过。

当 base 为空时,默认值是 0,会根据 $var 的格式来调整转换的进制。

  • 如果 $var 以 0 开头,就使用 8进制

  • 如果 $var 以0x开头,就使用 16进制

  • 否则,就使用 10进制

转换字符串特性绕过

  • 如果以数字开头,就返回1个或多个连续的数字
  • 如果以字母开头,就返回0
1
2
3
4
5
6
7
if(intval($id) > 999){
# id 大于 999 直接退出并返回错误
die("id error");
}else{
# id 小于 999 拼接sql语句
$sql = "select * from article where id = $id order by id limit 1 ";
<!-- flag in id = 1000 -->

payload:?id=2 or id=1000

数组绕过

intval() 转换数组类型时,不关心数组中的内容,只判断数组中有没有元素,有为1无为0

三种数组写法:

1
2
3
4
5
$a[]=1;

$a=array(1,2);

$a=[1,2];

但在传参时一般使用第一种形式,经过测试发现,传参默认都是字符串类型,根据intval的字符串转换规则,如果字符串第一个字符不是数字就会直接返回0,所以后面两种形式都是返回0,只有第一种可以正确返回数字1

image-20231101235921465

取反~绕过

当某个数字被过滤时,可以两次取反来绕过

1
2
var_dump(intval(~10));  \\ -11
var_dump(intval(~~10)); \\ 10

算数运算符绕过

当某个数字被过滤时,可以使用算数运算符绕过

1
2
3
var_dump(intval(5*5));
var_dump(intval(5+5));
var_dump(intval(05+5));

输出:

1
2
3
int(25)
int(10)
int(10)

SQL注入intval()函数绕过黑名单方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#flag in id=1000
if(preg_match("/or|\-|\\|\*|\<|\>|\!|x|hex|\+/i",$id)){
die("id error");
}
if(intval($id) > 999){
die("id error");
}
else{
# id 小于 999 拼接sql语句
$sql = "select * from article where id = $id order by id limit 1 ";
}
根据黑名单的不同,访问?id=1000有以下几种方法:
?id='1000' //"1000"或(1000)皆可
?id=125<<3 //左移
?id=680|320 //按位或
?id=992^8 //按位异或
?id=~~1000 //两次取反
?id=0x3e8 //十六进制
?id=0b1111101000 //二进制

preg_replace()