写点什么

我赌一包辣条这是全网最详细的代码审计 (没有之一)

发布于: 2 小时前
我赌一包辣条这是全网最详细的代码审计(没有之一)

前言


本篇是对极致 CMSv1.7 漏洞的一些新的发现,先从 MVC 开始到漏洞的发掘利用 MVC 篇


首先,先打开 index.php


<?php// 应用目录为当前目录define('APP_PATH', __DIR__ . '/');
// 开启调试模式//define('APP_DEBUG', true);
//定义项目目录define('APP_HOME','Home');
//定义项目模板文件目录define('HOME_VIEW','template');
//定义项目模板公共文件目录define('Tpl_common','');
//定义项目控制器文件目录define('HOME_CONTROLLER','c');
//定义项目模型文件目录define('HOME_MODEL','m');

//定义项目默认方法define('DefaultAction','jizhi');
//取消logdefine('StopLog',false);
//定义静态文件路径define('Tpl_style','/static/');
// 加载框架文件require(APP_PATH . 'FrPHP/Fr.php');
// 就这么简单~
复制代码


先是 define 定义,然后加载框架,所以直接去加载的框架看看,是再 FrPHP/Fr.php,打开后,拖到最后,发现



先加载了配置文件,因为配置文件里是用单引号包裹,就没什么好看的。然后再会触发 FrPHP 的 eun 方法,跟进查看


我是一名网络安全工作者,擅长渗透攻防方面的内容,学习工作了几年,也整理了很多渗透、攻防、审计等资料文档,需要这份文档的读者**点我资料领取**



前三个很简单,是配置数据库,和对传入的数据的简单处理,需要注意的是 route()路由处理,对它进行跟进



在 141 行接收 url 传入的参数,然后在 206 行对控制器和方法名进行 define 赋值



然后在 212 行对传入的 url 进行处理,把输入的 url 前面传入的 index.php 先舍去



然后在 231 行开始,会对传入的 url 拆分,变为数组,如我 url 输入:index.php/Home/ce,会被拆分为 Home 和 ce 然后在 243 行赋值给控制器名和方法名





然后再调用我们指定的类的方法


漏洞篇

SQL 注入

在\Home\c\HomeController.php 中的 jizhi 中



看到在 101 行存在把url 则是由这里:



$url 只是对 url 栏输入的进行接收,所以我们先来看下接收的方式:



看出只是对接收 index.php 后面的。回到第 101 行,看到会先以/来进行分割,然后取出数组的第一个进入 find 中,执行 sql 语句,所以我们考虑怎么对其进行攻击利用,但是我们不能更换/Home/否则会无法执行 jizhi,但是我们回到 MVC 篇中看到的,在第 264 行中,我们可以看到如果我们输入的不存在,会默认 controllerName 为 Home



所以这就意味着我们可以随意的写入,都会最终默认转换为 Home,所以直接进行 SQL 注入:



然后因为没有过滤,就是正常的 sql 注入了,HomeController.php 中的 jizhi_details 中还有一处 sql 注入,是通过传值来进行 sql 注入的,难度不打,有兴趣的可以自行去看看 XSS1


漏洞在\Home\c\UserController.php 的 release 中,主要利用代码如下:if(_POST){data = $this->frparam();



$w = get_fields_data($data,$w['molds']);
switch($w['molds']){ case 'article': if(!$data['body']){
if($this->frparam('ajax')){ JsonReturn(['code'=>1,'msg'=>'内容不能为空!']); }else{ Error('内容不能为空!'); } } if(!$data['title']){ if($this->frparam('ajax')){ JsonReturn(['code'=>1,'msg'=>'标题不能为空!']); }else{ Error('标题不能为空!'); } } $data['body'] = $this->frparam('body',4); $w['title'] = $this->frparam('title',1); $w['seo_title'] = $w['title']; $w['keywords'] = $this->frparam('keywords',1); $w['litpic'] = $this->frparam('litpic',1); $w['body'] = $data['body']; $w['description'] = newstr(strip_tags($data['body']),200);

break; ... } ...
if($this->frparam('id')){ $a = M($w['molds'])->update(['id'=>$this->frparam('id')],$w); if(!$a){ if($this->frparam('ajax')){ JsonReturn(['code'=>1,'msg'=>'未修改内容,不能提交!']); }else{ Error('未修改内容,不能提交!'); } } if($this->frparam('ajax')){ JsonReturn(['code'=>0,'msg'=>'修改成功!','url'=>U('user/posts',['molds'=>$w['molds']])]); }else{ Success('修改成功!',U('user/posts',['molds'=>$w['molds']])); }
}else{ $a = M($w['molds'])->add($w); if(!$a){ if($this->frparam('ajax')){ JsonReturn(['code'=>1,'msg'=>'发布失败,请重试!']); }else{ Error('发布失败,请重试!'); } } if($this->frparam('ajax')){ JsonReturn(['code'=>0,'msg'=>'发布成功!','url'=>U('user/posts',['molds'=>$w['molds']])]); }else{ Success('发布成功!',U('user/posts',['molds'=>$w['molds']])); }
}}
复制代码


很简单,就是先赋值给data 会经过 get_fields_data 函数,该函数代码如下:


function get_fields_data($data,$molds,$isadmin=1){     if($isadmin){         $fields = M('fields')->findAll(['molds'=>$molds,'isadmin'=>1],'orders desc,id asc');     }else{         //前台需要判断是否前台显示         $fields = M('fields')->findAll(['molds'=>$molds,'isshow'=>1],'orders desc,id asc');     }     foreach($fields as $v){         if(array_key_exists($v['field'],$data)){             switch($v['fieldtype']){                 case 1:                 case 2:                 case 5:                 case 7:                 case 9:                 case 12:                 $data[$v['field']] = format_param($data[$v['field']],1);                 break;                 case 11:                 $data[$v['field']] = strtotime(format_param($data[$v['field']],1));                 break;                 case 3:                 $data[$v['field']] = format_param($data[$v['field']],4);                 break;                 case 4:                 case 13:                 $data[$v['field']] = format_param($data[$v['field']]);                 break;                 case 14:                 $data[$v['field']] = format_param($data[$v['field']],3);                 break;                 case 8:                 $r = implode(',',format_param($data[$v['field']],2));                 if($r!=''){                     $r = ','.$r.',';                 } 
$data[$v['field']] = $r; break;
} }else if(array_key_exists($v['field'].'_urls',$data)){ switch($v['fieldtype']){ case 6: case 10: $data[$v['field']] = implode('||',format_param($data[$v['field'].'_urls'],2)); break; } }else{
$data[$v['field']] = '';
}
} return $data;
}
复制代码


因为是先经过 sql 执行,所以可以构造data 的值赋值给 $w。


然后看到源代码的这一句this->frparam('body',4);,我们可以知道 4 是没有对 html 实体话的,所以可以对 body 进行 XSS 的注入,所以构造 payload:tid=2&article=asd&body=<script>alert(1)</script>&id=4&molds=article&title=qwe&sad=qwe



2


漏洞在\Home\c\ErrorController.php 中



很简单,直接输入


?msg=<script>alert(1)</script>


任意文件删除

漏洞在 A\c\SysController.php 中的 deletePicAll 处:



首先,frparam 函数功能是可以通过在浏览器传值进行对data 数组中 litpic 检测是否为文件名,然后再删除文件。


首先,我们先来一段测试代码:


function ce(){        $data = $this->frparam('data',1);        if($data!='') {            $pictures = M('pictures')->findAll('id in(' . $data . ')');            var_dump($pictures);            $isall = true;
foreach($pictures as $v){ if(strpos($v['litpic'],'http')===false){ var_dump('.'.$v['litpic']); }else{ $isall = false; } } } }
复制代码


然后先随意输入:



看到拼接后执行的语句,然后再来进行构造,因为过滤了单引号和双引号,所以用 16 进制,构造 payload:



这样就能先实现任意文件删除


【代码审计资料领取】



【代码审计资料领取】



【代码审计资料领取】



我是一名网络安全工作者,擅长渗透攻防方面的内容,学习工作了几年,也整理了很多渗透、攻防、审计等资料文档,需要这份文档的读者**点我资料领取**

用户头像

我是一名网络安全渗透师 2021.06.18 加入

关注我,后续将会带来更多精选作品,需要资料+wx:mengmengji08

评论

发布
暂无评论
我赌一包辣条这是全网最详细的代码审计(没有之一)