宽字节注入和防御
?
0、前言
最近要為了自動(dòng)化審計(jì)搜集所有PHP漏洞,在整理注入的時(shí)候,發(fā)現(xiàn)寬字節(jié)注入中使用iconv造成的漏洞原理沒有真正搞懂,網(wǎng)上的文章也說得不是很清楚,于是看了榮哥(lxsec)以前發(fā)的一篇http://www.91ri.org/8611.html,加上我們兩個(gè)人的討論,最終有了這一篇深入的研究成果。
?
1、概述
主要是由于使用了寬字節(jié)編碼造成的。,典型情景是網(wǎng)站使用GBK編碼,數(shù)據(jù)庫使用UTF-8編碼
什么是字符集?
計(jì)算機(jī)顯示的字符圖形與保存該字符時(shí)的二進(jìn)制編碼的映射關(guān)系。
如ASCII中,A(圖形)對(duì)應(yīng)編碼01000001(65)。
對(duì)于MYSQL數(shù)據(jù)庫來說,涉及字符集的地方大致分為存儲(chǔ)和傳輸時(shí),即:
(1)存儲(chǔ)在服務(wù)器端的數(shù)據(jù)是何種編碼
(2)客戶端和服務(wù)器交互的時(shí)候數(shù)據(jù)傳輸使用的編碼。
?
2、MYSQL服務(wù)器端存儲(chǔ)字符集
在MYSQL服務(wù)器端進(jìn)行數(shù)據(jù)存儲(chǔ)時(shí),允許在以下的級(jí)別設(shè)置字符集:
(1)服務(wù)器端字符集(character_set_server)
(2)庫字符集
(3)表字符集
(4)字段字符集
優(yōu)先級(jí)為:字段----->表------->庫-------->服務(wù)器
對(duì)應(yīng)的語法是:
Create table test( name varchar(20) charset gbk, number varchar(10), age int )engine=innodb charset=utf-8 ;?
?
3、客戶端與服務(wù)器交互數(shù)據(jù)傳輸?shù)淖址?/p>
存儲(chǔ)時(shí)的字符集已經(jīng)確定了,不會(huì)影響交互階段的字符集。
在MYSQL中,還有一個(gè)中間層的結(jié)構(gòu),負(fù)責(zé)客戶端和服務(wù)器之間的連接,所以稱為連接層。
交互的過程如下:
(1)客戶端以某種字符集生成的SQL語句發(fā)送至服務(wù)器端,這個(gè)“某種字符集”其實(shí)是任意規(guī)定的,PHP作為客戶端連接MYSQL時(shí),這個(gè)字符集就是PHP文件默認(rèn)的編碼。
(2)服務(wù)器會(huì)將這個(gè)SQL語句轉(zhuǎn)為連接層的字符集。問題在于MYSQL是怎么知道我們傳過來的這個(gè)SQL語句是什么編碼呢?這時(shí)主要依靠兩個(gè)MYSQL的內(nèi)部變量來表示,一個(gè)是character_set_client(客戶端的字符集)和character_set_connection(連接層的字符集)??梢允褂胹how?variables?like?‘character_set_%’?;進(jìn)行查看。
可以看到,這里的客戶端字符集為GBK,連接層字符集也是為GBK。
兩者相同,就不會(huì)有問題,如果不一致,就會(huì)出現(xiàn)亂碼問題了。
使用MYSQL中的set命令可以對(duì)這些內(nèi)部變量做設(shè)置,如修改客戶端編碼為UTF-8;
set?character_set_client?=?UTF-8
(1)服務(wù)器將轉(zhuǎn)換好的SQL語句,轉(zhuǎn)為服務(wù)器內(nèi)部編碼與存儲(chǔ)在服務(wù)器上的數(shù)據(jù)進(jìn)行交互
(2)服務(wù)器處理完之后,將結(jié)果返回給客戶端,還是轉(zhuǎn)為服務(wù)器認(rèn)為客戶端可以認(rèn)識(shí)的編碼,如上圖的GBK,使用character_set_results來確定返回客戶端的編碼。
平時(shí)在PHP中寫的set?names?UTF-8相當(dāng)于下面三條同時(shí)執(zhí)行:
(1)set?character_set_client?=?UTF-8
(2)set?character_set_connection?=?UTF-8
(3)set?character_set_results?=?UTF-8
?
4、亂碼問題原理
設(shè)置三個(gè)字符集相同,這也就不會(huì)出現(xiàn)亂碼的真正原理。網(wǎng)頁上有時(shí)會(huì)出現(xiàn)亂碼是因?yàn)镻HP動(dòng)態(tài)文件將數(shù)據(jù)打印到瀏覽器的時(shí)候,瀏覽器也會(huì)按照一定的字符集進(jìn)行判斷,如果PHP的響應(yīng)數(shù)據(jù)編碼和瀏覽器編碼一致,就不會(huì)出現(xiàn)亂碼,否則就出現(xiàn)亂碼??梢酝ㄟ^在PHP中使用header()來指定這個(gè)響應(yīng)數(shù)據(jù)的編碼。
?
5、寬字節(jié)注入原理
有三種形式:
(1)情景一:在PHP中使用mysql_query(“set?names?GBK”);指定三個(gè)字符集(客戶端、連接層、結(jié)果集)都是GBK編碼。
情景代碼:?
?
mysql_query(“set names GBK”); $bar = addslashes($_GET[‘bar’]) ; $sql = “select password from user where bar=’{$bar}’”; $res = mysql_query($sql) ;?
?
提交:http://127.0.0.1/foo.php?bar=admin%df%27
這時(shí),發(fā)生如下轉(zhuǎn)換:
%df%27=====(addslashes)======>%df%5c%27======(GBK)======>運(yùn)’
帶入sql為:
Select?password?from?user?where?bar=‘運(yùn)’
成功將單引號(hào)閉合。為了避免漏洞,網(wǎng)站一般會(huì)設(shè)置UTF-8編碼,然后進(jìn)行轉(zhuǎn)義過濾。但是由于一些不經(jīng)意的字符集轉(zhuǎn)換,又會(huì)導(dǎo)致漏洞。
?
(2)情景二:
使用set?names?UTF-8指定了UTF-8字符集,并且也使用轉(zhuǎn)義函數(shù)進(jìn)行轉(zhuǎn)義。有時(shí)候,為了避免亂碼,會(huì)將一些用戶提交的GBK字符使用iconv函數(shù)(或者mb_convert_encoding)先轉(zhuǎn)為UTF-8,然后再拼接入SQL語句。
情景代碼:
?
mysql_query(“set names UTF-8”) ; $bar =iconv(“GBK”,”UTF-8”, addslashes($_GET[‘’bar])) ; $sql = “select password from user where bar=’{$bar}’” ; $res = mysql_query($sql) ;?
?
?
我們可以看到,為了使得SQL語句中的字符集保持一致,一般都會(huì)使用iconv等字符集轉(zhuǎn)換函數(shù)進(jìn)行字符集轉(zhuǎn)換,問題就是出在了GBK向UTF-8轉(zhuǎn)換的過程中。
提交:http://127.0.0.1/foo.php?bar=%e5%5c%27
變換過程:(e55c轉(zhuǎn)為UTF-8為e98ca6)
e55c27====(addslashes)====>e55c5c5c27====(iconv)====>e98ca65c5c27
可以看到,多出了一個(gè)5c,將轉(zhuǎn)義符(反斜杠)本身轉(zhuǎn)義,使得后面的%27發(fā)揮了作用。
測試如下:
?
(3)情景三:使用iconv進(jìn)行字符集轉(zhuǎn)換,將UTF-8轉(zhuǎn)為GBK,同時(shí),set?names字符集為GBK。提交%e9%8c%a6即可。
這個(gè)情景的大前提是先編碼后轉(zhuǎn)義:
e98ca6====(iconv)=====>e55c=====(addslashes)====>e55c5c
同樣可以多出一個(gè)反斜杠進(jìn)行利用,在此不再詳述,因?yàn)槁┒礂l件比較苛刻。
?
?
6、安全方案
對(duì)于寬字節(jié)編碼,有一種最好的修補(bǔ)就是:
(1)使用mysql_set_charset(GBK)指定字符集
(2)使用mysql_real_escape_string進(jìn)行轉(zhuǎn)義
原理是,mysql_real_escape_string與addslashes的不同之處在于其會(huì)考慮當(dāng)前設(shè)置的字符集,不會(huì)出現(xiàn)前面e5和5c拼接為一個(gè)寬字節(jié)的問題,但是這個(gè)“當(dāng)前字符集”如何確定呢?
就是使用mysql_set_charset進(jìn)行指定。
上述的兩個(gè)條件是“與”運(yùn)算的關(guān)系,少一條都不行。
測試;
輸出:
?
?
轉(zhuǎn)自http://write.blog.csdn.net/postedit/42874517
?
轉(zhuǎn)載于:https://www.cnblogs.com/drkang/p/8644435.html
總結(jié)
- 上一篇: html图形渐变颜色一半一半,CSS3教
- 下一篇: 2.1 随从图标的创建———自制卡牌游戏