- 前言:近段時間在學習access偏移注入時,在網上查詢了大量的資料,感覺很多資料講解的十分模糊並且我個人認為有很多不夠嚴謹的地方,於是我便線上下經過大量測試,寫出以下文章,如有錯誤,望指出。
- 如要轉載,請標明出處!!
一、認識偏移注入
- 偏移注入的適用背景:
- access資料庫與mysql不同,access資料庫沒有類似於mysql的information_schema這樣的系統資料庫,所以對於access的表名及其欄位名我們只能靠經驗進行猜解,而偏移注入就是提供了另外一種思路:
- 在我們只能猜解出表名,而猜解不出我們所想要的欄位名的情況下,直接爆最後的欄位資料。
- 偏移注入的原理(這裡只是粗略的概述,詳細請看下面):
- 就是將目標表進行(多級)內連線,通過聯合查詢和已知目標欄位名的微調,將我們想要知道的欄位值在已經確定的顯示位上暴露出來。
- 影響偏移注入成功率的因素(當然這些因素都是影響因素,不是決定因素):
- 聯合查詢中顯示位的位置
- 當前注入點所查詢的表的欄位數量(即:“當前表”的欄位數量)
- 目標表的欄位數量
- 我們可以猜解到的目標表的欄位名的數量
二、實戰測試環境
- 此次實戰測試主要涉及的兩張表:product表和admin表
- product表:該表有22個欄位(請謹記這個欄位數)
- admin表:該表有6個欄位(請謹記這個欄位數)
- product表:該表有22個欄位(請謹記這個欄位數)
三、前置知識
-
exist()函式:用於檢查子查詢是否至少會返回一行資料,該子查詢實際上並不返回任何資料,而是返回值True或False。
-
as關鍵字:用於起別名,可以為表起別名,也可以為欄位起別名(as關鍵字可省略)
-
表1 inner join 表2 on 篩選條件 :該關鍵字用於將表1與表2做笛卡爾積,然後根據on後面的條件進行篩選。
- 下圖中select語句的意思是:將admin表與自己做笛卡爾積,然後篩選出兩者id值相同的記錄
- 下圖中select語句的意思是:將admin表與自己做笛卡爾積,然後篩選出兩者id值相同的記錄
-
top n 關鍵字:作用是使查詢結果只顯示前n條記錄
四、原理講解
- 為了方便講解,我們在這裡選擇“實戰”和“偏移注入的注入原理”相結合的方式進行討論。
- 偏移注入的流程是:
- 判斷是否存在注入點
- 判斷當前注入點對應表的欄位數量
- 為方便之後講解,我們把“當前注入點對應表”稱作為“當前表”,
- 把我們將要進行聯合查詢的表稱為“目標表”,
- 在這裡“當前表”->product表;“目標表”->admin表
- 猜解目標表的表名
- 確定顯示位
- 確定目標表的欄位數量
- 開始進行偏移注入,經過不斷的“微調”,將我們想要的欄位值在顯示位處暴露出來。
4.1 判斷是否存在注入點
- payload:
- ?id=1513 and 1=2 頁面顯示出錯
- ?id=1513 and 1=1 頁面顯示正常
- 說明存在注入點,且為數字型注入
4.2 判斷當前注入點對應表的欄位數量
- payload:
- ?id=1513 order by 22
- 頁面返回正常,說明當前表(即product表)對應的欄位數量為22
4.3 猜解目標表的表名
- payload:
- ?id=1513 and exists(select * from admin)
- 因為access資料庫沒有類似於mysql的information_schema這樣的系統索引庫,所以我們只能根據經驗靠猜了,在真實的測試環境中,我們也可以通過社工的方式進行猜解。此次頁面返回正常,說明存在access資料庫中存在admin表。
4.4 確定顯示位
- payload:
- ?id=1513 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22 from admin
- 在頁面的原始碼中,我們可以看到存在3,9,13,15 四個顯示位
4.5 確定目標表的欄位數量
- payload:
- ?id=1513 and exists(select * from admin order by 6)
- 頁面返回正常,說明admin有6個欄位
4.6 開始進行偏移注入
-
偏移注入的基本公式:
- 聯合查詢所要補充的欄位數 = 當前表的欄位數 - 目標表的欄位數 x N(N=1,2...)
- 在此處即為:聯合查詢補充欄位數 = product表的欄位數 - admin表的欄位數 x N
- 當N=1時我們稱為 “1級偏移注入”,當N=2時我們稱為 “2級偏移注入”;當N=3時我們稱為 “3級偏移注入”,...
-
1級偏移注入的payload:
- 根據公式我們可以計算出:聯合查詢補充欄位數 = 22-6x1 = 16
- ?id=1513 union select top 1 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16, * from admin
- 在這裡我們解釋一下,為什麼1級偏移注入並沒有爆出我們想要的欄位值呢:
- 由前面的步驟我們已經得知,已經確定的顯示位只有 3,9,13,15 四個,即只有處於第3,9,13,15這四個欄位的資料才可以顯示出來,
- 但是我們觀察下標發現,在進行1級偏移注入時,admin表的資料實際上是排在了17號欄位之後了,當然不會在頁面中顯示出來。
- 那麼我們怎麼樣才可以將admin表的資料向前移動,以致可以使其處於第3,9,13,15號欄位而顯示出來呢?
- 答案是:我們可以進行2級(多級)偏移注入(即通過admin表的自連線使得sql語句中“ * ”所代表的的欄位數增大,那麼聯合查詢中用於充數字段就會減小,這樣的話,admin表中的資料自然會向前移動了)
-
2級偏移注入的payload:
- 根據公式我們可以計算出:聯合查詢補充欄位數 = 22-6x2 = 10
- ?id=1513 union select 1,2,3,4,5,6,7,8,9,10, * from (admin a inner join admin b on a.id=b.id)
- 根據頁面返回的資料,我們可以看到,在第13號顯示位,我們成功的爆出了密碼值:a48e190faf
- 但這是為什麼呢?
- 通過分析下圖中表2我們發現,經過2級偏移注入,我們成功的將admin表的資料向前移動了6個欄位,使其原本在17號欄位及其之後才顯現出的資料,變為了在11號欄位及其之後就可回顯而出。而此時admin表的password欄位和count_time欄位恰好處於顯示位13和15上,於是就自然而然的暴露了出來。
- 那又為什麼admin表的資料會向前移動6個欄位呢?
- 原因就是,由於admin表進行了一次自連線,使得payload中from關鍵字後面的表由原有的admin表變成了:由“先讓admin自己做笛卡爾積然後挑選id值相等的記錄”組成的表。這樣的話,payload中的“ * ”就由原來所代表的admin表中的6個欄位,變為了現在代表的admin自連線表的12個欄位,又由於union關鍵字的使用,要求union關鍵字後面查詢的欄位數必須要等於前面的表即product表的欄位數,所以union關鍵字後面的select中用於充數的欄位由原來的22-6=16變為了22-12=10個欄位,因此由於充數的欄位變少了,那麼admin表的資料自然的就可以向前移動了。
- 請注意:admin表中的資料向前移動的欄位數只能是admin表(即目標表)欄位數的整數倍(這是由表自連線的特性所決定的)。
- 在此我們已經爆出了admin表的密碼,
- 此時,其實admin表的admin欄位就緊挨在password欄位的前方(其實在實戰環境中我們是不確定admin欄位是在前還是在後的,此處只是為了方便原理的講解,就直接告訴你了)
- 那麼我們是否仍然可以將資料向前移動而爆出admin欄位的值呢?在這裡顯然是不行的,因為我們只能向前移動admin表的欄位數量的整數倍(在這裡即是6的整數倍),而此時admin表的admin欄位此時所處欄位為12號欄位,再向前移動6個欄位的話,admin欄位就處於6號欄位處了,仍然沒有與顯示位的位置發生重合。
-
到了這裡,細心的同學會發現:
- 之前我們講的都是如何將admin表中的資料向前移動,那麼我們可不可以使得資料向後移動呢?要是可以向後移動的話,緊接著2級偏移,然後讓資料向後移動一個欄位,不就正好讓admin欄位處於13號顯示位了嗎?
- 恭喜你!你的想法是對的,我們的確可以讓admin表的資料向後移動,不過遺憾的是,向後移動的欄位數仍然取決於:我們能夠猜解出admin表中多少個欄位名。若猜解出1個欄位名,那麼我們就可以讓資料向後移動1個欄位數,若猜解出2個欄位名,那麼我們就可以讓資料向後移動2個欄位數,以此類推。(不過這裡所需要猜解的欄位名不需要是我們想要查詢的欄位名,只要是admin表中的欄位名均可),原因請繼續往後閱讀:
-
微調payload:
- ?id=1513 union select top 1 1,2,3,4,5,6,7,8,9,10,b.id, * from (admin a inner join admin b on a.id=b.id)
- 根據頁面返回的資料,我們可以看到,在第13號顯示位我們成功的爆出了admin欄位的第一個值:admin
- 原因:
- 我們先觀察sql語句,發現union關鍵字後面的select查詢的填充欄位多了程式碼“b.id”,意思是在此輸出b表(admin表的別名之一)的id欄位值,由於此處已經顯式的指出id欄位值的輸出位置,那麼後面的 “ * ” 就會自動的識別,就只輸出admin自聯表剩下的欄位值了,從而使得剩餘資料均向後移動了一個欄位,讓原本在13號欄位的admin欄位向後移動了1位,到了13號顯示位上了。
- 但請注意:此處的id欄位名是我們已經猜解出的
- 這也就回答了上述所說的:“向後移動的欄位數仍然取決於:我們能夠猜解出admin表中多少個欄位名,不過這裡所需要猜解的欄位名不需要必須是我們想要查詢的欄位名,只要是admin表中的欄位名均可”,因此,如果我們想讓admin資料向後移動2個欄位值,那麼我們就需要知道除了id欄位名外,其他任一欄位名即可,然後構造如下payload:?id=1513 union select top 1 1,2,3,4,5,6,7,8,9,10,b.id,b.欄位名 * from (admin a inner join admin b on a.id=b.id)
五. 總結與反思
- 至此,整個測試已結束,我們成功的爆出了 賬號與密碼:admin/a48e190faf
- 接下來我會依次提出幾個問題,然後一一進行解答:
- 如果我們仍然採用上述環境,那可不可以進行3級偏移和四級偏移呢?
- 答:3級偏移可以,但是4級偏移不行,因為如果進行4級偏移的話,就會使得偏移注入基本公式:聯合查詢補充欄位數=當前表的欄位數-目標表的欄位數 x 4 ==> 22-6x4=-2<0,即:會造成union關鍵字之前的select查詢欄位數的數量 < union關鍵字之後的欄位數量,從而導致查詢失敗。
- 3級偏移的payload:?id=1513 union select top 1 1,2,3,4, * from((admin as a inner join admin as b on a.id=b.id) inner join admin as c on a.id=c.id)
- access偏移注入是否是真的隨機?
- 通過上述原理的講解,這個問題也就不攻自破了,顯然access注入並不是真正的隨機,並不是完全不受我們控制的,在我們獲取足夠資訊的情況下(如“當前表”和“目標表”的欄位數量,已知的“目標表欄位名"的數量),我們可以在一定範圍內完全控制顯示位處的資料顯示,而之所以說是一定範圍內,只是因為“顯示位的位置”和“我們可以猜解到的目標表欄位名的數量”這兩個因素不是我們可以控制的。
- 是否可以只說:“當前表”的欄位數越多成功率越大,或“目標表”的欄位數越少成功率越大?
- 顯然我們不能這樣簡單的得出結論,偏移注入是否能夠成功,取決於:“顯示位位置” 和 “目標欄位能夠移動到的位置” 是否可以重合,如果可以重合的話,即使“當前表”欄位數小一點,“目標表”欄位數多一點也是無妨的(但萬萬不可“當前表”的欄位數量 > “目標表”的欄位數量)
- 是什麼決定著“目標表”的資料一次性前移的欄位數?是什麼決定著“目標表”的資料可以後移的欄位數?
- 前者是由“目標表的欄位數量”所決定的:目標表中的資料向前移動的欄位數只能是目標表中的欄位數的整數倍(這是由表自連線的特性所決定的)。
- 後者是由“我們可以猜解得到的目標表的欄位名數量”所決定。若猜解出1個欄位名,那麼我們就可以讓資料向後移動1個欄位數,若猜解出2個欄位名,那麼我們就可以讓資料向後移動2個欄位數,以此類推。(不過這裡所需要猜解的欄位名不需要必須是我們想要查詢的欄位名,只要是admin表中的欄位名均可)
- 如果我們仍然採用上述環境,那可不可以進行3級偏移和四級偏移呢?