• PHP审计之BEESCMS审计案例


    PHP审计之BEESCMS审计案例

    审计流程

    任意文件包含

    文件存在即包含该文件,而包含的这个文件名可控,则需要找这个文件创建的地方

    function creat_inc($fl,$str){
    	if(file_exists($fl)){@unlink($fl);}
    	if(!$fp=@fopen($fl,'w')){
    		msg('文件打开失败,请检查是否有足够的权限操作文件');
    	}
    	flock($fp,LOCK_EX);
    	if(!fwrite($fp,$str)){
    		msg('写入文件失败,请检查是否有足够的权限操作文件');
    	}
    	flock($fp,LOCK_UN);
    	unset($fp);
    }
    

    lang是request接受过来的值,可控。

    跟踪到这只要$cate_list可控,那么就是一个妥妥的任意文件包含漏洞。而这里的实际代码是$cate_list =.var_export($rel,true)

    发现这个$rel这个参数大部分都是数据库查询获取的值。

    找了几个目录可控的,继续来看代码

    adminadmin_db.php
    
    adminadmin_index.php
    
    adminadmin_info.php
    
    adminadmin_sq_code.php
    

    admin_db.php文件

    elseif($action=='save_back'){
    	if(!check_purview('data_backup')){msg('<span style="color:red">操作失败,你的权限不足!</span>');}
    	$db = $_POST['db'];
    	$init = isset($_POST['init'])?$_POST['init']:0;
    	$sql_size = 1048;
    	$dir = isset($_GET['dir'])?$_GET['dir']:'';
    	//缓存所有表
    	if($init){
    		if(empty($db)){msg('请选择要备份的表');}
    		$str="<?php
    $table_arr=".var_export($db,true).";
    ?>";
    		$file=DATA_PATH.'cache/db_cache.php';
    		creat_inc($file,$str);
    		//创建备份目录
    		$dir = 'db'.date(YmdHms,time());
    		@mkdir(DATA_PATH.'backup/'.$dir);
    	}
    	@include(DATA_PATH.'cache/db_cache.php');
    

    发现转义单引号,代码中并没有发现有过滤函数,看到包含过来的init.php文件

    if (!get_magic_quotes_gpc())
    {
        if (isset($_REQUEST))
        {
            $_REQUEST  = addsl($_REQUEST);
        }
        $_COOKIE   = addsl($_COOKIE);
    	$_POST = addsl($_POST);
    	$_GET = addsl($_GET);
    }
    

    检测没开启魔术引号,则启用自己的过滤方法进行全局的过滤。

    /*
    *转义函数
    *
    *@param   $value   array || string
    *@return  array || string
    */
    function addsl($value)
    {
        if (empty($value))
        {
            return $value;
        }
        else
        {	
            return is_array($value) ? array_map('addsl', $value) : addslashes($value);
        }
    }
    

    过滤操作

    注入

    login.php

    elseif($action=='ck_login'){
    	global $submit,$user,$password,$_sys,$code;
    	$submit=$_POST['submit'];
    	$user=fl_html(fl_value($_POST['user']));
    	$password=fl_html(fl_value($_POST['password']));
    	$code=$_POST['code'];
        
        
       .....
           check_login($user,$password);
    

    fl_html跟踪查看发现是过滤xss的,也就是实例化html。fl_value方法是一个正则过滤sql的方法。

    function fl_value($str){
       if(empty($str)){return;}
       return preg_replace('/select|insert | update | and | in | on | left | joins | delete |\%|=|/*|*|../|./| union | from | where | group | into |load_file
    |outfile/i','',$str);
    }
    
    unction check_login($user,$password){
    	$rel=$GLOBALS['mysql']->fetch_asc("select id,admin_name,admin_password,admin_purview,is_disable from ".DB_PRE."admin where admin_name='".$user."' limit 0,1");	
    	$rel=empty($rel)?'':$rel[0];
    

    updatexml没被过滤,可以使用updatexml。

    session覆盖

    Extract()该函数使用数组键名作为变量名,使用数组键值作为变量值。但是当变量中有同名的元素时,该函数默认将原有的值给覆盖掉。这就造成了变量覆盖漏洞。

    如果能覆盖(添加)这几个$_SESSION值 就能绕过这个检查

    $_SESSION覆盖有个必须前提,session_start()必须出现在覆盖之前,不然就算覆盖了$_SESSION变量,一旦session_start() 变量就会被初始化掉。没有使用EXTR_SKIP参数导致任意变量覆盖,又由于执行的时候已经session_start()了
    所以可以覆盖(添加)任意$_SESSION值

    if(!is_login()){header('location:login.php');exit;}
    

    查看is_login的方法

    function is_login(){
       if($_SESSION['login_in']==1&&$_SESSION['admin']){
          if(time()-$_SESSION['login_time']>3600){
             login_out();
          }else{
             $_SESSION['login_time']=time();
             @session_regenerate_id();
          }
    

    发现验证了三个值,主要伪造着三个值即可登录。

    if (!get_magic_quotes_gpc())
    {
        if (isset($_REQUEST))
        {
            $_REQUEST  = addsl($_REQUEST);
        }
        $_COOKIE   = addsl($_COOKIE);
    	$_POST = addsl($_POST);
    	$_GET = addsl($_GET);
    }
    if (isset($_REQUEST)){$_REQUEST  = fl_value($_REQUEST);}
        $_COOKIE   = fl_value($_COOKIE);
    	$_GET = fl_value($_GET);
    @extract($_POST);
    @extract($_GET);
    @extract($_COOKIE);
    

    而在这里,init.php代码中,使用Extract方法未使用EXTR_SKIP参数,并且未过滤_session字符,导致可以同名变量覆盖。

    _SESSION[login_in]=1&_SESSION[admin]=1&_SESSION[login_time]=99999999999
    

    结尾

    类似这种非MVC的架构,可以省略看路由这步骤,直接定位危险函数/方法,还有的就是鉴权实现。

  • 相关阅读:
    Git_学习_01_ 常用 Git 命令清单
    Git_错误_03_ Git提交时显示用户 unknown
    Java微信小程序开发_00_资源帖
    Git_错误_02_error: src refspec master does not match any
    Java企业微信开发_08_素材管理之下载微信临时素材到本地服务器
    Java企业微信开发_07_JSSDK多图上传
    Java企业微信开发_07_总结一下企业微信的配置
    Java_数据交换_dom4j_01_解析xml
    Git_学习_00_资源帖
    小结:线段树 & 主席树 & 树状数组
  • 原文地址:https://www.cnblogs.com/nice0e3/p/15244611.html
Copyright © 2020-2023  润新知