sqli-寬字節注入


0x0 背景

  1. 當某字符的大小為一個字節時,稱其字符為窄字節.
  2. 當某字符的大小為兩個字節時,稱其字符為寬字節.
  3. 所有英文默認占一個字節,漢字占兩個字節
  4. 常見的寬字節編碼:GB2312,GBK,GB18030,BIG5,Shift_JIS等等

0x1 寬字節注入原理

 

 

程序員為了防止sql注入,對用戶輸入中的單引號(’)進行處理,在單引號前加上斜杠(\)進行轉義,這樣被處理后的sql語句中,單引號不再具有‘作用’,僅僅是‘內容’而已,換句話說,這個單引號無法發揮和前后單引號閉合的作用,僅僅成為‘內容‘

【再舉個例子,要找某位名字里帶單引號的用戶,搜索的時候,就要讓單引號成為內容去搜索,而不能起到其他作用】

 

而安全測試人員要繞過這個轉義處理,使單引號發揮作用,有兩個思路:

  1. 讓斜杠(\)失去作用
  2. 讓斜杠(\)消失

 

第一個思路就是借鑒程序員的防范思路,對斜杠(\)轉義,使其失去轉義單引號的作用,成為‘內容’

第二個思路就是寬字節注入

 

 

 

當使用寬字節編碼,如:GBK時,兩個連在一起的字符會被認為是漢字,我們可以在單引號前加一個字符,使其和斜杠(\)組合被認為成漢字,從未達到讓斜杠消失的目的,進而使單引號發揮作用

注意:前一個字符的Ascii要大於128,兩個字符才能組合成漢字

 

0x2 注入方法

0x21 黑盒

 

 

可以看到,在發現單引號被轉義后,當我們加了%df后,sql語句報錯,說明單引號發揮了作用,斜杠與%df組合

 

 

0x22白盒

 

 

1.gbk編碼

 

 

2.單引號被替換成\’

 

 

 

3.php內置函數addslashes進行轉義(lesson33)

 

4.mysql_real_escape_string

這個mysql內置的函數可以把sql語句中字符串的特殊字符進行轉義,同時考慮連接的字符集,可以用來解決寬字節注入,但某些場景仍不行,因為程序沒有指定php連接mysql的字符集。

如果要使用這個函數防御,要在執行sql語句之前調用一下mysql_set_charset函數,設置當前連接的字符集為gbk,再調用mysql_real_escape_string來過濾用戶輸入

0x23 sqlmap

需要注意的是,對於寬字節注入場景,直接

python sqlmap.py -u "http://localhost/sqli-labs-master/Less-32/?id=1"

是找不到注入的

 

 

必須得

python sqlmap.py -u "http://localhost/sqli-labs-master/Less-32/?id=1%df%27"

還可以加些參數:

--threads 10 //如果你玩過 msfconsole的話會對這個很熟悉 sqlmap線程最高設置為10

--level 3 //sqlmap默認測試所有的GET和POST參數,當--level的值大於等於2的時候也會測試HTTP Cookie頭的值,當大於等於3的時候也會測試User-Agent和HTTP Referer頭的值。最高可到5

--risk 3 // 執行測試的風險(0-3,默認為1)risk越高,越危險

----search //后面跟參數 -D -T -C 搜索列(S),表(S)和或數據庫名稱(S) 如果你腦子夠聰明,應該知道庫列表名中可能會有ctf,flag等字樣,結果有時候題目就是這么耿直對吧?

 

 

//我最后還是沒成功用sqlmap注入

0x3防御

 

借鑒內容:https://www.leavesongs.com/PENETRATION/mutibyte-sql-inject.html

 

在0x22.3中我們說到了一種修復方法,就是先調用mysql_set_charset函數設置連接所使用的字符集為gbk,再調用mysql_real_escape_string來過濾用戶輸入。

 

這個方式是可行的,但有部分老的cms,在多處使用addslashes來過濾字符串,我們不可能去一個一個把addslashes都修改成mysql_real_escape_string。我們第二個解決方案就是,將character_set_client設置為binary(二進制)。

 

只需在所有sql語句前指定一下連接的形式是二進制:

 

SET character_set_connection=gbk, character_set_results=gbk,character_set_client=binary

這幾個變量是什么意思?

 

當我們的mysql接受到客戶端的數據后,會認為他的編碼是character_set_client,然后會將之將換成character_set_connection的編碼,然后進入具體表和字段后,再轉換成字段對應的編碼。

 

然后,當查詢結果產生后,會從表和字段的編碼,轉換成character_set_results編碼,返回給客戶端。

 

所以,我們將character_set_client設置成binary,就不存在寬字節或多字節的問題了,所有數據以二進制的形式傳遞,就能有效避免寬字符注入。

 

比如,我們的phithon內容管理系統v2.0版本更新如下:

 

 

 

已經不能夠注入了:

 

 

 

在我審計過的代碼中,大部分cms是以這樣的方式來避免寬字符注入的。這個方法可以說是有效的,但如果開發者畫蛇添足地增加一些東西,會讓之前的努力前功盡棄。

 

0x4總結

在逐漸國際化的今天,推行utf-8編碼是大趨勢。如果就安全性來說的話,我也覺得使用utf-8編碼能夠避免很多多字節造成的問題。

不光是gbk,我只是習慣性地把gbk作為一個典型的例子在文中與大家說明。世界上的多字節編碼有很多,特別是韓國、日本及一些非英語國家的cms,都可能存在由字符編碼造成的安全問題,大家應該有擴展性的思維。

總結一下全文中提到的由字符編碼引發的安全問題及其解決方案:

  1. gbk編碼造成的寬字符注入問題,解決方法是設置character_set_client=binary。
  2. 矯正人們對於mysql_real_escape_string的誤解,單獨調用set names gbk和mysql_real_escape_string是無法避免寬字符注入問題的。還得調用mysql_set_charset來設置一下字符集。
  3. 謹慎使用iconv來轉換字符串編碼,很容易出現問題。只要我們把前端html/js/css所有編碼設置成gbk,mysql/php編碼設置成gbk,就不會出現亂碼問題。不用畫蛇添足地去調用iconv轉換編碼,造成不必要的麻煩。

 

 

參考文檔:https://www.leavesongs.com/PENETRATION/mutibyte-sql-inject.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM