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); echo intval(4.2);
|
可以发现小数点后的数字会直接舍去,因此,当过滤4的时候,我们可以输入4.2来绕过
字符串转换
1 2
| echo intval(1e10); echo intval('1e10');
|
单引号传值的时候,它只识别字母前面的一部分(只要是字母就行了),当进行get传参时,其实就是默认加单引号的,所以这又是一种绕过方式。
取反(~)
intval() 函数支持一些特殊符号的,比如~取反。
1 2 3
| <?php var_dump(intval(~10)); var_dump(intval(~~10));
|
输出
所有,当某个数字被过滤时,可以两次取反来绕过。
算数运算符
intval() 函数支持算数运算符,如果传入的 $var参数包含算数运算符,会先运算,再对运算结果进行转换。
1 2 3
| var_dump(intval(5*5)); var_dump(intval(5+5)); var_dump(intval(05+5));
|
输出
因此,当某个数字被过滤时,可以使用算数运算符绕过。
实例
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表明是八进制数,10574是4476的八进制数
|
强比较和弱比较一样,都是数字类型。
这里插一下强比较和弱比较的概念,有点忘了
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如下