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這個參數大部分都是數據庫查詢獲取的值。

找了幾個目錄可控的,繼續來看代碼

\admin\admin_db.php

\admin\admin_index.php

\admin\admin_info.php

\admin\admin_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\n\$table_arr=".var_export($db,true).";\n?>";
		$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的架構,可以省略看路由這步驟,直接定位危險函數/方法,還有的就是鑑權實現。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章