又一根儿

intval函数

定义

intval — 获取变量的整数值

具体

1
int intval( $var, $base )//前者指要转换成整数的数量值,后者指转换的进制。

NOTE:base为0,则通过检测 var 的格式来决定使用的进制;如果字符串包括了 “0x” (或 “0X”) 的前缀,使用 16 进制 (hex);如果字符串以 “0” 开始,使用 **8 进制(octal)**;否则,将使用 10 进制 (decimal)。

可以利用的特性

进制自动转换

从NOTE可以看出,当过滤某个数字时,我们可以利用它的进制转换来绕过。

数组转换

对于该函数的返回值,有如下特性

1
成功时返回 var 的 integer 值,失败时返回 0。空的 array 返回 0,非空的 array  返回 1。

该特性就是PHP弱比较绕过时通过数组绕过所使用的。

小数转换

1
2
echo intval(42);           // 42
echo intval(4.2); // 4

可以发现小数点后的数字会直接舍去,因此,当过滤4的时候,我们可以输入4.2来绕过

字符串转换

1
2
echo intval(1e10);                    // 1410065408
echo intval('1e10'); // 1

单引号传值的时候,它只识别字母前面的一部分(只要是字母就行了),当进行get传参时,其实就是默认加单引号的,所以这又是一种绕过方式。

取反(~)

intval() 函数支持一些特殊符号的,比如~取反。

1
2
3
<?php 
var_dump(intval(~10));
var_dump(intval(~~10));

输出

1
2
int(-11)
int(10)

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

算数运算符

intval() 函数支持算数运算符,如果传入的 $var参数包含算数运算符,会先运算,再对运算结果进行转换。

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)

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

实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
include("flag.php");
highlight_file(__FILE__);

if(isset($_GET['num'])){
$num = $_GET['num'];
if(preg_match("/[0-9]/", $num)){
die("no no no!");
}
if(intval($num)){
echo $flag;
}
}
?>

数组绕过

1
2
3
4
5
6
7
8
9
10
11
12
13
14

include("flag.php");
highlight_file(__FILE__);
if(isset($_GET['num'])){
$num = $_GET['num'];
if($num==="4476"){
die("no no no!");
}
if(intval($num,0)===4476){
echo $flag;
}else{
echo intval($num,0);
}
}

要求不是4476,但经过intval函数运算过后仍是4476

intval($num,0)

0的含义就是通过检测 var 的格式来决定使用的进制,这是可以利用的地方

因此,payload可以使多个答案,如下

1
2
3
4
5
6
7
8
num=4476e123
//只看字母前面的
num=4476.1
//计算int值时,后面有小数点会直接舍去
num=0x117c
//0x表明是十六进制数,117c是4476的十六进制数
num=010574
//0表明是八进制数,105744476的八进制数

强比较和弱比较一样,都是数字类型。

这里插一下强比较和弱比较的概念,有点忘了

1
2
3
弱比较(==)会在比较时进行类型转换。例如,字符串"1"和整数1在使用“==”比较时,结果是true,因为PHP会把它们转换为相同类型后再比较。

强比较(===)不会进行类型转换,除了比较值还会比较类型。如果用“===”比较字符串"1"和整数1,结果是false,因为它们类型不同。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
include("flag.php");
highlight_file(__FILE__);
if(isset($_GET['num'])){
$num = $_GET['num'];
if($num==4476){
die("no no no!");
}
if(preg_match("/[a-z]|\./i", $num)){
die("no no no!!");
}
if(!strpos($num, "0")){
die("no no no!!!");
}
if(intval($num,0)===4476){
echo $flag;
}
}
?>

又是preg_match("/[a-z]|\./i", $num),又是!strpos($num, "0")

所以这里想到用换行符%0a它对实际输出没影响,它还可以绕过上面的那些函数,由于小数点不能用,这里就用八进制。payload如下

1
num=%0a010574

又一根儿
http://example.com/2024/12/01/又一根儿/
作者
John Doe
发布于
2024年12月1日
许可协议