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