在上一篇2.0.9的版本分析中(https://xz.aliyun.com/t/7918),有师傅提到文中的漏洞在nginx下利用不了,为了解决这个问题同时挖掘新版本可用的利用方法,对目前的3.0.1版本进行了进一步分析
下载源码: https://gitee.com/hnaoyun/PbootCMS
版本V3.0.1 ,更新时间为20200709
安装教程如下
安装后去 https://www.pbootcms.com/freesn/获取授权码
依然是先查看apps\home\controller\ParserController.php中的parserIfLabel方法的两个if标签的过滤项
if (preg_match_all('/([\w]+)([\/\*\<\>\%\w\s\\\\]+)?\(/i', $matches[1][$i], $matches2)) {
foreach ($matches2[1] as $value) {
if (function_exists($value) && ! in_array($value, $white_fun)) {
$danger = true;
break;
}
}
}
if (preg_match('/(\$_GET\[)|(\$_POST\[)|(\$_REQUEST\[)|(\$_COOKIE\[)|(\$_SESSION\[)|(file_put_contents)|(file_get_contents)|(fwrite)|(phpinfo)|(base64)|(`)|(shell_exec)|(eval)|(assert)|(system)|(exec)|(passthru)|(pcntl_exec)|(popen)|(proc_open)|(print_r)|(print)|(urldecode)|(chr)|(include)|(request)|(__FILE__)|(__DIR__)|(copy)|(call_user_)|(preg_replace)|(array_map)|(array_reverse)|(getallheaders)|(get_headers)|(decode_string)|(htmlspecialchars)/i', $matches[1][$i]))
关于第一处的判断,我们依然可以使用在函数名和括号之间插入控制字符的方法来绕过该处校验,对于第二处,可以看到在黑名单中相较于上个分析版本(2.0.9)添加了getallheaders的黑名单判断,于是该处我们需要寻找新的方法来实现代码执行的目的,这让我想到了array_filter函数
通过该函数我们可以实现执行php代码,例如array_filter(['whoami'],'system');
那么接下来我们需要思考如何绕过黑名单中对system的检测,在这里我们依然可以将system放到header头中,这里可以使用session_id(session_start())的方法来取到session的值,我们可以将session的值置为system,就可以成功的调用system函数来执行命令了,通过上面的思路写出利用payload使用的时候却发生了如下问题
该处的冒号被替换成了@
符号,通过查看github更新记录可以发现如下代码段
该处使用了正则来替换我们输入的if标签,为了绕过该处正则的替换我们可以使用反斜杠来进行绕过,例如{pboot\:if}{/pboot\:if},该处的反斜杠会被写入数据库,而在程序调用该段数据并渲染到前台的模板时会调用到stripcslashes函数,进而删除反斜杠,代码位于core\function\handle.php中,如图
通过上面的分析,我们易得如下payload
来到后台站点信息处
插入如下代码并保存
而后来到前台首页,访问前台首页抓取数据包,将cookie中session的配置项改为system,如图
可以看到成功执行了system("whoami");