• 代码审计(一) 熊海cms V1.0


    菜鸡跟着前辈文章入门代码审计。

    首先看一下这套cms的源代码目录分布

    • admin//管理员后台
    • css//css样式
    • files//功能函数
    • images//图片文件
    • inc//配置信息
    • install//安装目录文件
    • seacmseditor//seacms编辑器
    • template//模板文件
    • upload//文件上传
    • index.php//网站入口
    • 使用说明.txt//使用说明

    漏洞总结

    id 漏洞 修复
    1 文件包含漏洞
    2 越权漏洞,登录绕过
    3 资料处存储型xss
    4 登录处存在POST sql注入
    5 前台的评论处存储型型xss
    6 post注入
    7 前台的一个报错get型sql注入
    8 sql注入报错伴随的反射型xss

    代码审计常见方法

    1. 通读全文代码
    2. 定向功能审计
    3. 敏感函数回溯

    1、通读全文代码

    第一个漏洞,文件包含漏洞

    <?php
    //单一入口模式
    error_reporting(0); //关闭错误显示
    $file=addslashes($_GET['r']); //接收文件名
    $action=$file==''?'index':$file; //判断为空或者等于index
    include('files/'.$action.'.php'); //载入相应文件
    ?>

    index.php里通过get方法接受一个r参数,然后用addslashes函数进行过滤,如果r的值为空则拼接包含files/index.php,若r参数非空,则包含files/$file.php

    php官方手册针对addslashes函数给的例子,该函数会对单引号(')、双引号(")、反斜线(\)与 NUL(NULL 字符)进行转义。

    <?php
    $str = "Is your name O'reilly?";
    
    // 输出: Is your name O\'reilly?
    echo addslashes($str);
    ?>

    所以,我们在url里面可以路径跳转,访问file目录之外的php文件,但是因为拼接了.php所以不能任意文件包含,例如包含1.txt是不可以的。

    在根目录写一个phpinfo.php的文件,通过index包含访问

    http://192.168.2.114/xscms/index.php?r=../phpinfo    #可以成功包含

    文件包含漏洞修复,想法是白名单操作,将所有可能调用的都写在一个数组里面,然后封装成一个函数。

    function protect($r){
        $key=0;
        $cars=array("about","contact","content","download","downloads","index","list","pages","software","submit");
        for ($i=0;$i<count($cars);$i++){
            if($r==$cars[$i])
                $key=1;
        }
        return $key;
    }

    源代码包含逻辑修改为

    <?php
    //单一入口模式
    error_reporting(0); //关闭错误显示
    $file=addslashes($_GET['r']); //接收文件名
    $action=$file==''?'index':$file; //判断为空或者等于index
    if (protect($action)==1){
        include('files/'.$action.'.php'); //载入相应文件}else{
        echo "图图已修复";
    }
    ?>

    我们跟进代码的正常逻辑,不指定参数r的值,包含files/index.php

    href="?r=content&cid=<?php echo $toutiaoimg['id']?>"

    可以看到主业,很多文章的连接如上,包含content.php,跟进content.php文件

    <?php 
    require 'inc/conn.php';
    require 'inc/time.class.php';
    $query = "SELECT * FROM settings";
    $resul = mysql_query($query) or die('SQL语句有误:'.mysql_error());
    $info = mysql_fetch_array($resul);
    
    $id=addslashes($_GET['cid']);
    $query = "SELECT * FROM content WHERE id='$id'";
    $resul = mysql_query($query) or die('SQL语句有误:'.mysql_error());
    $content = mysql_fetch_array($resul);
    
    $navid=$content['navclass'];
    $query = "SELECT * FROM navclass WHERE id='$navid'";
    $resul = mysql_query($query) or die('SQL语句有误:'.mysql_error());
    $navs = mysql_fetch_array($resul);
    
    //浏览计数
    $query = "UPDATE content SET hit = hit+1 WHERE id=$id";
    @mysql_query($query) or die('修改错误:'.mysql_error());
    ?>
    <?php
    $query=mysql_query("select * FROM interaction WHERE (cid='$id' AND type=1 and xs=1)");
    $pinglunzs = mysql_num_rows($query)
    ?>

    第8行get传入id参数,仅仅使用addslashes函数进行过滤。第9行,第19行,直接带入id进行查询,典型的报错注入。

    $id=addslashes($_GET['cid']);
    $query = "SELECT * FROM content WHERE id='$id'";
    $query = "UPDATE content SET hit = hit+1 WHERE id=$id";

    使用updatexml语句进行测试。

    http://192.168.2.114/xscms/index.php?r=content&cid=1 and updatexml(1,concat(0x7e,(select @@version),0x7e),1)

    继续跟进content.php,第154行,调用了submit.php对应前台的评论提交功能处。

    <form  name="form" method="post" action="/?r=submit&type=comment&cid=<?php echo $id?>">

    跟进submit.php,第6行,第66行

    $mail=$_POST['mail'];
    $query = "SELECT * FROM interaction WHERE( mail = '$mail')";

    直接通过POST方式传入mail参数,未经任何处理直接拼接SQL查询语句

    第175行

    if ($type==1){
    $query = "SELECT * FROM content WHERE( id= $cid)";
    $result = mysql_query($query) or die('SQL语句有误:'.mysql_error());
    $wz = mysql_fetch_array($result);
    $title=$wz['title'];

    第121行

    $query = "INSERT INTO interaction (type,xs,cid,name,mail,url,touxiang,shebei,ip,content,tz,date) VALUES ('$type','$xs','$cid','$name','$mail','$url','$touxiang','$shebei','$ip','$content','$tz',now())";

    mail处提交

    'and updatexml(1,concat(0x7e,(select concat(0x7e,version(),0x7e)),0x7e),1) ,'$url','$touxiang','$shebei','$ip','$content','$tz','1')#

    此时拼接的SQL语句

    "INSERT INTO interaction (type,xs,cid,name,mail,url,touxiang,shebei,ip,content,tz,date) VALUES ('$type','$xs','$cid','$name','' and updatexml(1,concat(0x7e,(select concat(0x7e,version(),0x7e)),0x7e),1) ,'$url','$touxiang','$shebei','$ip','$content','$tz','1')#','$url','$touxiang','$shebei','$ip','$content','$tz',now())";

    修复:使用mysqli_real_escape_string()函数对传入的参数进行过滤。

    二、定向代码审计

    以admin管理员相关功能为方向进行审计

    首先定位到admin目录下的index.php,判断r是否传参,先默认跟进到admin/files/index.php文件

    <?php
    require '../inc/checklogin.php';
    require '../inc/conn.php';
    $indexopen='class="open"';
    ?>

    包含,inc目录下的checklogin.php检查是否登录模块

    跟进checklogin.php

    <?php
    $user=$_COOKIE['user'];
    if ($user==""){
    header("Location: ?r=login");
    exit;    
    }
    ?>

    仅仅只是简单的判断cookie是否有user,且user的值不为空,只要在cookie添加user字段,就很容易越权登录后台。

    修复:

    if(!defined('IN_SYS')) { 
    exit('不好意思,越权已经被我干掉了~'); 
    }   #IN_SYS未定义

    针对后台登录处login.php

    <?php 
    ob_start();
    require '../inc/conn.php';
    $login=$_POST['login'];
    $user=$_POST['user'];
    $password=$_POST['password'];
    $checkbox=$_POST['checkbox'];
    
    if ($login<>""){
    $query = "SELECT * FROM manage WHERE user='$user'";
    $result = mysql_query($query) or die('SQL语句有误:'.mysql_error());
    $users = mysql_fetch_array($result);
    
    if (!mysql_num_rows($result)) {  
    echo "<Script language=JavaScript>alert('抱歉,用户名或者密码错误。');history.back();</Script>";
    exit;
    }else{
    $passwords=$users['password'];
    if(md5($password)<>$passwords){
    echo "<Script language=JavaScript>alert('抱歉,用户名或者密码错误。');history.back();</Script>";
    exit;    
        }
    //写入登录信息并记住30天
    if ($checkbox==1){
    setcookie('user',$user,time()+3600*24*30,'/');
    }else{
    setcookie('user',$user,0,'/');
    }
    echo "<script>this.location='?r=index'</script>";
    exit;
    }
    exit;
    ob_end_flush();
    }
    ?>

    在user和password没有进行过滤直接拼接SQL语句查询

    开启报错

    test' and updatexml(1,concat(0x7e,(select concat(0x7e,version(),0x7e)),0x7e),1) #
    
    1' or updatexml(1,concat((select concat(0x7e,password,0x7e) from manage)),0) #

    未开启报错,使用union联合查询绕过

    ' union select 1,2,3,md5(1),5,6,7,8#

    密码为1

    三、敏感函数回溯

    根据敏感函数,来追踪函数使用传递的过程,逐一溯源进行分析。

    在files/concat.php中的第12行

    $page=addslashes($_GET['page']);
    if ($page<>""){
    if ($page<>1){
    $pages="第".$page."页 - ";
    }
    }
    ?>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title><?php echo $navs['name']?> - <?php echo $pages.$info['name']?></title>

    $page参数只是仅仅进行了特殊字符的转义,然后直接带入一下的html代码中,此处可以构造payloads直接进行反射性xss

    修复使用htmlentities()函数进行修复

    文章评论处的xss后面再补

  • 相关阅读:
    css sprites图片背景优化技术
    CSS3新特性(整理贴)
    span HTML元素
    jQuery1.2选择器(2)
    JavaScript 弹出窗口总结
    jQuery1.2选择器(1)
    jquery如何判断checkbox(复选框)是否被选中
    使用 Lightbox 2 和 JavaScript 构建出色的图片库
    如何在一台电脑同时安装IE6、IE7、FF2、FF3进行网页调试
    IE的有条件注释详解(附实例代码)
  • 原文地址:https://www.cnblogs.com/R1card0/p/12776063.html
Copyright © 2020-2023  润新知