一、Sql注入簡介
Sql 注入攻擊是通過將惡意的 Sql 查詢或添加語句插入到應用的輸入?yún)?shù)中,再在后臺 Sql 服務器上解析執(zhí)行進行的攻擊,它目前黑客對數(shù)據(jù)庫進行攻擊的最常用手段之一。
二、Web 程序三層架構(gòu)
三層架構(gòu)(3-tier architecture
) 通常意義上就是將整個業(yè)務應用劃分為:
界面層(User Interface layer)
業(yè)務邏輯層(Business Logic Layer)
數(shù)據(jù)訪問層(Data access layer)。
區(qū)分層次的目的即為了“高內(nèi)聚低耦合”的思想。在軟件體系架構(gòu)設(shè)計中,分層式結(jié)構(gòu)是最常見,也是最重要的一種結(jié)構(gòu)被應用于眾多類型的軟件開發(fā)。
由數(shù)據(jù)庫驅(qū)動的Web應用程序依從三層架構(gòu)的思想也分為了三層:
表示層。
業(yè)務邏輯層(又稱領(lǐng)域?qū)樱?/p>
數(shù)據(jù)訪問層(又稱存儲層)
拓撲結(jié)構(gòu)如下圖所示
在上圖中,用戶訪問實驗樓主頁進行了如下過程:
在 Web 瀏覽器中輸入
www.shiyanlou.com
連接到實驗樓服務器。業(yè)務邏輯層的 Web 服務器從本地存儲中加載
index.php
腳本并解析。腳本連接位于數(shù)據(jù)訪問層的
DBMS
(數(shù)據(jù)庫管理系統(tǒng)),并執(zhí)行Sql
語句。數(shù)據(jù)訪問層的數(shù)據(jù)庫管理系統(tǒng)返回
Sql
語句執(zhí)行結(jié)果給 Web 服務器。業(yè)務邏輯層的 Web 服務器將 Web 頁面封裝成 HTML 格式發(fā)送給表示層的 Web 瀏覽器。
表示層的 Web 瀏覽器解析 HTML 文件,將內(nèi)容展示給用戶。
在三層架構(gòu)中,所有通信都必須要經(jīng)過中間層,簡單地說,三層架構(gòu)是一種線性關(guān)系。
三、Sql 注入漏洞詳解
3.1 Sql 注入產(chǎn)生原因及威脅:
剛剛講過當我們訪問動態(tài)網(wǎng)頁時, Web 服務器會向數(shù)據(jù)訪問層發(fā)起 Sql 查詢請求,如果權(quán)限驗證通過就會執(zhí)行 Sql 語句。
這種網(wǎng)站內(nèi)部直接發(fā)送的Sql請求一般不會有危險,但實際情況是很多時候需要結(jié)合用戶的輸入數(shù)據(jù)動態(tài)構(gòu)造 Sql 語句,如果用戶輸入的數(shù)據(jù)被構(gòu)造成惡意 Sql 代碼,Web 應用又未對動態(tài)構(gòu)造的 Sql 語句使用的參數(shù)進行審查,則會帶來意想不到的危險。
Sql 注入帶來的威脅主要有如下幾點
- 猜解后臺數(shù)據(jù)庫,這是利用最多的方式,盜取網(wǎng)站的敏感信息。
- 繞過認證,列如繞過驗證登錄網(wǎng)站后臺。
- 注入可以借助數(shù)據(jù)庫的存儲過程進行提權(quán)等操作
3.2 Sql 注入示例一.猜解數(shù)據(jù)庫
接下來我們通過一個實例,讓你更加清楚的理解 Sql 注入猜解數(shù)據(jù)庫是如何發(fā)生的。
使用DVWA滲透測試平臺,作為攻擊測試的目標:
先輸入 1 ,查看回顯 (URL中ID=1,說明php頁面通過get方法傳遞參數(shù)):
那實際上后臺執(zhí)行了什么樣的Sql語句呢?點擊 view source
查看源代碼 ,其中的SQL查詢代碼為:
可以看到,實際執(zhí)行的Sql語句是:
SELECT first_name, last_name FROM users WHERE user_id = '1';
我們是通過控制參數(shù)Id的值來返回我們需要的信息。
如果我們不按常理出牌,比如在輸入框中輸入 1' order by 1#
實際執(zhí)行的Sql語句就會變成:
SELECT first_name, last_name FROM users WHERE user_id = '1' order by 1#`;(按照Mysql語法,#后面會被注釋掉,使用這種方法屏蔽掉后面的單引號,避免語法錯誤)
這條語句的意思是查詢users表中user_id為1的數(shù)據(jù)并按第一字段排行。
輸入 1' order by 1#
和 1' order by 2#
時都返回正常:
當輸入 1' order by 3#
時,返回錯誤:
由此可知,users表中只有兩個字段,數(shù)據(jù)為兩列。
接下來我們使用 union select
聯(lián)合查詢繼續(xù)獲取信息。
union 運算符可以將兩個或兩個以上 select 語句的查詢結(jié)果集合合并成一個結(jié)果集合顯示,即執(zhí)行聯(lián)合查詢。需要注意在使用 union 查詢的時候需要和主查詢的列數(shù)相同,而我們之前已經(jīng)知道了主查詢列數(shù)為 2,接下來就好辦了。
輸入1' union select database(),user()#
進行查詢 :
- database()將會返回當前網(wǎng)站所使用的數(shù)據(jù)庫名字.
- user()將會返回執(zhí)行當前查詢的用戶名.
實際執(zhí)行的Sql語句是 :
SELECT first_name, last_name FROM users WHERE user_id = '1' union select database(),user()#`;
通過上圖返回信息,我們成功獲取到:
- 當前網(wǎng)站使用數(shù)據(jù)庫為 dvwa .
- 當前執(zhí)行查詢用戶名為 root@localhost .
同理我們再輸入 1' union select version(),@@version_compile_os#
進行查詢:
- version() 獲取當前數(shù)據(jù)庫版本.
- @@version_compile_os 獲取當前操作系統(tǒng)。
實際執(zhí)行的Sql語句是:
SELECT first_name, last_name FROM users WHERE user_id = '1' union select version(),@@version_compile_os#`;
通過上圖返回信息,我們又成功獲取到:
- 當前數(shù)據(jù)庫版本為 : 5.6.31-0ubuntu0.15.10.1.
- 當前操作系統(tǒng)為 : debian-linux-gnu
接下來我們嘗試獲取 dvwa 數(shù)據(jù)庫中的表名。
information_schema
是 mysql 自帶的一張表,這張數(shù)據(jù)表保存了 Mysql 服務器所有數(shù)據(jù)庫的信息,如數(shù)據(jù)庫名,數(shù)據(jù)庫的表,表欄的數(shù)據(jù)類型與訪問權(quán)限等。該數(shù)據(jù)庫擁有一個名為 tables 的數(shù)據(jù)表,該表包含兩個字段 table_name 和 table_schema,分別記錄 DBMS 中的存儲的表名和表名所在的數(shù)據(jù)庫。
我們輸入1' union select table_name,table_schema from information_schema.tables where table_schema= 'dvwa'#
進行查詢:
實際執(zhí)行的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 數(shù)據(jù)庫有兩個數(shù)據(jù)表,分別是 guestbook 和 users .
有些同學肯定還不滿足目前獲取到的信息,那么我們接下來嘗試獲取重量級的用戶名、密碼。
由經(jīng)驗我們可以大膽猜測users表的字段為 user 和 password ,所以輸入:1' union select user,password from users#
進行查詢:
實際執(zhí)行的 Sql 語句是:
SELECT first_name, last_name FROM users WHERE user_id = '1' union select user,password from users#`;
可以看到成功爆出用戶名、密碼,密碼采用 md5 進行加密,可以到www.cmd5.com
進行解密。
直此,同學們應該已經(jīng)對 Sql 注入有了一個大概得了解,也清楚了 Sql 注入的強大。
4.3 Sql 注入實例二.驗證繞過
接下來我們再試試另一個利用 Sql 漏洞繞過登錄驗證的實例。
使用事先編寫好的頁面,這是一個普通的登錄頁面,只要輸入正確的用戶名和密碼就能登錄成功。
我們先嘗試隨意輸入用戶名 123 和密碼 123 登錄:
從錯誤頁面中我們無法獲取到任何信息。
看看后臺代碼如何做驗證的:
實際執(zhí)行的操作時:
select * from users where username='123' and password='123'
當查詢到數(shù)據(jù)表中存在同時滿足 username 和 password 字段時,會返回登錄成功。
按照第一個實例的思路,我們嘗試在用戶名中輸入 123' or 1=1 #
, 密碼同樣輸入 123' or 1=1 #
:
為什么能夠成功登陸呢?因為實際執(zhí)行的語句是:
select * from users where username='123' or 1=1 #' and password='123' or 1=1 #'
按照 Mysql 語法,# 后面的內(nèi)容會被忽略,所以以上語句等同于(實際上密碼框里不輸入任何東西也一樣):
select * from users where username='123' or 1=1
由于判斷語句 or 1=1 恒成立,所以結(jié)果當然返回真,成功登錄。
我們再嘗試不使用 # 屏蔽單引號,采用手動閉合的方式:
我們嘗試在用戶名中輸入 123' or '1'='1
, 密碼同樣輸入 123' or '1'='1
(不能少了單引號,否則會有語法錯誤):
實際執(zhí)行的 Sql 語句是:
select * from users where username='123' or '1'='1' and password='123' or '1'='1
看到了嗎?兩個 or 語句使 and 前后兩個判斷永遠恒等于真,所以能夠成功登錄。
還有很多其他 Mysql 語句可以巧妙的繞過驗證,同學們可以發(fā)散自己的思維進行嘗試。
四、判斷 Sql 注入點
通常情況下,可能存在 Sql 注入漏洞的 Url 是類似這種形式 :http://xxx.xxx.xxx/abcd.php?id=XX
對 Sql 注入的判斷,主要有兩個方面:
- 判斷該帶參數(shù)的 Url 是否存在 Sql 注入?
- 如果存在 Sql 注入,那么屬于哪種 Sql 注入?
可能存在 Sql 注入攻擊的 ASP/PHP/JSP 動態(tài)網(wǎng)頁中,一個動態(tài)網(wǎng)頁中可能只有一個參數(shù),有時可能有多個參數(shù)。有時是整型參數(shù),有時是字符串型參數(shù),不能一概而論。總之只要是帶有參數(shù)的 動態(tài)網(wǎng)頁且此網(wǎng)頁訪問了數(shù)據(jù)庫,那么就有可能存在 Sql 注入。如果程序員沒有足夠的安全意識,沒有進行必要的字符過濾,存在SQL注入的可能性就非常大。
4.1 判斷是否存在 Sql 注入漏洞
最為經(jīng)典的單引號判斷法:
在參數(shù)后面加上單引號,比如:
http://xxx/abc.php?id=1'
如果頁面返回錯誤,則存在 Sql 注入。
原因是無論字符型還是整型都會因為單引號個數(shù)不匹配而報錯。
(如果未報錯,不代表不存在 Sql 注入,因為有可能頁面對單引號做了過濾,這時可以使用判斷語句進行注入,因為此為入門基礎(chǔ)課程,就不做深入講解了)
4.2 判斷 Sql 注入漏洞的類型
通常 Sql 注入漏洞分為 2 種類型:
- 數(shù)字型
- 字符型
其實所有的類型都是根據(jù)數(shù)據(jù)庫本身表的類型所產(chǎn)生的,在我們創(chuàng)建表的時候會發(fā)現(xiàn)其后總有個數(shù)據(jù)類型的限制,而不同的數(shù)據(jù)庫又有不同的數(shù)據(jù)類型,但是無論怎么分常用的查詢數(shù)據(jù)類型總是以數(shù)字與字符來區(qū)分的,所以就會產(chǎn)生注入點為何種類型。
4.2.1 數(shù)字型判斷:
當輸入的參 x 為整型時,通常 abc.php 中 Sql 語句類型大致如下:
select * from <表名> where id = x
這種類型可以使用經(jīng)典的 and 1=1
和 and 1=2
來判斷:
- Url 地址中輸入
http://xxx/abc.php?id= x and 1=1
頁面依舊運行正常,繼續(xù)進行下一步。
- Url 地址中輸入
- Url 地址中繼續(xù)輸入
http://xxx/abc.php?id= x and 1=2
頁面運行錯誤,則說明此 Sql 注入為數(shù)字型注入。
- Url 地址中繼續(xù)輸入
原因如下:
當輸入 and 1=1
時,后臺執(zhí)行 Sql 語句:
select * from <表名> where id = x and 1=1
沒有語法錯誤且邏輯判斷為正確,所以返回正常。
當輸入 and 1=2
時,后臺執(zhí)行 Sql 語句:
select * from <表名> where id = x and 1=2
沒有語法錯誤但是邏輯判斷為假,所以返回錯誤。
我們再使用假設(shè)法:如果這是字符型注入的話,我們輸入以上語句之后應該出現(xiàn)如下情況:
select * from <表名> where id = 'x and 1=1'
select * from <表名> where id = 'x and 1=2'
查詢語句將 and 語句全部轉(zhuǎn)換為了字符串,并沒有進行 and 的邏輯判斷,所以不會出現(xiàn)以上結(jié)果,故假設(shè)是不成立的。
4.2.2 字符型判斷:
當輸入的參 x 為字符型時,通常 abc.php 中 SQL 語句類型大致如下:
select * from <表名> where id = 'x'
這種類型我們同樣可以使用 and '1'='1
和 and '1'='2
來判斷:
- Url 地址中輸入
http://xxx/abc.php?id= x' and '1'='1
頁面運行正常,繼續(xù)進行下一步。
- Url 地址中輸入
- Url 地址中繼續(xù)輸入
http://xxx/abc.php?id= x' and '1'='2
頁面運行錯誤,則說明此 Sql 注入為字符型注入。
- Url 地址中繼續(xù)輸入
原因如下:
當輸入 and '1'='1
時,后臺執(zhí)行 Sql 語句:
select * from <表名> where id = 'x' and '1'='1'
語法正確,邏輯判斷正確,所以返回正確。
當輸入 and '1'='2
時,后臺執(zhí)行 Sql 語句:
select * from <表名> where id = 'x' and '1'='2'
語法正確,但邏輯判斷錯誤,所以返回正確。同學們同樣可以使用假設(shè)法來驗證。
五、 總結(jié)
如果你覺得這篇文章講的不錯的話,可以關(guān)注我的其他文章和課程:
- 【課程】SQL 注入基礎(chǔ)原理介紹
-
【課程】滲透測試方法論之 Linux 提權(quán)實戰(zhàn) (專屬優(yōu)惠碼
7MaDpzNc
,可以享受折上折哦!) - 【GitHub】滲透測試方法論/OSCP備考資源
- 【文章】滲透測試方法論之靶機系列
- 【文章】跨站腳本漏洞(XSS)基礎(chǔ)講解