题外: 今天是上班第一天,全都在做准备工作,明天开始正式实战做事。

看着周围稍年长的同事和老大做事,自己的感觉就是自己还是差的很多很多,自己只能算个废物。

学无止境,我这样的垃圾废物就该多练,保持战斗的欲望,嗯。

今晚回来了没什么事,跟着网上的师傅复现审计一套awd的源码吧。

看了下也是很简单的一套源码,不过在某的小地方可能不容易发现,所以这篇自己把过程写的尽可能详细、对新手友好。

0x01 前台储存型XSS

在留言板处存在储存型XSS

来看看代码  存储xss,首先是前台接收数据没有过滤,然后是后台存储后输出的时候也没有过滤,两个点,一个输入,一个输出 ,都没过滤造成xss存储漏洞。

首先是前台接收:

提交留言的时候我们请求的地址是:

POST /YXCMS_v1.4.7/index.php?r=default/column/index&col=guestbook HTTP/1.1

对应文件的地址:

default模块中column控制器的index()方法.快速审计我们只用找到接收插入数据的地方即可:

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'];

这里$sortinfo=model('sort')->find("ename='{$ename}'",'id,name,ename,path,url,type,deep,method,tplist,keywords,description,extendid');

这里其实很简单,不过有的新手朋友看不懂一些细节,这里就记录的细一些:

先看这个model('sort') 追踪到函数:

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];
}

这个函数就是找到对应的model文件,如果存在该model的类就新建对象,mvc都是这个套路,这里就是sortModel,

然后是:调用这个函数的find("ename='{$ename}'",'id,name,ename,path,url,type,deep,method,tplist,keywords,description,extendid');函数,我们继续来看看find(),

追踪到model的基类(protected\base\model\model.php):

public function find($condition = '', $field = '', $order = ''){
        return $this->model->table($this->table, $this->ignoreTablePrefix)->field($field)->where($condition)->order($order)->find();
    }

这里其实非常非常明显了,table方法指定操作的表名,field操作指定的字段,where是指定条件,order是排序,

这里->find()函数是cpModel的find函数,内部调用的select函数,将封装在options数组中的信息进行拼接查询。

//查询多条信息,返回数组
     public function select() {
        $table = $this->options['table'];    //当前表
        $field = $this->options['field'];    //查询的字段
        $where = $this->_parseCondition();    //条件
        return $this->query("SELECT $field FROM $table $where", array(), true);
     }

关于这里如果 知道model是cpModel和相应函数的作用,写了下追踪过程:

这里调用了自己的model属性的table方法,我们再转到构造函数来看,虽然有点绕,但是别晕,mvc都是这样,清楚了后一点不难。

public function __construct( $database= 'DB', $force = false){
        $this->model = self::connect( config($database), $force);
        $this->db = $this->model->db;
    }

这里model属性是自己connect函数的返回值,看看connect函数;

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

不用追求细节末枝,我们只需要看到这里新建了cpModel,接着看

$model = new cpModel($config);

ok回到我们这里:

public function find($condition = '', $field = '', $order = ''){
        return $this->model->table($this->table, $this->ignoreTablePrefix)->field($field)->where($condition)->order($order)->find();
    }

调用了model对象的table方法,这里model对象我们已经知道是cpModel这个对象了,来看看它的table方法:

public function table($table, $ignorePre = false) {
        if ( $ignorePre ) {
            $this->options['table'] = $table;
        } else {
            $this->options['table'] = $this->config['DB_PREFIX'] . $table;
        }
        return $this;
    }

这里我们是走到:

$this->options['table'] = $this->config['DB_PREFIX'] . $table;

注意这里是调用model对象的table方法,也就是cpModel这个对象,而不是基类model,这里容易搞混淆哦~~~

而这里就大致知道我们插到哪个数据库了,config方法是定义数据库前缀,表前缀也就是我们当初传入的sort,操作的表也就是yx_sort,其他的函数追踪也大同小异 ,我们再回到当初的:

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;
        }

这里根据不同的type值调用不同的方法,我们来看看我们留言板的数据库是插在哪个表的。

而这个type是查询返回的字典,我们提交的col的值是guestbook,对应的type是6,所以我们执行的是

case 6://表单
                $this->extend($sortinfo,$path,$deep);
                break;

看到这里的extend()函数,我们跟踪:

到这里我们只关注插入相关的操作:

$list=model('extend')->Extselect($tablename,"ispass='1'",'','id desc',$limit);

又是和上面新建model对象一样,这次是extendModel的extselect,我们跟踪看看是否是插入操作:

这里还是最后调用的cpModel的insert方法,中间没有任何过滤。到这里前台接收的代码就分析完成,我们再来看看后台从数据库读取数据的代码.

然后是后台读取:

http://192.168.5.149/YXCMS_v1.4.7/index.php?r=admin/index/login

admin 123456

来看看代码部分

文件位置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('信息修改失败~');
         }
    }

发现读取数据也没有任何过滤和转移。造成存储xss。

0x02 后台模版getshell

这里可以直接对php文件进行操作。。

并且没有任何过滤措施:

0x03  任意文件删除

文件位置protected/apps/admin/controller/photoController.php:

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 '原图以及缩略图删除成功~';
    }

代码首先判断是否含有POST参数picname,然后赋给$picname,获取路径uploadpath=ROOT_PATH.'upload/photos/',使用file_exists()函数判断文件是否存在,然后再unlink()进行删除。参数$picname完全可控,导致任意文件删除:

yxcms代码不是很绕,主要还是心细

代码审计-YXcms1.4.7的更多相关文章

  1. PHP代码审计中你不知道的牛叉技术点

    一.前言 php代码审计如字面意思,对php源代码进行审查,理解代码的逻辑,发现其中的安全漏洞.如审计代码中是否存在sql注入,则检查代码中sql语句到数据库的传输 和调用过程. 入门php代码审计实 ...

  2. 技术专题-PHP代码审计

    作者:坏蛋链接:https://zhuanlan.zhihu.com/p/24472674来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 一.前言 php代码审计如字面 ...

  3. 关于PHP代码审计和漏洞挖掘的一点思考

    这里对PHP的代码审计和漏洞挖掘的思路做一下总结,都是个人观点,有不对的地方请多多指出. PHP的漏洞有很大一部分是来自于程序员本身的经验不足,当然和服务器的配置有关,但那属于系统安全范畴了,我不太懂 ...

  4. Kindeditor 代码审计

    <?php /** * KindEditor PHP * * 本PHP程序是演示程序,建议不要直接在实际项目中使用. * 如果您确定直接使用本程序,使用之前请仔细确认相关安全设置. * */ r ...

  5. 一个CMS案例实战讲解PHP代码审计入门

    前言 php代码审计介绍:顾名思义就是检查php源代码中的缺点和错误信息,分析并找到这些问题引发的安全漏洞. 1.环境搭建: 工欲善其事必先利其器,先介绍代码审计必要的环境搭建 审计环境 window ...

  6. php代码审计基础笔记

    出处: 九零SEC连接:http://forum.90sec.org/forum.php?mod=viewthread&tid=8059 --------------------------- ...

  7. 【PHP代码审计】 那些年我们一起挖掘SQL注入 - 3.全局防护Bypass之Base64Decode

    0x01 背景 现在的WEB程序基本都有对SQL注入的全局过滤,像PHP开启了GPC或者在全局文件common.php上使用addslashes()函数对接收的参数进行过滤,尤其是单引号.同上一篇,我 ...

  8. 【PHP代码审计】 那些年我们一起挖掘SQL注入 - 2.全局防护Bypass之UrlDecode

    0x01 背景 现在的WEB程序基本都有对SQL注入的全局过滤,像PHP开启了GPC或者在全局文件common.php上使用addslashes()函数对接收的参数进行过滤,尤其是单引号.遇到这种情况 ...

  9. PHP代码审计】 那些年我们一起挖掘SQL注入 - 1.什么都没过滤的入门情况

    0x01 背景 首先恭喜Seay法师的力作<代码审计:企业级web代码安全架构>,读了两天后深有感触.想了想自己也做审计有2年了,决定写个PHP代码审计实例教程的系列,希望能够帮助到新人更 ...

随机推荐

  1. 自荐RedisViewer有情怀的跨平台Redis可视化客户端工具

    # **自荐一个有情怀的跨平台Redis可视化客户端工具——RedisViewer**[转载自 最美分享Coder 2019-09-17 06:31:00](https://www.toutiao.c ...

  2. <%@ include %>导入的文件乱码

    如: <% String ss = (String) session.getAttribute("username"); if (ss == null || ss == &q ...

  3. STL中关于全排列next_permutation以及prev_permutation的用法

    这两个函数都包含在algorithm库中.STL提供了两个用来计算排列组合关系的算法,分别是next_permutation和prev_permutation. 一.函数原型 首先我们来看看这两个函数 ...

  4. 腾讯云和阿里云部署web 项目tomcat 日志 中文变成问号

    在部署项目到云上的时候,遇到了tomcat logs 日志中文变问号的问题,今天终于得到解决了 这是中文变成问号的的截图 打开到tomcat bin 目录的文件夹 找到catalina.sh  文件 ...

  5. 使用Spring中的PropertyPlaceholderConfigurer读取文件

    目录 一. 简介 二. XML 方式 三. Java 编码方式 一. 简介 大型项目中,我们往往会对我们的系统的配置信息进行统一管理,一般做法是将配置信息配置与一个cfg.properties 的文件 ...

  6. Mysql 笔记(一)

    InnoDB存储引擎 mysql 存储引擎(好难用,看https://www.zybuluo.com/eqyun/note/27850) 简介 InnoDB是事务安全的MySQL存储引擎,从MySQL ...

  7. 《菜鸟程序员成长之路:从技术小白到阿里巴巴Java工程师》

    <菜鸟程序员成长之路:从技术小白到阿里巴巴Java工程师> 国庆节快乐!一年一度长度排第二的假期终于来了. 难得有十一长假,作者也想要休息几天啦. 不管你是选择出门玩,还是在公司加班,在学 ...

  8. CVPR 2019 论文解读 | 小样本域适应的目标检测

    引文 ​ 最近笔者也在寻找目标检测的其他方向,一般可以继续挖掘的方向是从目标检测的数据入手,困难样本的目标检测,如检测物体被遮挡,极小人脸检测,亦或者数据样本不足的算法.这里笔者介绍一篇小样本(few ...

  9. java进阶文章优选链接,面试干货集合

    Java多线程: java多线程详细总结:https://blog.csdn.net/chenruijia170707/article/details/78505351 ThreadLocal 用法及 ...

  10. idea 自动生成并跳转单元测试

    在要测试的类上按快捷键ctrl + shift + t,选择Create New Test,在出现的对话框的下面member内勾选要测试的方法,点击ok 或者点击菜单栏Navigate–>tes ...