Challenge 2

前言

主要考察的是PHP类型,及类型转换的一些特性,还是很有意思的。

分析代码执行流程

<?php
show_source(__FILE__);
$flag = "xxxx";
if (isset($_GET['time'])) {
    if (!is_numeric($_GET['time'])) {
        echo 'The time must be number.';
    } else if ($_GET['time'] < 60 * 60 * 24 * 30 * 2) {
        echo 'This time is too short.';
    } else if ($_GET['time'] > 60 * 60 * 24 * 30 * 3) {
        echo 'This time is too long.';
    } else {
        sleep((int) $_GET['time']);
        echo $flag;
    }
    echo '<hr>';
}

首先我们定位到关键变量 $flag 的最终输出位置,然后紧跟变量进行逆向的分析,确认代码逻辑及关键 if 语句条件。

接收外部传递的 $_GET['time'] ,经过三次 if 判断才会到达输出 $flag 的代码段,但在输出 $flag 之前存在一个 sleep() 函数。

  • $_GET['time'] 必须是数字
  • $_GET['time'] 必须大于 5184000
  • $_GET['time'] 必须小于 7776000
  • $_GET['time'] 会被转换成 int 类型,并休眠响应秒后,才会打印 $flag

这里的关键点有两个:

  • is_numeric 函数用于检查参数是否是数字(为的类型有:浮点型、十进制、十六进制、科学计数)
  • (int) 强制转换成 int 类型。这个就比较特殊了,当然类型为字符串时,比如 89ee 最终会变成 89 ,后面的字符串部分则会被丢弃。

所以,这里我们直接提交一个十六进制数绕过 is_numeric 函数,又因为 php 接收 _GET、_POST 等参数默认都是字符串类型,从而又绕过了 (int) 强制类型转换。

最终提交:?time=0x518400 成功拿到 $flag