本文以「SQL注入攻擊」為主軸說明現代SQL注入攻擊的手法,並透過SQLMap工具進行實作,展示如何使用這個自動化工具進行SQL注入測試,這樣的實作將有助於了解一個低門檻的攻擊手法如何對資訊安全構成嚴重威脅,以及如何有效地防範這類攻擊。
隨著網際網路的應用逐漸多元與普及,資訊安全成為不可忽視的重要課題。然而,一些潛藏的應用層漏洞卻常被忽略,其中一項歷年都榜上有名的就是SQL注入攻擊(SQL Injection)。SQL注入攻擊是一種常見但卻危險的攻擊手法,攻擊者利用應用程式對輸入驗證的不當處理,將惡意的SQL語句輸入查詢欄位,從而實現未經授權的資料存取、修改甚至刪除等操作。
本文將深入探討SQL注入攻擊的基本原理和現代攻擊手法,並介紹一些有效的防範對策。此外,也將使用開源滲透測試工具SQLMap進行SQL注入攻擊的實作,展示如何利用這個強大的工具來測試和加固應用程式的安全性。
SQLMap是一款自動化SQL注入測試工具,能夠幫助資安人員快速發現並修復潛在的SQL注入漏洞,但當這項工具落入攻擊者手中時,就會是一項強大的攻擊工具。透過實作的過程,將可逐步了解如何配置及使用SQLMap,並以攻擊者的角度探討其在實際攻擊場景中的應用。
認識結構化查詢語言(SQL)
接著,介紹何謂結構化查詢語言,及其常用的基礎語法。
何謂SQL
Structured Query Language簡稱SQL,是一種結構化查詢的程式語言,用於管理關聯式資料庫管理系統(Relational Database Management System),也稱其為RDBMS,例如MySQL、SQL Server、SQLite、PostgreSQL。SQL的範圍包括資料的插入(INSERT)、查詢(SELECT)、更新(UPDATE)、刪除(DELETE),以及資料庫的建立與修改和資料存取權的控制。
除了RDBMS之外,還有一種非關聯式資料庫系統叫作NoSQL(Not Only SQL),用於處理大規模的資料儲存和查詢需求。與RDBMS相比,NoSQL資料庫在結構靈活性、可擴展性和性能方面具有顯著優勢(例如Redis、MongoDB、Cassandra、Neo4j)。除了傳統的RDBMS會受到SQL Injection攻擊的威脅之外,NoSQL也有可能遭到注入攻擊,但其攻擊手法有別於傳統的RDBMS,而本文將針對RDBMS的手法進行介紹。
認識基礎SQL語法
利用結構化查詢語言SQL能夠針對資料庫與資料表進行增加(Create)、刪除(Delete)、查詢(Read)、更改(Update)等操作,即為所謂的CRUD(Create, Read, Update, Delete)。透過SQLZoo(https://www.sqlzoo.net/wiki/SQL_Tutorial),使用者就能夠在瀏覽器上直接練習SQL語法,而不用在本地端額外進行相關環境的安裝與部署,以下針對常用的SQL語法進行介紹。
SELECT、FROM
SELECT、FROM是用於查詢資料庫中資料的基本指令,需要指定它選取資料的標的,以及從哪個資料表中選取資料。在輸入指令後,會根據所輸入的指定條件回傳資料。除此之外,可透過Where語句來過濾所要選取資料的範圍。而如果想一次取得整張資料表裡所有的資料,可以在SELECT語句裡使用「*」任意符號:
SELECT * FROM example;
圖1為SQLZoo以SELECT、FROM做解題之例題。
WHERE
透過WHERE語法,可在操作SQL的相關操作時設定其篩選條件,唯有符合條件的資料列才會進一步產生作用。如同一般程式語言,可利用If設定其條件式,在後方指定大於、小於、等於等其他比較運算子,同時也可利用邏輯運算子來指定多個查詢條件。同時,在條件設定時也能夠利用括號符號( )執行更複雜的查詢條件,而列於括號中的的條件式會優先判斷,例如:
WHERE rule 1 AND (rule 2 OR rule 3)
會優先對rule 2與rule 3做OR運算,所得結果再和rule 1做AND運算。圖2為SQLZoo以WHERE做解題之例題。
INSERT INTO、VALUES
INSERT INTO語法可用於SQL語法中的新增操作,能夠將指定的資料新增至資料表(Table),而VALUES表示需要新增至資料列的值,以表1的範例做說明。
可使用以下的敘述句作為範例,新增後的結果如表2所示:
INSERT INTO customers VALUES (3,小誠,高雄市,95);
也可以一次新增多筆資料或利用子查詢,從其他的資料表中取得資料進行一次多筆資料的新增。
DELETE FROM
用來刪除資料表中的資料,而若欲針對特定之資料進行刪除,可以使用WHERE條件式加以限制,其語法如下:
DELETE FROM "表格名稱" WHERE "條件";
透過表3範例可以更好地說明刪除語法DELETE FROM的使用方式。
若想要將San Diego的資料刪除,可以用以下的SQL語句來達到這個目的,輸入後的結果如表4所示:
DELETE FROM Store_Information WHERE Store_Name = 'San Diego';
認識SQL Injection
SQL Injection是一種針對資料庫進行攻擊的技術,攻擊者透過向應用程式的輸入欄位(如表單、URL參數等)插入惡意的SQL語句,企圖操控應用程式執行未經授權的SQL操作。這類型的攻擊可能會導致資料洩漏、資料庫破壞或未經授權的存取等其他嚴重的安全問題。
全球性非營利組織OWASP(The Open Web Application Security Project)一個以提高企業和開發者對網路應用程式安全問題的警覺為目的而發表的OWASP TOP 10中,2017年SQL Injection為排名第一名的漏洞,而在2021年時Injection系列的攻擊仍位居第三。由此可見,SQL Injection這種攻擊手法不但造成的危害重大,也是一直存在且持續發生的攻擊方式,因此必須重視SQL Injection這種漏洞攻擊,以加強所管理資料庫的安全和保障。
接著,透過SQL Injection中最經典的範例「'OR 1=1 --」來說明如何繞過登入驗證的手法。先來看看一個正常的查詢語句:
SELECT * FROM users WHERE username= 'user' AND password='password’
從這個語句中,不難推斷出在瀏覽器中輸入的帳號密碼將會對應到語句中的哪些位置,接著透過觀察該語句,可進一步對這個語法進行操作。
舉例來說,在username的位置輸入「admin’ OR 1=1 --」時,便會將字串語句串成以下內容:
SELECT * FROM users WHERE username= ‘admin’ OR 1=1 -- AND password=‘’
從這個範例中可以看見此時的SQL語句變成將username鎖定為admin,並且透過單引號「’」來關閉username的參數,並在後方加上OR邏輯運算符以及一個「1=1」的恆真式,最後透過「--」符號來註解掉後方的密碼驗證,如此一來,就達到繞過登入驗證的效果,倘若該網站服務的前端與後端尚未做好防禦機制,這種攻擊便能夠發動成功。表5中條列了上述的手法攻擊字串的相關說明:
雖然SQL Injection不是一種新興的攻擊手法,但其種類多變且常與其他攻擊類型並行而衍伸出不同的綜合型攻擊,因此近年來還是有諸多企業組織遭受到SQL Injection攻擊而導致資安災害的案例,例如:
‧在2023年11月至12月期間,駭客組織ResumeLooters利用SQL Injection的技術攻擊了超過65個網站,竊取超過200萬個電子郵件地址及其他個人資訊。這次攻擊雖然主要是針對印度、台灣和泰國的招聘與零售網站,但也波及澳大利亞、美國、巴西等其他國家的使用者。
‧2024年初,美國網路安全和基礎設施安全局(CISA)與聯邦調查局(FBI)發布一份聯合警報,指出近期一個受管理的文件傳輸應用程式受有心人士利用SQL Injection攻擊,影響了數千個組織。
‧資安業者Ivant在2024年5月公布裝置管理平台Endpoint Manager(EPM)重大的SQL Injection漏洞CVE-2024-29824,此漏洞存在於EPM的核心伺服器元件,攻擊者可在未經身分驗證的情況下,在EPM伺服器執行任意程式碼,CVSS風險評分達到9.6。2024年10月1日Ivanti更新公告內容,說明該漏洞已被駭客利用,有部分客戶因此遭遇攻擊。
從上述這些例子就可以得知,SQL Injection的攻擊仍不容小覷,在加強自身警惕以提防遭受SQL Injection攻擊的同時,適時地增強資料庫系統的安全防護,也有助於降低遭受SQL注入攻擊的可能性,並避免難以挽回的危害結果的發生。
SQL Injection的常見攻擊類型
接下來,說明SQL Injection常見的攻擊類型。
Error-based SQL Injection
其利用輸入錯誤回傳的SQL錯誤訊息來得知資料庫結構,攻擊者可藉此進行更進一步的攻擊。舉例來說,有一個查詢商品內容的語句如下:
SELECT * FROM products WHERE id = '$product_id';
攻擊者可能藉由輸入:
1' AND 1=CONVERT(int, (SELECT @@version)) --
導致SQL查詢變成:
SELECT * FROM products WHERE id = '1' AND 1=CONVERT(int, (SELECT @@version)) --
若資料庫回傳錯誤資訊如「Conversion failed when converting the nvarchar value 'Microsoft SQL Server 2017' to data type int.」,攻擊者就能夠得知資料庫的版本是Microsoft SQL Server 2017。
Boolean-based SQL Injection
其透過發送可能導致資料庫回傳布林值(True或False)的條件,來觀察伺服器端的變化,用以逐步猜測出資料庫中的資料。假設有一個查詢語句如下:
SELECT * FROM products WHERE id = '$product_id';
攻擊者可以藉由輸入「1' AND 1=1 --」進行Boolean-based SQL Injection,因為1=1永遠為真,這個查詢會返回正常的結果。接下來,攻擊者輸入另一個值進行測試,例如「1' AND 1=2 --」,由於1=2永遠為假,這個查詢不會返回任何結果。透過觀察這兩個查詢的不同結果(如頁面是否顯示資料),攻擊者可以確定應用程式是否易受Boolean-based SQL Injection攻擊。
更進一步來說,攻擊者可透過Boolean-based SQL Injection來逐步推斷資料庫中的資料。例如,攻擊者想知道產品名稱的第一個字母是什麼,可以輸入:
1' AND SUBSTRING((SELECT name FROMproducts WHERE id=1), 1, 1) = 'A' --;
如果頁面能夠正常顯示出內容,說明第一個字母是A。若沒有顯示,攻擊者可繼續嘗試其他字母,直到找到正確的字母為止。
Time-based Blind SQL Injection
其執行包含時間延遲函數的語句(例如SLEEP、WAITFOR DELAY、pg_sleep、dbms_lock.sleep等)來推斷資料庫資訊。攻擊者可以透過測量回應時間來獲取資料,假設有一個查詢如下:
SELECT * FROM products WHERE id = '$product_id';
攻擊者可輸入如「1' AND IF(1=1, SLEEP(5), 0) --」進行Time-based Blind SQL Injection,由於1=1永遠為真,資料庫會執行SLEEP(5)操作,導致查詢延時5秒。藉此攻擊者再輸入「1' AND IF(1=2, SLEEP(5), 0) --」,由於1=2永遠為假,資料庫不會執行SLEEP(5)操作,查詢會立即返回。透過觀察這兩個查詢的不同回應時間,攻擊者可確定應用程式是否易受Time-based Blind SQL Injection攻擊。例如輸入:
1' AND IF(SUBSTRING((SELECT name FROM products WHERE id=1), 1, 1) = 'A', SLEEP(5), 0) --
若頁面發生延時5秒,說明第一個字母是A。如果沒有延時,攻擊者可以繼續嘗試其他字母,直到找到正確的字母為止。
SQL Injection的防範方法
接下來,說明幾種SQL Injection的防範方法。
參數化查詢(Parameterized Queries)
設定參數化查詢後,伺服器不會將參數的內容視為SQL指令的一部分來處理,而是在資料庫完成SQL指令的編譯後,才套用參數執行,因此就算參數中含有具破壞性的指令,也不會被資料庫所執行。這個方法目前已被視為最有效可預防SQL注入攻擊的攻擊手法的防禦方式。
例如,Microsoft SQL Server的參數格式為所有參數前方加上@符號,再執行查詢操作,藉由此方法使參數與SQL語句分開處理,讓攻擊者無法把惡意SQL插入到查詢語句中,同時也自動處理使用者輸入中的特殊字符(例如引號),避免這些字符引起的語法錯誤。圖3是對於參數化查詢簡單說明與舉例。
輸入驗證(Input Validation)
透過驗證使用者的輸入,確保輸入資料符合預期的格式和範圍,以避免非法字元或字串作為請求內容傳送到伺服器主機,而正規表示式(Regular Expression)是一個常用來進行輸入驗證的方法。以Python為例,能以正規表達式的函式庫「re」來建立正規表示式的驗證,以及建立其對應的規則。舉例來說,若規定一個字串驗證必須以Hello作為字串中的起始內容,可透過以下的程式碼來達成目的:
import re str1 = 'hello world' x = re.findall(r'^hello', str1) if x: print("Yes, the string starts with 'hello'") else: print('No match')
其中,re.findall(pattern, string)用於查找所有匹配的子串,並以列表的形式返回。r'^hello其中的符號「^」表示匹配字符串的開頭,而此段程式碼的輸出結果為「Yes, the string starts with 'hello'」。
最小權限原則(Principle of Least Privilege)
為應用程序賦予最低的資料庫權限,只允許其執行必要的操作。並且,避免使用具有高階權限的帳戶連接資料庫。
白名單(Whitelisting)
對輸入進行白名單過濾,僅允許符合預期模式的輸入,拒絕所有不在白名單中的輸入。
情境模擬與實作演練
小汪跟阿埔都是在程園科技公司上班的系統工程師,他們的工作內容是負責系統的建置與網站架設,並使用Linux作業系統維持其運行順利。
但由於小汪總是抱著僥倖的心態,並不對輸入網站的訊息加以管理與限制,同事阿埔多次提醒小汪要小心提防被不法份子利用SQL Injection注入滲透的危險,儘管如此,阿埔仍發現小汪無動於衷,於是他決定給小汪一個深刻的經驗,運用駭客攻擊的手法攻擊小汪所架設的網站,藉此讓小汪知道,不對輸入網站的訊息加以管理與限制可能會發生的後果。
環境準備
阿埔先在自己的電腦進行必要的環境準備,以下是他安裝的軟體與系統:
‧Virtual Box(https://www.virtualbox.org/)
‧Kali Linux(https://www.kali.org/get-kali/#kali-platforms)
‧Metasploitable2(https://sourceforge.net/projects/metasploitable/)
SQLMap介紹
SQLMap是一個由Python編寫的強大滲透測試工具,使用SQLMap可以實現自動化檢測網頁可能存在的SQL Injection漏洞,並利用這些漏洞達成查詢(SELECT)、插入(INSERT)、更新(UPDATE)、刪除(DELETE)資料庫裡的資料,或建立(CREATE TABLE)與修改(ALTER TABLE)資料庫中表格等等的功能,並且SQLMap支援多種資料庫管理系統,包括MySQL、PostgreSQL、Oracle、Microsoft SQL Server、SQLite等。
藉由SQLMap,可以自動化執行腳本的方式取代親自操作漫長且沒有效率的「盲注」過程,透過簡單的指令完成滲透測試,以省略繁雜的語法學習過程,提升進行滲透測試時的效率,表6為SQLMap相關參數介紹以及說明。
動手實作
為了避免觸犯《妨害電腦使用罪》,這裡使用Metasploitable2來模擬小汪所架設的網站,首先在虛擬機上啟動Metasploitable2(其帳號密碼皆為msfadmin),接著使用ifconfig指令得知inet addr的網址是10.0.2.4,然後再開啟Kali Linux(其帳號密碼皆為kali)的Terminal,輸入「ping 10.0.2.4」讓Kali Linux與Metasploitable2連線,操作步驟如圖4~5所示。
與Metasploitable2建立連線後,開啟瀏覽器輸入以ifconfig得知的inet addr連線,然後點選並登入DVWA(帳號admin、密碼password),把DVWA Security設定調為low(預設為high),就可以點選側邊欄的SQL Injection開始做模擬,其操作步驟如圖6~7所示。
阿埔在輸入欄隨意輸入字元(用意是需要呈現送出狀態的網址已進行注入攻擊),並按下〔F12〕鍵(或〔Ctrl〕+〔Shift〕+〔I〕組合鍵)檢查網頁程式碼,再點選Storage後找到Cookies(圖8),並下拉清單選擇該網站網址,以得知Cookies為何(用意是在執行SQLMap時能保持登入狀態),最後點選security以再次確認此網站的security狀態(圖9)。
緊接著,阿埔在Kali Linux中打開Terminal並輸入:
sqlmap -u [小汪架設的網站網址] --cookie=’[網站所顯示的cookies]; security= [網站的security狀態]’
接著,自動執行SQLMap自動檢測網站的SQL漏洞,如圖10所示。
看到網站已被SQLMap找出漏洞後,阿埔使用以下的語法:
sqlmap -u "URL" -D database --tables
首先,查詢資料庫中所有的表格(圖11),阿埔在查看完所有的表格後,認為DVWA資料庫底下的users有值得打開查看的可能,於是接著輸入:
sqlmap -u "URL" -D database -T table --columns
藉此,取得該欄位更進一步的內容,如圖12所示。
阿埔發現在user這個table裡的欄位中有password資料欄,於是決定以「--dump」提取user表格裡的資料,其提取出來之資料如圖13所示。
至此,阿埔成功得知小汪架設之網站使用者的帳號與密碼,並進行登入後修改其密碼。事後,發現無法順利登入管理者帳號的小汪,因著急而跑來詢問同事阿埔,最後阿埔才向小汪坦白這是他對阿埔刻意的警惕,並把密碼修改回來,此事才得以落幕。
在經過說明此事以後,小汪雖然感到生氣,但也因此知道不對輸入欄輸入之資訊進行相當程度的管控,所可能會造成的下場。在此事之後,小汪為網頁設置參數化查詢,以防不法份子使用SQL語法惡意注入攻擊其所架設的網站或服務。
結語
在本文中,以攻擊者的角度示範說明了SQL Injection所帶來的危害以及介紹一些基礎的攻擊類型,並了解當處於網頁設計者與使用者的角色時能夠以什麼樣的方法防禦或降低SQL Injection所帶來的傷害。在情境模擬中更使用了基本的SQLMap語法來檢視資料庫欄位下的密碼資料,示範SQLMap可以達到的攻擊目的。透過實作與情境演練,讓大家從中了解SQL Injection的原理與危害並加以預防,避免發生危害或是當資安事件發生時所造成的損失。
<本文作者:社團法人台灣E化資安分析管理協會(ESAM, https://www.esam.io/)中央警察大學資訊密碼暨建構實驗室 & 情資安全與鑑識科學實驗室(ICCL and SECFORENSICS)1998年成立,目前由王旭正教授領軍,並致力於資訊安全、情資安全與鑑識科學,資料隱藏與資料快速搜尋之研究,以為人們於網際網路(Internet)世界探索的安全保障(https://hera.secforensics.org/)。>