前言
最近在做ctfshow的时候碰到intval()函数,虽然题目比较简单,却发现有很多的绕过手段,所以写下这篇博客进行总结
intval()函数
函数用于获取变量的整数值。intval函数有个特性:“直到遇上数字或正负符号才开始做转换,在遇到非数字或字符串结束时(\0)结束转换
- 语法
int intval ( mixed $var [, int $base = 10 ] )
通过使用指定的进制 base 转换(默认是十进制),返回变量 var 的 integer 数值。 intval() 不能用于 object(即是数组),否则会产生 E_NOTICE 错误并返回 1。
参数 | 描述 |
---|---|
var | 要转换成 integer 的数量值。 |
*base * | 转化所使用的进制。 |
Note:
如果
base
是 0,通过检测var
的格式来决定使用的进制:
- 如果字符串包括了 “0x” (或 “0X”) 的前缀,使用 16 进制 (hex);否则,
- 如果字符串以 “0” 开始,使用 8 进制(octal);否则,
- 将使用 10 进制 (decimal)。
函数的作用非常简单,就是获取变量的整数值
实例:
echo intval(42); // 42
echo intval(4.2); // 4
echo intval('42'); // 42
echo intval('+42'); // 42
echo intval('1e3'); //1000
那我们来看看具体题目中的如何绕过
ctf.show 萌新 web1
源代码
(flag in id = 1000)
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 ";
echo "执行的sql为:$sql<br>";
# 执行sql 语句
$result = $conn->query($sql);
# 判断有没有查询结果
if ($result->num_rows > 0) {
# 如果有结果,获取结果对象的值$row
while($row = $result->fetch_assoc()) {
echo "id: " . $row["id"]. " - title: " . $row["title"]. " <br><hr>" . $row["content"]. "<br>";
}
}
# 关闭数据库连接
$conn->close();
}
分析一下:
我们先上传参数id,如果小于999,进行sql语句拼接查询
那么我们上传的参数id值要小于999,可是题目提示flag在id=1000,完全是矛盾的
方法一
但是我们可以利用intval函数的特性,遇到非数字的直接停止转换,也就是
?id='1000'
这样肯定就小于999,并且又可以查到id=1000
方法二
遇到非数字的直接停止转换,那么我们再结合sql查询语句中数值型查询会自动进行运算操作
构造payload为?id=999+1
不过由于get传参,url编码一下
?id=999%2B1
执行结果同上
方法三
思路同上
?id=125*8
方法三
利用取反绕过,因为~~1000=1000
?id=~~1000
执行结果同上
方法四
我们再看intval()函数的另一个参数$base
,由于默认是$base=10
,那么我们传入1000的十六进制即可绕过,因为十六进制为0x开头,intval()函数遇到非数字无法将其转换,即为0小于999
?id=0x3E8
方法五
按位左移
payload
?id=125<<3
按位左移操作将二进制数向左移动指定的位数,并在右侧用零填充。在这里,125 的二进制表示是 1111101,将其左移3位后,得到 1111101000。将该二进制数转换为十进制,结果为1000。