代码是这样的(加了注释的)

1
<?php
2
$flag = "66666";
3
if(isset($_GET['time'])){ // 如果get请求中存在time参数
4
        if(!is_numeric($_GET['time'])){ // 如果非数字
5
                echo 'The time must be number.'; 
6
        }else if($_GET['time'] < 60 * 60 * 24 * 30 * 2){  // 如果time小于xx
7
                        echo 'This time is too short.'; 
8
        }else if($_GET['time'] > 60 * 60 * 24 * 30 * 3){ // 如果time大于xx
9
                        echo 'This time is too long.'; 
10
        }else{ // 否则
11
                sleep((int)$_GET['time']); // 睡眠time秒
12
                echo $flag; // 睡眠结束后输出flag
13
        } 
14
}

在注释中很详细的讲解了

如果想要输出$flag就必须绕过这3if条件判断才能到else 然后才会输出$flag,那么我们来看看如何才能不达到这几个if条件语句

第一个if条件

1
if(!is_numeric($_GET['time']))

如果$_GET['time']的值不是数字,则会触发这个if条件

第二个if条件

1
else if($_GET['time'] < 60 * 60 * 24 * 30 * 2)

如果$_GET['time']的值小于60 * 60 * 24 * 30 * 2,则触发这个if条件,那么我们来看看这个数值有多大

image_1cqiit27u1pdt1jok1cebpl02dac.png-16.4kB

1
5184000

然后再来看看第三个if条件

1
else if($_GET['time'] > 60 * 60 * 24 * 30 * 3

如果$_GET['time']的值大于60 * 60 * 24 * 30 * 3,则触发这个if条件,那么来看看这个有多大

image_1cqij4pgv8i019b51vpvmo0o1pp.png-2.6kB

1
7776000

那么要逃逸这2个if条件很简单,只要$_GET['time']大于5184000并且小于7776000就可以获取到flag,但是我们看一下else里面的代码

1
sleep((int)$_GET['time']); // 睡眠time秒
2
echo $flag; // 睡眠结束后输出flag

那么我们如果把time的值填的符合上面那么大的值,估计我孩子都生出来了。。。,那么该肿么办呢,之前看过一篇文章有讲过,测试代码如下

1
<?php
2
3
$num = $_GET['num']; // 接收get请求中的num参数
4
if ($num > 9999){ // 如果num大于9999
5
	echo '$temp > 9999'; // 输出 $temp > 9999
6
}
7
echo "<br>";
8
var_dump( (int)$num ); // 打印转换$num的值

那么我们来访问以下?num=0x2710

1.png-10.8kB

what?为啥会显示大于9999最后又输出结果是0呢?下面来看下讲解

这里的0x271010000转换为十六进制后的值

image_1cqijn7kc121u197k1611vif9te2m.png-2.9kB

然后我们再来看个小案例

1
var_dump( (int)('0only_free') );

1.png-9.7kB

可以看到0only_freeint转换后变成了0 可以理解为int就是取一个有数字、字母的字符串的前面数字。

那么我们可以利用这个办法去绕过上面的2if判断,直接访问一下

1
http://you_url.xxx/xxx.php?time=0x4f1a01

1.png-8.5kB

ok,成功绕过并且输出了flag