BlueCMS_V1.6:審計過程與漏洞分析
菜鳥入坑代碼審計,聽說BlueCMS比較合適初學者,特此學習,大佬勿噴
漏洞環境&搭建
本地環境搭建,使用phpstudy集成系統,CMS版本為BlueCMS_v1.6
訪問install目錄

下一步,查看數據庫文件有沒有生成

數據庫有數據表顯示,安裝成功!
漏洞分析
丟進seay里面(新建項目->選擇bluecms安裝目錄->自動審計->開始)
1.數字型SQL注入
產生此漏洞的文件為ad_js.php

seay顯示19行的$ad_id變量存在sql注入,而變量$ad_id是從$_GET['ad_id']中來的,且只經過了trim。
trim():函數移除字符串兩側的空白字符或其他預定義字符。
而在ad_js.php文件的開頭(第10行)引入了過濾文件require_once dirname(__FILE__) . '/include/common.inc.php';
查看common.inc.php文件, 發現對$_POST,$_GET,$_COOKIE,$_REQUEST傳遞的參數都進行了過濾

跟蹤看看deep_addslashes是怎么實現的
function deep_addslashes($str)
{
if(is_array($str))
{
foreach($str as $key=>$val)
{
$str[$key] = deep_addslashes($val);
}
}
else
{
$str = addslashes($str);//
}
return $str;
}
使用addslashes過濾
$ad = $db->getone("SELECT * FROM ".table('ad')." WHERE ad_id =".$ad_id);
可以看出上面的是個數字型注入,getone函數我們也追蹤一下,代碼在mysql.class.php中
function getone($sql, $type=MYSQL_ASSOC){
$query = $this->query($sql,$this->linkid);
$row = mysql_fetch_array($query, $type);
return $row;
}
是一個執行sql語句的函數,這里就確認存在數字型sql注入漏洞
漏洞復現:因為我們這里是白盒測試,所以直接提取一下管理的用戶名和密碼
http://www.bluecms16.com/ad_js.php?ad_id=1 UNION SELECT 1,2,3,4,5,6,GROUP_CONCAT(admin_name,0x3a,pwd) FROM blue_admin


38行輸出的時候注釋掉了,因此我們需要查看源代碼
2. INSERT型SQL注入

// include/common.fun.php 文件108行
function getip()
{
if (getenv('HTTP_CLIENT_IP'))
{
$ip = getenv('HTTP_CLIENT_IP');
}
elseif (getenv('HTTP_X_FORWARDED_FOR'))
{
$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;
}
由于第一分析中common.inc.php文件只對$_POST,$_GET,$_COOKIE,$_REQUEST進行了處理,但是遺漏了$_SERVER,而getip()函數中恰好是通過該變量獲取ip地址。我們可以通過client-ip或x-forwarded-for進行ip的偽造,觸發漏洞。
phpstorm使用ctrl+shift+F搜索一下,看哪里調用了getip(), 如下圖,我們跟進comment.php文件114行

$sql = "INSERT INTO ".table('comment')." (com_id, post_id, user_id, type, mood, content, pub_date, ip, is_check) VALUES ('', '$id', '$user_id', '$type', '$mood', '$content', '$timestamp', '".getip()."', '$is_check')";
$db->query($sql);
這里我們也分析一下其他變量插入會不會產生漏洞
$id = !empty($_REQUEST['id']) ? intval($_REQUEST['id']) : '';
// intval函數進行了轉義
$user_id = $_SESSION['user_id'] ? $_SESSION['user_id'] : 0; //session 略
$mood = intval($_POST['mood']);
// intval函數進行了轉義
$content = !empty($_POST['comment']) ? htmlspecialchars($_POST['comment']) : '';
// 對comment內容做了html轉義,所以不存在xss
看來我們還是只能利用getip()來觸發漏洞
漏洞復現:
這里是對評論區進行的sql注入,因此我們需要新建一篇文章,然后在評論區測試(白盒測試,為了方便理解,我將sql語句輸出了)

poc 構造思路如下:
插入兩條數據的思路,進行構造(注入返回結果要顯示在留言內容處)



3. 另一處INSERT型注入
在文件guest_book.php77行處
$sql = "INSERT INTO " . table('guest_book') . " (id, rid, user_id, add_time, ip, content) VALUES ('', '$rid', '$user_id', '$timestamp', '$online_ip', '$content')";
$db->query($sql);
這里有個$online_ip, 我們跟蹤一下

// include/common.fun.php文件106行處
function getip()
{
if (getenv('HTTP_CLIENT_IP'))
{
$ip = getenv('HTTP_CLIENT_IP');
}
elseif (getenv('HTTP_X_FORWARDED_FOR'))
{
$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;
}
原理跟上面的sql注入一樣,我們需要構造http頭,加個X-FORWARDED-FOR

4.本地文件包含

漏洞發生在user.php文件750行處

$_POST['pay']并沒有做多余的安全檢測,而是直接進行拼接,但是后面有index.php文件,所以我們的重點是如何截斷。如果php版本低于5.3.4且magic_quotes_gpc=off則可以使用%00截斷。還可以使用系統文件路徑長度限制來進行截斷。
這里我們使用系統文件路徑長度的限制來截斷:
Windows 259個字節

當然了,由于文件包含漏洞可以包含圖片文件(例如jpg),而且服務器會解析圖片文件(當作php文件執行),那么我們就可以上傳一個帶木馬的jpg文件,然后利用文件包含漏洞包含此jpg文件。執行惡意代碼。
具體利用步驟如下:
在個人資料編輯,上傳頭像處傳jpg文件-> 使用包含漏洞包含此文件

5. 任意文件刪除

漏洞發生在publish.php文件309行處
elseif($act == 'del_pic')
{
$id = $_REQUEST['id'];
$db->query("DELETE FROM ".table('post_pic')." WHERE pic_path='$id'");
if(file_exists(BLUE_ROOT.$id))
{
@unlink(BLUE_ROOT.$id);
}
}
第7行unlink刪除文件,傳入$id,先刪除數據庫里的,然后判斷本地有沒有此文件,如果有,unlink函數也對其進行刪除
漏洞復現:

- 另一處任意文件刪除
漏洞觸發在文件user.php中788行處

未做任何處理,直接導致任意文件刪除漏洞
漏洞復現:

7.發布文章處XSS
在user.php文件中的266行,有個對文章內容進行過濾
$content = !empty($_POST['content']) ? filter_data($_POST['content']) : '';
跟進一下filter_data函數,看它過濾了什么(include/common.fun.php文件985行)
function filter_data($str)
{
$str = preg_replace("/<(\/?)(script|i?frame|meta|link)(\s*)[^<]*>/", "", $str);
return $str;
}
就過濾了幾個標簽,我們可以用img標簽繞過:<img src=1 onerror=alert(‘Tao’)>
漏洞復現:


- 用戶注冊處xss
在user.php文件中的763行處
//編輯個人資料
elseif($act == 'edit_user_info'){
$user_id = intval($_SESSION['user_id']);
if(empty($user_id)){
return false;
}
$birthday = trim($_POST['birthday']);
$sex = intval($_POST['sex']);
$email = !empty($_POST['email']) ? trim($_POST['email']) : '';
$msn = !empty($_POST['msn']) ? trim($_POST['msn']) : '';
$qq = !empty($_POST['qq']) ? trim($_POST['qq']) : '';
$mobile_phone = !empty($_POST['mobile_phone']) ? trim($_POST['mobile_phone']) : '';
$office_phone = !empty($_POST['office_phone']) ? trim($_POST['office_phone']) : '';
$home_phone = !empty($_POST['home_phone']) ? trim($_POST['home_phone']) : '';
$address = !empty($_POST['address']) ? htmlspecialchars($_POST['address']) : '';
..............
...............
$sql = "UPDATE ".table('user')." SET birthday = '$birthday', sex = '$sex', face_pic = '$face_pic', email = '$email', msn = '$msn', qq = '$qq'," ." mobile_phone = '$mobile_phone', office_phone = '$office_phone', home_phone = '$home_phone', address='$address' WHERE user_id = ".intval($_SESSION['user_id']);
$db->query($sql);
showmsg('更新個人資料成功', 'user.php');
$email只是經過了trim, 其余未作處理,存在xss

觀察表結構,email長度是足夠存儲產生xss代碼的
漏洞復現:


當管理登錄后臺,查看用戶的時候,也會觸發(可拿管理員cookie),且具有隱藏性。這里模擬一下管理員登錄后臺。

- 后臺大量漏洞
漏洞有點多,就先不寫了?
原創: Tao 黑白天實驗室
原文鏈接:https://mp.weixin.qq.com/s/C6SXz61DsKeNiIw...