1. 程式人生 > >【SQL注入技巧拓展】————3、SQL注入防禦與繞過的幾種姿勢

【SQL注入技巧拓展】————3、SQL注入防禦與繞過的幾種姿勢

本文章主要以後端PHP和MySQL資料庫為例,參考了多篇文章後的集合性文章。

前言

本文章主要以後端PHP和MySQL資料庫為例,參考了多篇文章後的集合性文章,歡迎大家提出個人見解,互促成長。

一、 PHP幾種防禦姿勢

1. 關閉錯誤提示

說明:PHP配置檔案php.ini中的display_errors=Off,這樣就關閉了錯誤提示。

2. 魔術引號

說明:

當php.ini裡的magic_quotes_gpc=On時。提交的變數中所有的單引號(')、雙引號(")、反斜線(\)與 NUL(NULL 字元)會自動轉為含有反斜線的轉義字元。

魔術引號(Magic Quote)是一個自動將進入 PHP 指令碼的資料進行轉義的過程。(對所有的 GET、POST 和 COOKIE 資料自動執行轉義)

PHP 5.4 之前 PHP 指令 magic_quotes_gpc 預設是 on。

本特性已自PHP 5.3.0 起廢棄並將自 PHP 5.4.0 起移除,在PHP 5.4.O 起將始終返回 FALSE。

參考:

《magic_quotes_gpc相關說明》:

http://www.cnblogs.com/qiantuwuliang/archive/2009/11/12/1601974.html

3. addslashes

說明:

addslashes函式,它會在指定的預定義字元前新增反斜槓轉義,這些預定義的字元是:單引號(')、雙引號(")、反斜線(\)與 NUL(NULL 字元)。

這個函式的作用和magic_quotes_gpc一樣。所以一般用addslashes前會檢查是否開了magic_quotes_gpc。

magic_quotes_gpc與addslashes的區別用法:

1)對於magic_quotes_gpc=on的情況

我們可以不對輸入和輸出資料庫的字串資料作addslashes()和stripslashes()的操作,資料也會正常顯示。

如果此時你對輸入的資料作了addslashes()處理,那麼在輸出的時候就必須使用stripslashes()去掉多餘的反斜槓。

2)對於magic_quotes_gpc=off 的情況

必須使用addslashes()對輸入資料進行處理,但並不需要使用stripslashes()格式化輸出,

因為addslashes()並未將反斜槓一起寫入資料庫,只是幫助mysql完成了sql語句的執行。

參考:

《addslashes函式說明》:

https://secure.php.net/manual/zh/function.addslashes.php

《對於magic_quotes_gpc的一點認識》:

http://www.phpfans.net/bbs/viewthread.php?tid=6860&page=1&extra=page=1

4. mysql_real_escape_string

說明:

mysql_real_escape_string()函式轉義 SQL 語句中使用的字串中的特殊字元。

下列字元受影響:

\x00  
\n  
\r  
\  
'  
"  
\x1a

如果成功,則該函式返回被轉義的字串。如果失敗,則返回 false。

本擴充套件自 PHP5.5.0 起已廢棄,並在自 PHP 7.0.0 開始被移除。

因為完全性問題,建議使用擁有Prepared Statement機制的PDO和MYSQLi來代替mysql_query,使用的是mysqli_real_escape_string

參考:

《 PHP防SQL注入不要再用addslashes和mysql_real_escape_string了》:

http://blog.csdn.net/hornedreaper1988/article/details/43520257

《PDO防注入原理分析以及使用PDO的注意事項》:

http://zhangxugg-163-com.iteye.com/blog/1835721

5. htmlspecialchars()

說明:

htmlspecialchars()函式把預定義的字元轉換為 HTML實體。

預定義的字元是:

& (和號)成為 &  
" (雙引號)成為 "  
' (單引號)成為 '  
< (小於)成為 &lt;
> (大於)成為 &gt;

6. 用正則匹配替換來過濾指定的字元

preg_match 
preg_match_all() 
preg_replace 

參考:

《preg_match說明》:

http://php.net/manual/zh/function.preg-match.php

《preg_replace說明》:

https://secure.php.net/manual/zh/function.preg-replace.php

7. 轉換資料型別

說明:

根據「檢查資料型別」的原則,查詢之前要將輸入資料轉換為相應型別,如uid都應該經過intval函式格式為int型。

8. 使用預編譯語句

說明:

繫結變數使用預編譯語句是預防SQL注入的最佳方式,因為使用預編譯的SQL語句語義不會發生改變,在SQL語句中,變數用問號?表示,攻擊者無法改變SQL語句的結構,從根本上杜絕了SQL注入攻擊的發生。

程式碼示例:

參考:

《Web安全之SQL注入攻擊技巧與防範》:

http://www.plhwin.com/2014/06/13/web-security-sql/

二、 幾種繞過姿勢

下面列舉幾個防禦與繞過的例子:

例子1:addslashes

防禦:

這裡用了addslashes轉義。

繞過:

  • 將字串轉為16進位制編碼資料或使用char函式(十進位制)進行轉化(因為資料庫會自動把16進位制轉化)
  • 用註釋符去掉輸入密碼部分如“-- /* #”

payload:

http://localhost/injection/user.php?username=admin-- hack

(因為有的SQL要求--後要有空格,所以此處加上了hack)

http://localhost/injection/user.php?username=admin/*

(escape不轉義/*)

http://localhost/injection/user.php?username=admin%23

(這裡的%23即為#,註釋掉後面的密碼部分。注意IE瀏覽器會將#轉換為空)

http://localhost/injection/user.php?username=0x61646d696e23

(admin# -->0x61646d696e23)

http://localhost/injection/user.php?username=CHAR(97,100, 109, 105, 110, 35)

(admin# -->CHAR(97, 100, 109, 105, 110, 35))

關於編碼原理:

因為一般前端JavaScript都會escape()、encodeURL或encodeURIComponent編碼再傳輸給伺服器,主要為encodeURL,如下,所以可以利用這點。

JavaScript程式碼如:

攔截請求:

1)escape( )

對ASCII字母、數字、標點符號"@* _ + - . /"不進行編碼。在\u0000到\u00ff之間的符號被轉成%xx的形式,其餘符號被轉成%uxxxx的形式。(注意escape()不對"+"編碼,而平時表單中的空格會變成+)

2) encodeURL

對" ; / ? : @ & = + $ , # ' "不進行編碼。編碼後,它輸出符號的utf-8形式,並且在每個位元組前加上%。

3) encodeURIComponent

用於對URL的組成部分進行個別編碼,而不用於對整個URL進行編碼。

常用編碼:  

@ * _ + - ./ ; \ ? : @ & = + $ , # ' 空格

轉碼工具可用:

http://evilcos.me/lab/xssor/

參考:

《URL編碼》:

http://www.ruanyifeng.com/blog/2010/02/url_encoding.html

例子2:匹配過濾

防禦:

繞過:

關鍵詞and,or常被用做簡單測試網站是否容易進行注入攻擊。這裡給出簡單的繞過使用&&,||分別替換and,or。

  • 過濾注入: 1 or 1 = 1 1 and 1 = 1
  • 繞過注入: 1 || 1 = 1 1 && 1 = 1

關於preg_match過濾可以看參考文章,文章裡講得很詳細了。

參考:

《高階SQL注入:混淆和繞過》:

http://www.cnblogs.com/croot/p/3450262.html

例子3:strstr

防禦:

strstr ()查詢字串的首次出現,該函式區分大小寫。如果想要不區分大小寫,使用stristr()。(注意後面這個函式多了個i)

繞過:

strstr()函式是對大小寫敏感的,所以我們可以通過大小寫變種來繞過

payload:

http://localhost/injection/user.php?id=1uNion select null,null,null

例子4:空格過濾

防禦:

繞過:

1)使用內聯註釋。

2)使用換行符代替空格。注意伺服器若為Windows則換行符為%0A%0D,Linux則為%0A。

http://localhost/injection/user.php?id=1/**/and/**/11=1  
http://localhost/injection/user.php?id=1%0A%0Dand%0A%0D1=1

例子5:空位元組

通常的輸入過濾器都是在應用程式之外的程式碼實現的。比如入侵檢測系統(IDS),這些系統一般是由原生程式語言開發而成,比如C++,為什麼空位元組能起作用呢,就是因為在原生變成語言中,根據字串起始位置到第一個出現空位元組的位置來確定字串長度。所以說空位元組就有效的終止了字串。

繞過:

只需要在過濾器阻止的字串前面提供一個採用URL編碼的空位元組即可。

payload:

例子6:構造故意過濾

防禦:

繞過:

檔案的63行開始可以看到,此處將傳入的%27和%2527都進行刪除處理,也就是還沒傳入資料庫前就已經被該死的程式吃了,但是在67行看到他還吃了*,這樣我們就有辦法了,我們構造%*27,這樣程式吃掉星號*後,%27就會被傳入。

payload:    

http://localhost/injection/user.php?id%3D1%*27%*20and%*20%*271%*27%3D%*271

(id=1' and '1'='1-->id%3D1%*27%*20and%*20%*271%*27%3D%*271)

參考:

《phpcms_v9.6.0_sql注入與exp》:

https://zhuanlan.zhihu.com/p/26263513