首先本地搭建环境,我所使用的是Windows PHPstudy集成环境。使用起来非常方便。特别是审计的时候。可以任意切换PHP版本。

本文作者:226safe Team – Poacher

0×01 CMS简介:

开源免费的PHP内容管理系统,不需要高深专业技术轻松搭建网站,使用简单 灵活方便 稳定快捷,风格切换 想换就换 适应不同需求。

0×00 正文:

漏洞所在处:/application/admin/controller/Index.php

漏洞所在行:即为以下代码的内容

两个越权以及XSS都在同一个方法内。所以直接贴上整个方法的代码(下文说的行数为本文章所贴代码的行数,并非实际cms漏洞文件的行数)

<?php
    public function rewrite()
    {
        $this->checkUser();
        $this->checkPermissions(6);
        if(Request::instance()->has('postId','post'))
        {
            //验证输入内容
            $rule = [
                'biaoti' => 'require',
                'neirong' => 'require'
            ];
            $msg = [
                'biaoti.require' => Lang::get('The title must be filled in'),
                'neirong.require' => Lang::get('Article content must be filled out')
            ];
            $data = [
                'biaoti' => Request::instance()->post('biaoti'),
                'neirong' => Request::instance()->post('neirong')
            ];
            $validate = new Validate($rule, $msg);
            if(!$validate->check($data))
            {
                $this->error($validate->getError());//验证错误输出
                return false;
            }
            $neirong = str_replace('<img','<img class="img-responsive"',Request::instance()->post('neirong'));
            $guanjianci = str_replace(',',',',Request::instance()->post('guanjianci'));
            $data = ['post_keywords' => htmlspecialchars($guanjianci), 'post_source' => htmlspecialchars(Request::instance()->post('laiyuan')), 'post_content' => $neirong, 'post_title' => htmlspecialchars(Request::instance()->post('biaoti')), 'post_excerpt' => htmlspecialchars(Request::instance()->post('zhaiyao')), 'comment_status' => Request::instance()->post('pinglun'), 'post_modified' => date("Y-m-d H:i:s"), 'post_type' => Request::instance()->post('xingshi'), 'thumbnail' => Request::instance()->post('suolvetu'), 'istop' => Request::instance()->post('zhiding'), 'recommended' => Request::instance()->post('tuijian')];
            Db::name('posts')
                ->where('id', Request::instance()->post('postId'))
                ->update($data);
            Db::name('term_relationships')->where('object_id',Request::instance()->post('postId'))->delete();
            // var_dump(Db::name('term_relationships')->getLastsql());exit;
            if(isset($_POST['fenlei']) && is_array($_POST['fenlei']))
            {
                $data = [];
                foreach($_POST['fenlei'] as $key => $val)
                {
                    $data[] = ['object_id' => Request::instance()->post('postId'), 'term_id' => $val];
                }
                Db::name('term_relationships')->insertAll($data);
            }
            Hook::add('rewrite_post',$this->plugins);
            $params = [
                'id' => Request::instance()->post('postId')
            ];
            Hook::listen('rewrite_post',$params,$this->ccc);
            Hook::add('rewrite_post_later',$this->plugins);
            Hook::listen('rewrite_post_later',$params,$this->ccc);
        }
        $classify = Db::name('term_relationships')->field('term_id')->where('object_id',Request::instance()->get('art'))->select();
        $fenlei =$this->getfenlei();
        foreach($fenlei as $key => $val){
            $fenlei[$key]['classify'] = 0;
            foreach($classify as $cval){
                if($val['id'] == $cval['term_id']){
                    $fenlei[$key]['classify'] = 1;
                    break;
                }
            }
        }
        $wzid = 0;
        if(Request::instance()->has('postId','post'))
        {
            $wzid = Request::instance()->post('postId');
        }
        elseif(Request::instance()->has('art','get'))
        {
            $wzid = Request::instance()->get('art');
        }
        $data = Db::name('posts')->where('id',$wzid)->select();
        $data[0]['post_content'] = str_replace('<img class="img-responsive"','<img',$data[0]['post_content']);
        $this->assign('data', $data[0]);
        $this->writeAlias($wzid);
        $this->switchEditor();
        $this->assign('backstageMenu', 'neirong');
        $this->assign('option', 'articles');
        $this->assign('fenlei', $fenlei);
        return $this->view();
    }

我大概讲一下这两个越权所在的地方。

第一处:在点击编辑文章的时候将文章内容查询出来并且遍历在页面中。

第二处:点击提交保存时候将修改的文章内容保存。

首先我们先来看第一处。我们先看代码的第六行(很明显的可以看出来是使用THINKPHP5开发的)。

这里是先判断是否存在postId请求参数并且请求类型为POST。就是说如果是以POST方式将postId传了过来的话就进入真区间。

看上述代码得知7-52行是进行的编辑修改操作。由于我们这里先说第一处。第一处的请求是为GET。所以我们需要继续往下走。从第53行开始处理的是正常get请求的一些操作。

从69行开始看。如果是get方式并且art值存在的话。那么$wzid则被赋值为get传过来的art值。接下来走到73行。我们可以清楚的看到。该行代码的where条件仅是id等于$wzid值即可查询。并没有进行所属用户的权限判断。上面得知我们$wzid的值是可控的。所以我们只要修改art值即可获取其他用户的文章内容。

以下面为例,test002有一篇文章id为6。

直接将art=4改成art=6

来查看一下所执行的SQL语句。

这样就可以非常明显的看出来了。并没有判断该文章所属用户。

接下来,我们看第二处。第二处跟第一处原理差不多。所以我也就不多讲了。直接定位到30行代码。

Db::name(‘posts’)->where(‘id’, Request::instance()->post(‘postId’))->update($data);

继续瞄准where条件。条件直接就是id等于传过来的postId值。在我们修改的时候。直接抓包。将POST包里面的postId修改成任意一篇文章的id。即可越权修改。

直接改成我们刚才的那篇文章id为6

修改成功。

存储型XSS:

我们看到29行。即为以下代码:

$data = ['post_keywords' => htmlspecialchars($guanjianci), 'post_source' => htmlspecialchars(Request::instance()->post('laiyuan')), 'post_content' => $neirong, 'post_title' => htmlspecialchars(Request::instance()->post('biaoti')), 'post_excerpt' => htmlspecialchars(Request::instance()->post('zhaiyao')), 'comment_status' => Request::instance()->post('pinglun'), 'post_modified' => date("Y-m-d H:i:s"), 'post_type' => Request::instance()->post('xingshi'), 'thumbnail' => Request::instance()->post('suolvetu'), 'istop' => Request::instance()->post('zhiding'), 'recommended' => Request::instance()->post('tuijian')];

我们可以看到在这里的。能够给用户看到的参数    该过滤的已经过滤了。正常情况下呢。是不会存在xss了。但是呢。开发者可能忽略了一个地方。就是:’thumbnail’ => Request::instance()->post(‘suolvetu’)。这里呢。是获取的图片缩略图内容。如果上传了图片则有值。否则就为空。但是呢。由于前面并没有对该值做限制。所以呢这里我们是可以任意的构造POST参数的。首先我们先定位到POST这个方法来看看。

<?php
    /**
     * 设置获取获取POST参数
     * [url=home.php?mod=space&uid=65943]@Access[/url] public
     * @param string        $name 变量名
     * @param mixed         $default 默认值
     * @param string|array  $filter 过滤方法
     * [url=home.php?mod=space&uid=126298]@return[/url] mixed
     */
    public function post($name = '', $default = null, $filter = null)
    {
        if (empty($this->post)) {
            $this->post = $_POST;
        }
        if (is_array($name)) {
            $this->param       = [];
            return $this->post = array_merge($this->post, $name);
        }
        return $this->input($this->post, $name, $default, $filter);
    }

对应这个方法。如果单单传一个参数进来。那么将不会进行过滤的。我们可以看到。$filter默认是等于null的,如果$filter不传的话则为null,所以我们这里可以直接插入xss代码。只要在POST参数插入:&suolvetu=”/><script>alert(‘xss’)</script> 即可

我们使用管理员进入后台。看看是否触发。

成功触发鸟。

PS:本着交流分享。如果有好的方法或者思路以及上文讲述不正确的地方欢迎指出。谢谢!

代码审计之Catfish CMS v4.5.7后台作者权限越权两枚+存储型XSS一枚的更多相关文章

  1. 【代码审计】大米CMS_V5.5.3 后台多处存储型XSS漏洞分析

      0x00 环境准备 大米CMS官网:http://www.damicms.com 网站源码版本:大米CMS_V5.5.3试用版(更新时间:2017-04-15) 程序源码下载:http://www ...

  2. 【代码审计】iZhanCMS_v2.1 前台存储型XSS漏洞分析

      0x00 环境准备 iZhanCMS官网:http://www.izhancms.com 网站源码版本:爱站CMS(zend6.0) V2.1 程序源码下载:http://www.izhancms ...

  3. 【代码审计】eduaskcms_v1.0.7前台存储型XSS漏洞分析

      0x00 环境准备 eduaskcms官网:https://www.eduaskcms.xin 网站源码版本:eduaskcms-1.0.7 程序源码下载:https://www.eduaskcm ...

  4. 【代码审计】QYKCMS_v4.3.2 前台存储型XSS跨站脚本漏洞分析

      0x00 环境准备 QYKCMS官网:http://www.qykcms.com/ 网站源码版本:QYKCMS_v4.3.2(企业站主题) 程序源码下载:http://bbs.qingyunke. ...

  5. PlugNT CMS v4.6.3 最新功能

    PlugNT CMS v4.6.3 最新功能: 弃用标签 selected="commend,stick" 改为andwhere="commend=1 and stick ...

  6. 帝国CMS(EmpireCMS) v7.5后台getshell分析(CVE-2018-18086)

    帝国CMS(EmpireCMS) v7.5后台getshell分析(CVE-2018-18086) 一.漏洞描述 EmpireCMS 7.5版本及之前版本在后台备份数据库时,未对数据库表名做验证,通过 ...

  7. 帝国CMS(EmpireCMS) v7.5后台任意代码执行

    帝国CMS(EmpireCMS) v7.5后台任意代码执行 一.漏洞描述 EmpireCMS 7.5版本及之前版本在后台备份数据库时,未对数据库表名做验证,通过修改数据库表名可以实现任意代码执行. 二 ...

  8. 帝国CMS(EmpireCMS) v7.5 后台XSS漏洞分析

    帝国CMS(EmpireCMS) v7.5 后台XSS漏洞分析 一.漏洞描述 该漏洞是由于代码只使用htmlspecialchars进行实体编码过滤,而且参数用的是ENT_QUOTES(编码双引号和单 ...

  9. MVC5+EF6 简易版CMS(非接口) 第三章:数据存储和业务处理

    目录 简易版CMS后台管理系统开发流程 MVC5+EF6 简易版CMS(非接口) 第一章:新建项目 MVC5+EF6 简易版CMS(非接口) 第二章:建数据模型 MVC5+EF6 简易版CMS(非接口 ...

随机推荐

  1. 一个简单的MVVM雏形

    这是@尚春实现的MVVM,使用定时器轮询,只支持{{}}与input.value的修改. 这只能算是一个玩具,真正的MVVM需要有更复杂的扫描机制,JS解析器,双向绑定链什么的. <!DOCTY ...

  2. 【Java】JavaIO(一)、基础知识

    一.常用概念介绍 Java的IO,实现输入输出的基础,可以方便的实现数据的输入输出 二.流的分类 1. 按照流向来分: a). 输入流:向应用程序输 b). 输出流:从应用程序中输出 输入输出流是站在 ...

  3. 使用.sig签名验证文件

    Linux下载文件的时候,由于网络等原因,下载的文件可能不完整,对于别有心机的人可以更改文件,这就需要我们对文件的完整性进行验证.这里以securityonion-14.04.5.2.iso为例进行验 ...

  4. java 主类的main方法调用其他方法

    方法1:A a=new test().new A(); 内部类对象通过外部类的实例对象调用其内部类构造方法产生,如下: public class test{ class A{ void fA(){ S ...

  5. JQuery 对象和事件

    JQuery 对象和事件 一:JQuery 对象和 Dom 对象 在使用 JQuery 过程中,我们一般(也是绝大多数情况下,除非我们使用了第二个框架)只有两类对象,即:JQuery 对象和 Dom ...

  6. Android 4.0关于开机启动服务

    针对使用App应用管理强制停止的App,重启系统后不能收到开机启动, 需要运行一次后,在下次再启动时,才可以正确收到.

  7. 23 DesignPatterns学习笔记:C++语言实现 --- 2.2 Adapter

    23 DesignPatterns学习笔记:C++语言实现 --- 2.2 Adapter 2016-07-22 (www.cnblogs.com/icmzn) 模式理解

  8. windows本地代码上传github

    1.下载Git工具 https://www.git-scm.com/download/win 2.进到项目目录 cd /dir/dir/dir/file 3.初始化 git init 4.添加远程仓库 ...

  9. python经典书记必读:Python编程快速上手 让繁琐工作自动化

    所属网站分类: 资源下载 > python电子书 作者:熊猫烧香 链接:http://www.pythonheidong.com/blog/article/69/ 来源:python黑洞网,专注 ...

  10. Cockroachdb 一、系统环境

    cockroachdb 一.系统环境 **硬件** 最低标准 a 至少3个节点保证集群可用副本 b 每个节点至少1CPU ,2GB RAM.增加资源配置可支持处理更多的数据,负载,高并发,高性能. 最 ...