前言
文章同步我的个人博客http://www.quan9i.top/,欢迎大家访问。
php特性的intval是一个比较常见的漏洞,今天就来比较全面的学习这个函数,将其简单的利用方式总结一下
函数学习
学习函数最好的方式就是去学习官方的,这样学习得到的收获更多一些,这里我们先来看一下这个函数定义
intval — 获取变量的整数值
而它的具体格式和解释如下
int intval( var,base)//var指要转换成 integer 的数量值,base指转化所使用的进制 Note: 如果 base 是 0,通过检测 var 的格式来决定使用的进制: ◦ 如果字符串包括了 "0x" (或 "0X") 的前缀,使用 16 进制 (hex);否则, ◦ 如果字符串以 "0" 开始,使用 8 进制(octal);否则, ◦ 将使用 10 进制 (decimal)。
这里这个Note对我们来说就尤为重要了,没有声明base参数时,字符串首字母是0则视为8进制,是0X则视为16进制,具体可以看官方给出的例子
echo intval(042); // 34echo intval(0x1A); // 2?>
此时就可以看出它的一个利用方式了,当过滤某个数字时,我们可以利用它的进制转换来绕过。
此时再往下看
返回值 成功时返回 var 的 integer 值,失败时返回 0。空的 array 返回 0,非空的 array 返回 1。
这时候就可以看出另一个利用方式了,如果是一个弱比较a==b
我们输入a[]=1
和
b[]=2
,此时这两个是不同的,但还都会返回1,此时也就实现了一种绕过,这是第二种绕过思路。
此时官方还给出了其他示例,我们再看
echo intval(42); // 42echo intval(4.2); // 4
我们可以发现小数点后的数字会直接舍去,所以这可以作为第三种,当过滤4的时候,我们可以输入4.2来绕过
然后呢,我们还发现例子里有1e
这种格式的,
echo intval(1e10); // 1410065408echo intval('1e10'); // 1
这个呢我们发现单引号传值的时候,它只识别字母前面的一部分,当我们进行get传参时,我们其实就是默认加单引号的,所以这又是一种绕过方式。
还有说一下这里不是必须是e,这里只要是字母就可以
实战
0X01
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; }}?>
看见这题我的思路就是用数组绕过,可能是因为之前md5()的时候强比较看习惯了,这里构造payload如下即可
num[]=1
0X02
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的第二个参数为0时的意思是什么
int intval( var,base)Note: 如果 base 是 0,通过检测 var 的格式来决定使用的进制: ◦ 如果字符串包括了 "0x" (或 "0X") 的前缀,使用 16 进制 (hex);否则, ◦ 如果字符串以 "0" 开始,使用 8 进制(octal);否则, ◦ 将使用 10 进制 (decimal)。
此时的话我们再看一下在这个函数的运算
看到这里的话就可以看出payload就有多种构造方法了
num=4476e123//这里就跟上面那个单引号的1e10情况一样,此时只看字母前面的num=4476.1//计算int值时,后面有小数点会直接舍去num=0x117c//0x表明是十六进制数,117c是4476的十六进制数num=010574//0表明是八进制数,10574是4476的八进制数
测试如下
执行结果如下
0X03
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); }}
这里的话就是从强比较换成了弱比较,用之前的解题payload即可
num=4476.1
0X04
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; }}?>
这道题的话看着几乎是防死了,多过滤了.
,这就意味着小数点绕过行不通,此时我们看到这个i修饰符,想到那个m修饰符,此时就想起来有个换行符%0a,它对实际输出没影响,它还可以绕过上面的那些函数,因此我们这里构造如下语句,就实现了绕过,由于小数点不能用,这里就用八进制
num=%0a010574
来源地址:https://blog.csdn.net/Reme_mber/article/details/124781330