多字節(jié)編碼由來
我們先來看看最常用的,最小字符集是ascii,對(duì)應(yīng)的二級(jí)制可以表示為:00-7F 編碼 。它也是我們計(jì)算機(jī)使用最早通用的字符集。前期幾乎可以表示所有英文字符。后來,更多使用計(jì)算機(jī)國(guó)家加入后,我們就想在計(jì)算機(jī)中表示中文字符。我們知道常見中文就有7000多個(gè)字符。ascii碼就只有128字符,只有0-127編碼位置,遠(yuǎn)遠(yuǎn)不夠用了。因此,我們就開始制作更大字符集,并且保證兼容ascii編碼。要支持更多字符,選擇更大字符集。我們只能用多個(gè)字節(jié)來描述一個(gè)字符了。為了很好的與ascii碼,區(qū)分開來!一般做法是:每個(gè)字節(jié)值都大于>7F,如果是2個(gè)字節(jié),那么就是:[>7F][>7F]。這樣編碼,保證很好的與ascii區(qū)分開,并且擴(kuò)大了字符集。像gb2312范圍在[0xA1-0xF7][0xA1-0xFE](中間很多沒有填滿),它完全保證所有字節(jié)在A0之上,也就完全滿足在7F之上了。
GBK編碼漏洞緣由
通過上面的分析,我們知道gb2312編碼是很好的跟ascii碼分開了。 那么我們看看,GBK編碼呢,它是完全兼容gb2312(就是說在gb2312字符集中每個(gè)字符位置,與gbk字符集里面位置完全一致,而且包含于gb2312),但是,它有2萬多個(gè)字符。從上面看,只能選擇往下排序了。 就是從A1A0往下排了,我們發(fā)現(xiàn)它編碼實(shí)際范圍是:[0x81-0xFE]([0x40-0x7E|0x80-0xFE] ) (GBK編碼),我們發(fā)現(xiàn)由2個(gè)字節(jié)組成,首字節(jié)范圍在7F之上,而第2個(gè)字節(jié),有一部分在0x40-0x7E了。這就是導(dǎo)致bug原因。我們看看下面例子吧!
從ASCII碼表中,我們知道0x40-0x7E 包含字符有:“
選擇gbk編碼,運(yùn)行上面代碼,就一條簡(jiǎn)單的命令導(dǎo)致出現(xiàn)錯(cuò)誤,說字符串 賦值 沒有結(jié)束! 呵呵,估計(jì)很多人看到這個(gè)就會(huì)認(rèn)為是php 出Bug了。但是,如果我們變成$a=”誠(chéng)a”,發(fā)現(xiàn)可以正常運(yùn)行了。是不是覺得很奇葩啦!!
原因分析:我們知道文件存在磁盤都是二級(jí)制方式,無論你存什么字符,最終都是以該字符的在所選字符集中字符編碼保存。php解析時(shí)候,最小分析單元是字節(jié)。無論你是多字節(jié)還是單字節(jié)字符。最終都是按照字節(jié)來處理的?!罢\(chéng)” GBK編碼是 D55C,php按字節(jié)來解釋,5C對(duì)應(yīng)字符是“\” 字符。后面直接跟個(gè)‘”',相當(dāng)于被轉(zhuǎn)義了。 因?yàn)闆]有閉合,因此出現(xiàn)錯(cuò)誤!。大家看出問題所在了吧,按自己處理的話,會(huì)自然把多字節(jié)拆成單字節(jié)了。這樣就會(huì)出現(xiàn)很多奇怪問題了。
總結(jié):通過上面講解,我們知道了多字節(jié)編碼過程,以及GBK導(dǎo)致簡(jiǎn)單程序出錯(cuò)的原因。其實(shí),我們很多程序語言里面,都會(huì)以單個(gè)字節(jié)來解析的。這樣,當(dāng)你選擇多字節(jié)GBK編碼中文時(shí),剛好有字節(jié)落在特殊位置,將會(huì)出現(xiàn)奇怪錯(cuò)誤問題。而且,還將給系統(tǒng)帶來本身的漏洞,后面我再說說,GBK編碼缺陷,導(dǎo)致漏洞、以及專門利用該編碼漏洞缺陷進(jìn)行系統(tǒng)入侵!好了,先到這里了,歡迎交流!
GBK字符編碼(字符集)缺陷攻擊(注入)原理
上一節(jié),我們分析了。選擇不同編碼可能會(huì)導(dǎo)致程序帶來本身潛在的漏洞。這次我們以GBK編碼為例,看看怎么樣通過該編碼注入到系統(tǒng)中。目前很多開源系統(tǒng)都存在類似的注入問題。我們先來,從一個(gè)Demo開始!
GBK字符集漏洞注入原理
?php
$u=isset($_GET['u'])? $_GET['u']:'';
$u=addslashes($u);
$sql = "select * from user where user='$u'";
以上是我們寫的一個(gè)測(cè)試?yán)樱℅BK編碼),現(xiàn)在很多開源系統(tǒng),比較少的進(jìn)行統(tǒng)一參數(shù)過濾,有時(shí)候?yàn)榱朔乐棺⑷?,就直接?duì)參數(shù)進(jìn)行轉(zhuǎn)義處理。我們看看,這樣一個(gè)例子,我們?cè)趺礃幼⑷脒M(jìn)系統(tǒng)!
步驟 |
備注 |
1.傳入值%D5%27 or 1=1# |
u參數(shù)參入上面值 (%27 對(duì)應(yīng)是“'” 單引號(hào)字符) |
2.GET獲取的值 |
0xD50x27 or 1=1# |
3.Addslashes后值 |
0xD50x5C0x27 or 1=1 (意思是:誠(chéng)' or 1=1#') #字符后面被注釋掉 |
4.sql值 將變成 |
select * from user where user='誠(chéng)' or 1=1#' |
#號(hào)是sql注釋符號(hào),后面字符將截取掉 |
GPC轉(zhuǎn)義打開,或者是通過addslashes函數(shù),會(huì)自動(dòng)在字符是單引號(hào)(‘)、雙引號(hào)(")、反斜線(\)與 NUL(NULL 字符)等字符前面增加“\”字符(0x5c),例子里面,我們采用一個(gè)特殊前面字節(jié)0xD5,它將與該字節(jié)組合變成:0xD50x5c ,剛好是gbk字符集中字符:”誠(chéng)“ 了。 后面的0×27這個(gè)單引號(hào)被保留下來了!
GBK字符集漏洞注入總結(jié)
呵呵,這個(gè)很有意思吧,好了。我們來總結(jié)下,這類注入是2個(gè)條件的。第一是:gbk編碼,第二是:程序采用了轉(zhuǎn)義方法,轉(zhuǎn)義了輸入。 這2個(gè)條件不苛刻,目前大部分開源系統(tǒng)都有g(shù)bk,utf-8編碼的源碼,剩下的就去看看,源碼里面有沒有用類似轉(zhuǎn)義方法,過濾字符串了。如果有,那么這個(gè)系統(tǒng)某個(gè)功能,你可以去滲透下了。這個(gè)編碼漏洞,網(wǎng)上面提的很多,不過很多時(shí)候,沒有引起開發(fā)人員的足夠重視,還是在不斷的重現(xiàn)!
那么我們?nèi)绻⑷胍粋€(gè)參數(shù),我們?cè)撨x擇什么樣的入?yún)?shù)呢?其實(shí)這種轉(zhuǎn)義字符是單引號(hào)(‘)、雙引號(hào)(")、反斜線(\)與 NUL(NULL 字符),我們這些字符往往在程序中有特殊作用,我們只需要在前面加一個(gè)在>7F字符,后面接一個(gè)%27(‘)、%22(")、%5C(\)、%00(NULL 字符),就可以自己讓這4個(gè)字符,可以逃脫轉(zhuǎn)義了。
好了,這個(gè)漏洞原理及注入過程分析就這些了。我們開發(fā)時(shí)候,需要注意這個(gè)問題,特別是使用GBK編碼開發(fā)程序,要有這個(gè)方面的預(yù)備知識(shí),對(duì)于自己開發(fā)安全的代碼會(huì)有幫助的。更多的GBK編碼,可以看http://doc.chacuo.net/gbk ?。ㄟ@里有很多落在5c中文字符呢)也歡迎討論!