
这是一道非常典型的 PHP Weak Typing弱类型和内置函数特性的 CTF 逆向题目。我们的目标是绕过前面的重重限制最终让代码执行到 echo $flag;。下面为你梳理详细的解题思路和绕过方法核心代码分析我们先来看必须要满足和绕过的 三个条件$num$_GET[num];// 条件 1强匹配强等于弱类型比较if($num4476){die(no no no!);}// 条件 2正则表达式过滤字母if(preg_match(/[a-z]/i,$num)){die(no no no!);}// 条件 3最终目标if(intval($num,0)4476){echo$flag;}解题思路与绕过技巧绕过条件 1num4476分析PHP在使用弱类型比较时如果一个字符串与数字进行比较它会尝试将字符串转换为数字。绕过方法我们不能直接传4476但是可以利用数字的形式变化。例如使用十六进制、八进制、科学计数法或者在数字后面加空格/特殊字符。比如字符串4476.0或4476在与数字4476弱类型比较时依然等于4476。所以我们需要找到一个值既能让intval(num 4476 分析PHP 在使用 弱类型比较时如果一个字符串与数字进行比较它会尝试将字符串转换为数字。 绕过方法我们不能直接传 4476但是可以利用数字的形式变化。例如使用十六进制、八进制、科学计数法或者在数字后面加空格/特殊字符。 比如字符串 4476.0 或 4476 在与数字 4476 弱类型比较时依然等于 4476。所以我们需要找到一个值既能让 intval(num4476分析PHP在使用弱类型比较时如果一个字符串与数字进行比较它会尝试将字符串转换为数字。绕过方法我们不能直接传4476但是可以利用数字的形式变化。例如使用十六进制、八进制、科学计数法或者在数字后面加空格/特殊字符。比如字符串4476.0或4476在与数字4476弱类型比较时依然等于4476。所以我们需要找到一个值既能让intval(num, 0) 4476 成立又不能让 $num 4476 成立。认识关键函数intval(num,0)这是本题的核心考点。intval(num, 0) 这是本题的核心考点。 intval(num,0)这是本题的核心考点。intval(var, $base) 的第二个参数 $base 代表进制。当 $base 设置为 0 时PHP 会根据字符串的前缀来自动检测并转换进制如果字符串以 0x 或 0X 开头会当作十六进制解析。如果字符串以 0 开头且后面不是x会当作八进制解析。如果以 1-9 开头会当作十进制解析。绕过条件 2preg_match(“/[a-z]/i”,num)分析这个正则带有/i修正案意味着它会严格过滤掉所有大小写英文字母。影响因为过滤了字母所以我们无法使用十六进制因为十六进制需要0xx会被正则拦截。出路既然十六进制不能用我们就只能把目光投向八进制因为八进制只包含数字0−7没有字母。构造Payload我们要将十进制的4476转换为八进制。计算八进制值447610105748利用intval的特性为了让intval(num) 分析这个正则带有 /i 修正案意味着它会严格过滤掉所有大小写英文字母。 影响因为过滤了字母所以我们无法使用十六进制因为十六进制需要 0xx 会被正则拦截。 出路既然十六进制不能用我们就只能把目光投向八进制因为八进制只包含数字 0-7没有字母。 构造 Payload 我们要将十进制的 4476 转换为八进制。 计算八进制值 4476_{10} 10574_{8} 利用 intval 的特性 为了让 intval(num)分析这个正则带有/i修正案意味着它会严格过滤掉所有大小写英文字母。影响因为过滤了字母所以我们无法使用十六进制因为十六进制需要0xx会被正则拦截。出路既然十六进制不能用我们就只能把目光投向八进制因为八进制只包含数字0−7没有字母。构造Payload我们要将十进制的4476转换为八进制。计算八进制值447610105748利用intval的特性为了让intval(num, 0) 把其当成八进制解析我们需要在前面加上前缀 0即构造字符串“010574”。验证这三个条件条件 1“010574” 4476 \rightarrow 在弱类型比较时字符串 “010574” 会被转换成十进制数字 10574。因为 10574 \neq 4476所以成功绕过不会 die。条件 2“010574” 中全部是数字没有包含任何字母成功绕过正则匹配。条件 3intval(“010574”, 0) \rightarrow 因为基数base为 0 且以 0 开头PHP 将其作为八进制解析转换回十进制就是 4476。4476 4476 成立成功触发 Flag还可以加上小数来payload为?num4476.9