DVWA系列2:SQL Injection

2023-01-19 12:00:45

DVWA系列2:SQL Injection

前言

SQL 注入是比較常見的攻擊型別,之前一直聽說過,也嘗試看過一些教學,但其中的單引號,字串拼接等感覺有點抽象,不知道為什麼要這麼做。這次就使用 DVWA 的環境來演練一下吧。

在這裡我們的目標是獲取所有的使用者名稱和密碼(雖然不是明文)

開啟 SQL Injection 頁面,將級別調整為 Low

1. 情況分析

正常情況下,我們輸入 1,點選 submit 按鈕,就會得到這個使用者的使用者名稱資訊:

此時我們輸入 1 AND 1 = 1,再次點選 Submit 按鈕,發現並沒有報錯。而我們輸入 1' 再點選按鈕後,會提示錯誤:

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''1''' at line 1

說明網頁程式將我們的輸入內容放入了資料庫的查詢語句中,即存在可以注入的地方

SQL 注入分為 數位型注入字元型注入 等等多種型別。數位型注入 意思為查詢條件為數位型別,同樣 字元型注入 意思為查詢條件是字元(串)型別的。在我們的場景中,是輸入單了引號才報錯,說明是 字元型注入

2. Low 難度實操

A. 大概猜測

根據網頁上的業務可以大致猜測一下查詢語句為:

SELECT * FROM 使用者表 WHERE 使用者ID = '傳入的值';

為了驗證猜想,我們傳入 1' OR 1 = 1 #,第一個 ' 用於閉合之前的引號,後面的 # 號 用於註釋SQL語句後面的內容(原查詢語句中的 ' 和 可能的後面內容)。實際執行的 SQL 語句即為:

SELECT * FROM 使用者表 WHERE 使用者ID = '1' OR 1 = 1 #';

可以看到執行成功,符合我們的預期。

B. 判斷欄位數量

我們需要判斷下返回當前結果的這條查詢語句的實際查詢欄位情況。拼接上 1' UNION SELECT 1, 2 #,並嘗試往後逐步增加列數。這裡利用的是 Union 操作要求查詢的欄位數量相等。實際執行的 SQL 語句為:

SELECT f1, f2 ...... FROM 使用者表 WHERE 使用者ID = '1' UNION SELECT 1, 2 #';

如果拼接上 Union 查詢語句沒報錯,則可以確定查詢欄位的數量。根據結果中1,2的順序(我們拼接進去的),可以確定返回欄位的順序。此處只有兩個,比較簡單。

此處也可以通過 Order By 來判斷。Order By 後面加數位,表示按照查詢出來的第幾列排序,如 Order By 2,意思為按照查詢出來的第 2 列排序,而如果沒有這麼多列,就會有報錯資訊。據此可以判斷查詢出的列數量。

C. 獲取敏感資訊

由於我們的目標是查詢使用者表中的使用者名稱和密碼,因此我們需要找到對應的資料庫,對應的表,對應的欄位。對於 MySQL 資料庫,這些內容儲存在 information_schema 這個資料庫中。

首先利用 Union,查出當前資料庫中所有的表。輸入 ' union select 1,group_concat(table_name) from information_schema.tables where table_schema=database() #。MySQL 內建的group_concat 函數可以將多個列組合起來。(此時不在 ' 前輸入既有的 id 的值 1,這樣可以避免查出我們不需要的資料,只需一行就得到了結果)

可以看到當前資料庫中有 guestbook 和 users 這兩張表。顯然我們的目標就是 users 表了,繼續查詢這個表中有哪些列。輸入 ' union select 1,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users' # ,得到結果:

距離目標已經很近了!繼續輸入 ' union select 1,group_concat(concat(user, '-', password)) from users #,得到結果:

Low 的目標達成(怎麼感覺怪怪的)!接下來探索 Medium 難度吧!

3. Medium 難度準備工作

A. 引入 BurpSuite

將難度調整為 Medium,可以看到已經沒有了輸入框,變成了下拉選擇:

其實對於 WEB 頁面來說,無論是輸入框,還是下拉選擇,或者是其它方式,最終反映到與後端伺服器的互動,都是通過 HTTP 請求(當然還有 WebSocket)。如果我們可以攔截這些請求,並嘗試修改,不是一樣可以達到注入的目的嗎。我們可以使用 Burp Suite 來實現這個操作(Burp Suite 有很多其它的功能,這裡用得比較簡單)。

因為還有很多攻擊的形式沒有嘗試,考慮到操作便捷性和以後的使用,這裡使用了另一臺安裝了 Kali Linux 的虛擬機器器,其中包含了很多其它的工具。請務必在法律允許的範圍內使用!!!

官方網站下載 Kali Linux 針對 Vmware 虛擬機器器的映象,並啟動即可。預設的使用者名稱和密碼都是 kali

B. Burp Suite 攔截相關設定

我們需要先設定瀏覽器,讓所有的流量都通過 BurpSuite (預設 8080 埠),這樣才能攔截的到。開啟 Firefox 瀏覽器(火狐大法好,破音),在 General 中找到 Network Settings,並設定代理為 localhost,埠號為 8080,如圖:

在 Firefox 瀏覽器中開啟我們的 DVWA 站點,調整 DVWA Security 中的難易度為 Medium,並開啟我們要操作的 SQL Injection 頁面。之後開啟 BurpSuite,在 Proxy 一欄點選 Intercept is off 以開啟攔截器。隨後在 Firefox 瀏覽器中的流量都會被 BurpSuite 攔截。

4. Medium 難度實操

點選 DVWA 頁面的 submit 按鈕,可以在 Burp Suite 中看到如圖所示的結果:

可以看到我們選擇的引數被放在了紅框所示的位置,接下來像在 Low 裡面一樣將注入的內容拼接到此處即可。

A. 注入型別判斷

id=1 修改為 id=1' OR 1 = 1 #,並點選 Forward 按鈕放行流量,可以看到 Firefox 瀏覽器中提示報錯:

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' OR 1 = 1 #' at line 1

這說明該注入漏洞不再是字元型注入了。嘗試數位型注入,將 id=1 修改為 1 OR 1 = 1 #,再次放行流量,發現沒有報錯,網頁展示了很多使用者的資訊,驗證了 數位型注入 的猜測。

之後的思路和在 Low 裡面的基本一樣,唯一的不同是輸入的內容在 BurpSuite 中修改

B. 判斷欄位數量

id=1 修改為 0 UNION SELECT 1, 2 #,沒有報錯,確定查詢語句查詢的欄位數量是 2 個,同時確定欄位順序。

C. 獲取敏感資訊

查詢資料庫中所有的表,替換為:
0 union select 1,group_concat(table_name) from information_schema.tables where table_schema=database() #

需要注意的是,前面必須要帶有值 0。 因為字元型注入可以直接用 ' 閉合為空字串,而數位型注入如果沒有值,我們替換後實際的執行語句就變成了: SELECT * FROM 表名 WHERE id = union select 1 ........ 這樣,會造成語法錯誤。

檢視表中所有的列。替換為:
0 union select 1,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users' #

此時發生了錯誤

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '\'users\' #' at line 1

可我們並沒有傳入 \'users\' 這樣的東西進去。通過分析或者檢視下DVWA的原始碼(/var/www/html/vulnerabilities/sqli/source/medium.php)發現,此時將單引號跳脫了:

此時可以通過將字串轉換為十六進位制來繞過跳脫。通過線上工具將字串 users 轉換為 7573657273,修改我們的拼接為:

0 union select 1,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name=0x7573657273 #

可以看到此時得到了我們想要的結果:

獲取使用者名稱和密碼。替換為:

0 union select 1,group_concat(concat(user, 0x2d, password)) from users #

原來的 '-' 也替換為了對應的十六進位制 0x2d。獲取到了結果:

Medium 的目標也達成了!!!

5. High 難度實操

檢視頁面和原始碼發現,實際與之前的 Low 幾乎一樣,只是通過彈出頁面,利用 Session 傳值。而且多了一個 LIMIT 1,限制了返回數量只有1條而不是多條,如圖:

而按照我們之前的注入操作都是一行返回,因此我們輸入:

' union select 1,group_concat(concat(user, '-', password)) from users #

即可達成結果。

6. Impossible 難度實操?

Impossible 難度旨在為我們提供一個比較安全的程式碼範例:

調整為 Impossible 難度,實際是很難注入的了。

參考

DVWA-------簡單的SQL隱碼攻擊
DVWA之SQL隱碼攻擊
DVWA SQL Injection SQL隱碼攻擊全等級分析與實踐
DVWA-7.4 SQL Injection(SQL隱碼攻擊)-Impossible