PbootCms-2.0.7模板注入到RCE

前言

90论坛上看到一篇关于该CMS的贴子,文章中分析的是两处注入,以前没有分析过该CMS,决定对着补丁看一下近期的版本来分析下

环境:

Windows 10

php5.5.9

Apache

代码分析

GitHub上看到该cms近期版本更新很频繁

本文先对2.0.7版本分析下,首先与2.0.8版本来对比下

该处增加了一些敏感函数的过滤和正则上的改动,这说明在2.0.7版本中该段代码存在着安全问题,我们来看一下该段代码所在的函数做起着什么作用

在源码中找到了该函数的注释,该函数是用来解析模板中的IF标签

继续阅读我们可以看到,在进行了过滤之后,如果没有发现危险的项目,会将if中的代码带入到eval中执行,如图

那么可以联想到,如果可以在页面中插入if标签并且绕过该处的安全验证,就可以执行任意php代码,下面来寻找一下是否存在插入if标签的地方,寻找之前我们先看一下该CMS的标签语法

{pboot:if(TRUE)}test{/pboot:if}

在后台尝试在站点信息编辑页面插入

进入首页看一下

可以看到这里是成功解析了的,那么下面我们需要来思考如何绕过前面的安全过滤

我们来看第一个判断

1
2
3
4
if ((function_exists($value) || preg_match('/^eval$/i', $value)) && ! in_array($value, $white_fun)) {
$danger = true;
break;
}

该处的意思是如果if中存在着一个函数并且该函数不在白名单中将会被认定为危险,看一下白名单中的函数

1
$white_fun = array('date','in_array','explode','implode');

显然没有可以利用的函数,我们需要一些可以进行输出或者执行代码的函数来进行下一步的验证,在该处我们如果想越过验证可以参考一下KCon 2019P神的一个议题

简单的来说就是可以在函数名和括号之间插入一些控制字符,这样函数仍然会正常执行,但是在本例中function_exists将会失效,我们可以插入下面的代码来尝试下

可以看到是成功执行的,下面来看一下第二个过滤点的if判断

1
if (preg_match('/(\$_GET\[)|(\$_POST\[)|(\$_REQUEST\[)|(\$_COOKIE\[)|(\$_SESSION\[)|(file_put_contents)|(fwrite)|(phpinfo)|(base64_decode)|(`)|(shell_exec)|(eval)|(system)|(exec)|(passthru)/i', $matches[1][$i]))

这里虽然过滤了很多函数,但是我们还有assert可用,首先想到的直接是下面的写法

但是经过测试,存在$符号的时候模板不会解析,该处我并没有深究为什么出现这个情况,而是想到了codebreaking中无参数RCE来解决这个问题,这样就可以不传入其他一些字符,只使用函数来利用了

这里可以使用getallheaders来获取head

这里可以利用cookie,使用current方法,并且将print_r改成assert

将代码写在cookie中执行