宽字节注入原理分析
什么是寬字節?
如果一個字符的大小是一個字節的,稱為窄字節;如果一個字符的大小是兩個字節的,成為寬字節
- 像GB2312、GBK、GB18030、BIG5、Shift_JIS等這些編碼都是常說的寬字節,也就是只有兩字節
- 英文默認占一個字節,中文占兩個字節
什么是寬字節注入?
原理:寬字節注入發生的位置就是PHP發送請求到MYSQL時字符集使用character_set_client設置值進行了一次編碼。在使用PHP連接MySQL的時候,當設置“character_set_client = gbk”時會導致一個編碼轉換的問題,也就是我們熟悉的寬字節注入
寬字節注入是利用mysql的一個特性,mysql在使用GBK編碼(GBK就是常說的寬字節之一,實際上只有兩字節)的時候,會認為兩個字符是一個漢字(前一個ascii碼要大于128,才到漢字的范圍)
GBK首字節對應0×81-0xFE,尾字節對應0×40-0xFE(除0×7F),例如%df和%5C會結合;GB2312是被GBK兼容的,它的高位范圍是0xA1-0xF7,低位范圍是0xA1-0xFE(0x5C不在該范圍內),因此不能使用編碼吃掉%5c
常見轉義函數與配置:addslashes、mysql_real_escape_string、mysql_escape_string、php.ini中magic_quote_gpc的配置
Mysql相關知識
Mysql中有個連接層,何為連接層?
在MYSQL中,有一個中間層的結構,負責客戶端和服務器之間的連接,稱為連接層
交互的過程如下:
(1)客戶端(這里指php)以某種字符集生成的SQL語句發送至服務器端(這里指Mysql),這個“某種字符集”其實是任意規定的,PHP作為客戶端連接MYSQL時,這個字符集就是PHP文件默認的編碼。
(2)服務器(Mysql)會將這個SQL語句轉為連接層的字符集。問題在于MYSQL是怎么知道我們傳過來的這個SQL語句是什么編碼呢?這時主要依靠兩個MYSQL的內部變量來表示,一個是character_set_client(客戶端的字符集)和character_set_connection(連接層的字符集)。
(3)總的來說,就是php把sql語句傳給mysql時,要轉換character_set_connection字符集的編碼,執行流程就是:將php的sql語句以character_set_client編碼(也就是轉為16進制數),再將16進制數以character_set_connection進行編碼(也就是轉換為url編碼),然后以內部操作字符集進行url解碼,最后以character_set_results編碼輸出結果
內部操作字符集怎么確定?進行內部操作前將請求數據從character_set_connection轉換為內部操作字符集,其確定方法如下:
? 使用每個數據字段的CHARACTER SET設定值;
? 若上述值不存在,則使用對應數據表的DEFAULT CHARACTER SET設定值(MySQL擴展,非SQL標準);
? 若上述值不存在,則使用對應數據庫的DEFAULT CHARACTER SET設定值;
? 若上述值不存在,則使用character_set_server設定值。
可以理解的同時參考下面這幅圖片
注:
- 查看Mysql字符集
show variables like '%char%';
- 修改字符集
set names 'gbk';相當于下面的三句命令
mysql> set character_set_client = gbk;
mysql> set character_set_results = gbk;
mysql> set character_set_connection = gbk;
實例
以sqli-labs的第32關為例
(1)輸入’,被\轉義
(2)輸入%df
(3)分析執行過程
① id=%df%27,瀏覽器執行時會自動url解碼一次,斷點你就會發現
注:其實那個亂碼的是希臘字母β
② 此時KaTeX parse error: Can't use function '\'' in math mode at position 39: …rs WHERE id='1�\?'?' LIMIT 0,1"`,接…sql轉為16進制
(2)將16進制數轉為url編碼
(3)這里以GBK(內部操作字符集)進行url解碼,執行sql語句
(4)以character_set_results編碼輸出結果
關鍵參數簡單示意圖:
%df%27 瀏覽器url自動解碼===> β\' 轉為16進制===> 0xdf0x5c0x27 轉換為url編碼===> %df%5c%27 進行url解碼(因為是GBK編碼,%df和%5c結合為漢字)===> 運'
注:%后面跟16進制數,就表示url編碼
注:在以GBK為編碼的mysql中
%df和%5c才可以結合為漢字,%df和\是無法結合的
例1:可結合
注:#注釋后面的' LIMIT 0,1
例2:不可結合
\將'轉義,使其失去了原本單引號的意義,只是一個沒有靈魂的肉體(不能和左邊的單引號閉合),因此id后面的第一個單引號就和最后一個單引號閉合了,也使得#注釋符也失去了作用,因為''里的內容被視為了字符串。
參考
https://blog.csdn.net/u011721501/article/details/42874517
https://blog.csdn.net/william_munch/article/details/100037244
https://www.lstazl.com/666-2/
注:
URL編碼的解碼(GBK)
查看字符編碼(簡體中文)-----GBK內碼查詢
總結
- 上一篇: 喜马拉雅app怎么查访客(如何评价APP
- 下一篇: CVE-2018-15473(OpenS