ctf show web入门115 这是一道非常经典的 PHP 弱类型与特性绕过的 CTF 题目。核心目标是通过 ?numxxx 传入一个参数使得它能通过那一长串复杂的 if 条件判断最终走到 echo $flag;。我们把核心的判断条件列出来需要同时满足以下 4个外部条件 和 1个内部条件if(is_numeric($num)// 1. 必须是一个数字或数字字符串and$num!36// 2. 强类型比较绝对不能等于字符串 36andtrim($num)!36// 3. 去除首尾空格后绝对不能等于字符串 36andfilter($num)36// 4. 经过 filter() 函数过滤、替换后的结果弱类型等于 36){if($num36){// 5. 内部条件$num 本身弱类型等于 36echo$flag;}}关键函数 filter($num) 分析这个函数会把 $num 中的以下字符全部替换为 “1”0x (十六进制)0. (浮点数小数点)e 或 E (科学计数法)(正号)核心突破口PHP 的弱类型与空白字符我们要让一个字符串既满足 is_numeric又在弱类型比较下等于 36同时还不能直接是 ‘36’。绕过思路一利用空白字符PHP 的 is_numeric() 和弱类型比较 在处理数字时会忽略字符串开头的某些空白字符例如空格 %20、制表符 %09、换行符 %0a、回车 %0d、水平制表符 %0b、换页符 %0c 等。但是题目中有一个条件叫 trim($num) ! ‘36’。trim() 会去除空格、\t、\n、\r、\0、\x0B。注意 trim() 不会去除换页符 \fURL编码为 %0c。如果我们传入 %0c36is_numeric(“%0c36”) -True (PHP 认为它是数字 36)“%0c36” ! ‘36’ - True (强类型不相等)trim(“%0c36”) - 结果依然是 “%0c36”所以 ! ‘36’ - Truefilter(“%0c36”) - 里面没有要替换的字符结果是 “%0c36”。在 filter($num) ‘36’ 时由于是弱类型比较%0c36 会被转换为数字 36 - True内部条件 “%0c36” ‘36’ - True所以我们构造payload为?num%0c36为什么空格 %20、制表符 %09、换行符 %0a、回车 %0d、水平制表符 %0b不能绕过限制字符编码 (URL),对应的空白字符类型,trim() 是否会切除%20,普通空格 (Space),会直接切除%09,制表符 (Tab),会直接切除%0a,换行符 (Line feed),会直接切除%0d,回车符 (Carriage return),会直接切除%00,空字节 (NUL-byte),会直接切除%0b,垂直制表符 (Vertical tab),会直接切除%0c,换页符 (Form feed),不会切除因为在 PHP 的底层逻辑中当它遇到像 %20空格、%09制表符、%0a换行这类标准空白字符开头数字的字符串时is_numeric() 和弱类型比较 会自动忽略开头的空白直接把后面的 36 提取出来进行计算。