如何安全地進行SQL注入測試

如果從Gitlab最近的離線事件(他們處理的非常好)能夠吸取某個教訓的話,那就是公司必須溺愛般地保護他們的生產資料庫;而作為滲透工程師,這個責任也延伸到我們。生產資料庫從本質上就不適合作為實驗的場所,因為任何意外的結果都可能對數據造成不可逆的不良影響,但滲透測試(至少黑盒滲透)卻必須通過實驗的方式尋找漏洞。本篇文章討論的就是如何在避免修改數據的情況下安全地在生產資料庫尋找漏洞。

許多公司都允許對生產伺服器和資料庫的測試,而這也並非沒有道理:生產環境是公司最可能被攻擊的位置,所以必須經過嚴密測試。雖然本文中說的所有內容都同樣適用於非生產環境,但在其他環境下意外修改數據的後果相比之下並不嚴重。作為滲透工程師,最大的噩夢恐怕就是自己的一個失誤搞垮了客戶的生產環境。運氣好的話也許僅導致一些離線時間,通過備份可以恢復伺服器;差的話可能用戶沒有完整的備份,失誤直接導致關鍵數據丟失。我們必須找到一種不會意外修改生產數據的方法來測試SQL注入。

我用谷歌搜索了「安全的SQL注入」,卻沒有找到任何相關的結果。當然,肯定有其他人寫過這個話題,NetSPI(原作者公司)的其他員工們也提到過他們解決這個問題的方法,但我希望通過這篇博文讓這個話題獲得更廣泛的關注並易於訪問。

準備測試環境

讓我們來重現一下常見的資料庫環境,來測試我們的注入。我們先安裝三款企業常用的關係資料庫管理系統(RDBMS),MySQL、MSSQL、和Oracle,並在它們中各創建一個儲存用戶的表(USERS),如下。

再添加一些用戶。

新手滲透工程師的第一天

在設置完成後,每個資料庫里都有一個名為USERS的表,它們的結構如下:

對於多數滲透測試來說,用戶表通常第一個被觸碰的表,因為它被用於用戶登錄。我們假設查詢它的代碼如下:

SELECT username FROM USERS WHERE username=$username and password=$password;

很明顯,這段代碼存在SQL注入漏洞,但它本身並不能對系統造成什麼影響(僅是泄露數據),所以我們案例中的新手滲透工程師可以大膽地隨意注入』 or 1=1 --。但如果是下面這段查詢代碼呢?這段代碼用於更新用戶的電子郵箱:

UPDATE USERS set email=$email where username=$username;

這回,如果滲透工程師還在大意地隨便亂用』 or 1=1 --,則後果不堪設想。

UPDATE USERS set email=; -- where username = $username;

糟啦!

公司資料庫中的所有電子郵件都被刪除了。假設這個公司沒有完整的備份,無法恢復這些郵件,那接下來該怎麼辦?更新一下簡歷,準備去面試吧– 這個工程師可以和這份工作說再見了。

如何保住你的工作

有幾種辦法可以避免上述的失誤,而它們的關鍵其實都在於多花一秒時間去思考伺服器需要執行什麼類型的查詢來實現被測試的功能。咱們換個角度來看剛才執行的這個查詢。

UPDATE USERS set email=$email where username=$username;

雖然在黑盒測試中我們看不到伺服器上執行的代碼,但我們能看到瀏覽器向它發送的請求,如下:

POST /updateEmail HTTP/1.1
Host: jakereynolds.co
Connection: close
Content-Length: 165
Content-Type: application/x-www-form-urlencoded

username=jake&[email protected]

從這個HTTP請求的格式和服務端點的名稱應該不難推斷出伺服器需要執行的查詢。很明顯,這個服務端點的用途是更新用戶的電郵,那必然會執行UPDATE查詢。我們的目標就是找到既可證明SQL注入漏洞存在,又不會造成破壞的注入載荷,並用其進行測試。

我們先來試試串聯兩個字元串。我們先用一個單引號結束當前的字元串,然後用相應的串聯運算符將另一個字元串與其串聯。如果資料庫成功將兩個字元串串聯在一起,我們就能得知它存在SQL注入漏洞了。

雖然每個資料庫系統的語法不太一樣,但它們的功效都等同於:

UPDATE USERS set email=+concat where username=jake;

若是成功,那麼資料庫的內容將被更新為:

再來看看一些其他辦法。MySQL和Oracle都允許對數字字元串進行算術運算。對於MSSQL,如果某個注入點不是字元串,而是整數值,則可以直接注入數字進行算術運算。

舉例如下:

UPDATE USERS set email=1+1 where username=jake;

我們現在已經有辦法根據不同資料庫系統進行安全的SQL注入測試了。但如果我們不知道伺服器運行的具體是哪個資料庫系統,該怎麼辦?有沒有任何一個載荷,可以通用於這三種RDBMS?

在做了一系列嘗試後,我沒能發現任何一個在這三種資料庫系統中功能完全一樣的運算符或函數。但是,我們並不需要這個載荷在對每種系統效果都一模一樣,只要它能核實注入漏洞的存在就夠了。

如之前所述,在MSSQL中「+」運算符被用於串聯字元串和加法運算,而在 MySQL和Oracle中它只被用於加法運算。也就是說,在MSSQL中,表達式『1』+『1』 會被評估為『11』,而在MySQL和Oracle中它則會被評估為『2』。所以,以下載荷便可通用於測試全三種資料庫系統:

UPDATE USERS set email=1+1 where username=jake;

若資料庫是 MSSQL ,則新的值會是『11』。

成功了!我們現在可以利用這個載荷隨意對最常見的三種RDBMS進行測試,並且不用擔心會造成任何不可逆轉的影響。未來的挑戰是擴展它以適應更多的RDBMS和更複雜的注入點。這個挑戰就留給讀者了。

本文由看雪翻譯小組 buusc 編譯,來源netspi@Jake Reynolds,轉載請註明來自看雪社區

推薦閱讀:

相关文章