在使用PHP連接MySQL的時候,當設置"set character_set_client=gbk"的時候 會導致一個編碼轉(zhuǎn)換的注入問題,也就是寬字符注入。我們先搭建一個環(huán)境:

建立的有test數(shù)據(jù)庫,user表,id列,username列和password列,里面存的有相應的數(shù)據(jù)。? ? ? ? ? ? ? 首先我們先加一個單引號試試

可以看到?jīng)]有報錯,說明不能執(zhí)行sql注入。為什么會這樣呢?查看代碼可以看到? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?$id=addslashes($_GET['id']);此函數(shù)的作用就是讓'變成\',讓單引號不再是單引號,因此就沒法執(zhí)行sql注入了。寬字節(jié)注入是利用MySQL的一個特性,mysql在使用GBK編碼的時候,會認為兩個字符是一個漢字(前一個ascii碼要大于128,才到漢字的范圍)。如果我們輸入%df%27看會怎樣:

我們可以看到,已經(jīng)報錯了。我們看到報錯,說明sql語句出錯,看到出錯說明可以注入了。
這是因為id的參數(shù)傳入代碼層,就會在’前加一個\,由于采用的URL編碼,所以產(chǎn)生的效果是:%df%5c%27,關鍵就在這里,在GBK編碼中,兩個字符表示一個數(shù)字,所以%df把%5c吃掉形成了一個漢字,后面就剩一個單引號,所以此時的單引號并沒有被轉(zhuǎn)義可以發(fā)揮效果。

很明顯sql注入成功了。
注意:寬字符注入利用的是多字節(jié)編碼,而多字節(jié)編碼并不止GBK一種,比如還有GB2312,而用GB2312就不會有 寬字符注入,這是因為gb2312編碼的取值范圍。它的高位范圍是0xA1~0xF7,低位范圍是0xA1~0xFE,而\是0x5c,是不在低位范圍中的。所以,0x5c根本不是gb2312中的編碼,所以自然也是不會被吃掉的。而GBK首字節(jié)對應0x81-0xFE,尾字節(jié)對應0x40-0xFE(除0x7F),剛好涵蓋了對應的編碼0x5C,所以有寬字符注入。因此可以推廣到所有多字節(jié)編碼,只要低位覆蓋0x5c就可以進行寬字符注入。