用户
搜索
  • TA的每日心情
    奋斗
    2017-6-10 15:08
  • 签到天数: 24 天

    连续签到: 1 天

    [LV.4]经常看看II

    i春秋-核心白帽

    Rank: 4

    18

    主题

    406

    帖子

    292

    魔法币
    收听
    0
    粉丝
    5
    注册时间
    2016-3-19
    发表于 2018-10-17 15:51:26 56410

    接上次发的v1.1.8前台注入后,详情:https://bbs.ichunqiu.com/thread-46172-1-1.html
    在cnvd又看到了v1.1.9注入:

    因为v1.1.8修复方式为:

            $string = htmlspecialchars(trim($string), ENT_QUOTES);
            $string = addslashes($string);

    所以在v1.1.9中产生sql注入的原因可能就是没有单引号包裹造成的。
    于是我下载了v1.1.9与v1.2.1两个版本,利用Beyond Compare 4工具来对比。(我也不知道我为啥要用这两个版本来对比,而不是v1.1.8与v1.1.9来对比,想到感觉差不多)

    V1.1.9中的一处注入:

    \apps\api\controller\CmsController.php 中的search函数:

     // 搜索
        public function search()
        {
            if (! $_POST) {
                json(0, '请使用POST提交!');
            }
    
            $acode = get('acode') ?: $this->lg;
            $num = get('num') ?: $this->config('pagesize');
            $order = get('order') ?: 'date';
    
            switch ($order) {
                case 'date':
                case 'istop':
                case 'isrecommend':
                case 'isheadline':
                case 'visits':
                case 'likes':
                case 'oppose':
                    $order = $order . ' DESC';
                    break;
                default:
                    $order = $order . ' ASC';
            }
            $order .= ",sorting ASC,id DESC";
    
            // 获取主要参数
            $field = post('field');
            $keyword = post('keyword');
            $scode = post('scode');
    
            // 匹配单一字段及关键字搜索方式
            $where = array();
            if ($field && $keyword) {
                $where[$field] = $keyword;
            } elseif ($keyword) {
                $where['title'] = $keyword;
            }
    
            // 数据处理
            $cond = array(
                'd_source' => 'post',
                'd_regular' => '/^[^\s]+$/'
            );
            foreach ($_POST as $key => $value) {
                $where[$key] = filter($key, $cond);
                if ($_POST[$key] && ! $where[$key]) {
                    json(0, '您的查询含有非法字符,已被系统拦截');
                }
            }
    
            // 去除特殊键值
            unset($where['keyword']);
            unset($where['field']);
            unset($where['scode']);
            unset($where['page']);
            unset($where['appid']);
            unset($where['timestamp']);
            unset($where['signature']);
            unset($where2['from']);
            unset($where2['isappinstalled']);
    
            // 读取数据
            $data = $this->model->getList($acode, $scode, $num, $order, $where);

    可以看到:

     $order = get('order') ?: 'date';
    
            switch ($order) {
                case 'date':
                case 'istop':
                case 'isrecommend':
                case 'isheadline':
                case 'visits':
                case 'likes':
                case 'oppose':
                    $order = $order . ' DESC';
                    break;
                default:
                    $order = $order . ' ASC';
            }
            $order .= ",sorting ASC,id DESC";

    这里的$order变量为get方式获取,除了单双引号反斜杠都可以引入(不知道这个get方法的,移步:https://bbs.ichunqiu.com/thread-46172-1-1.html
    然后传递进入了getList函数:

        // 列表内容
        public function getList($acode, $scode, $num, $order, $where = array())
        {
            ....
            return parent::table('ay_content a')->field($fields)
                ->where($where1, 'OR')
                ->where($where2)
                ->where($where, 'AND', 'AND', true)
                ->join($join)
                ->order($order)     //$order变量又直接传入进了order方法。
                ->page(1, $num)
                ->decode()
                ->select();
        }
        final public function order($order)
        {
            if (is_array($order)) {
                $order_string = 'ORDER BY ';
                foreach ($order as $key => $value) {
                    if (is_int($key)) {
                        $order_string .= $value . ',';
                    } else {
                        $order_string .= $key . ' ' . $value . ',';
                    }
                }
                $this->sql['order'] = substr($order_string, 0, - 1);
            } else {
                $this->sql['order'] = 'ORDER BY ' . $order;
            }
            return $this;
        }

    看到最后第4行的:

    $this->sql['order'] = 'ORDER BY ' . $order;

    直接将$order拼接了进去。所以造成了注入。
    注意:这是需要开启api接口,默认关闭,所以对实战来说鸡肋。

    发表于 2018-10-17 17:00:55
    学习学习。。。
    http://www.anonymou5.com
    使用道具 举报 回复
    使用道具 举报 回复
    发表于 2018-10-19 12:24:06
    请问:怎么看出来是需要api接口才可以注入的,只看到Get一个order参数进来
    使用道具 举报 回复
    发表于 2018-10-19 13:52:51
    本帖最后由 w_uai 于 2018-10-19 13:54 编辑
    罪ssss 发表于 2018-10-19 12:24
    请问:怎么看出来是需要api接口才可以注入的,只看到Get一个order参数进来

    请问你问的是为啥需要后台开启api才可以注入吗?还是为啥这里为啥造成了注入?
    第一个:因为该文件是在api模块目录下面,想要调用他就需要从api.php入口文件调用。这其中的路由解析规则肯定在开头会有一个类似的判断if($api_open !=1)exit; 因为他那个运行文件加密了,解密出来全部内容在一行,不好看,所以没看了了。我直接就是访问api.php文件,他会提示说没开启api接口,然后我去后台系统配置中找,真的有,还为关闭状态,直接开启就好了。就是一句话黑盒测试。测不出来在慢慢去看代码。这里可以用phpstorm+xdebug那个动态调试。
    第二个:漏洞的造成就是上面,在最后只说了$order拼接进去,但是却还是没到sql执行的地方,这个要细细看的话就需要去看db类了,因为他前面还有其他的where方法,我就是直接开启mysql监控,然后直接先测试下,看看语句是什么样的。
    使用道具 举报 回复
    发表于 2018-10-19 15:56:52
    w_uai 发表于 2018-10-19 13:52
    请问你问的是为啥需要后台开启api才可以注入吗?还是为啥这里为啥造成了注入?
    第一个:因为该文件是在api ...

    谢谢!!!!很详细
    使用道具 举报 回复
    发新帖
    您需要登录后才可以回帖 登录 | 立即注册