首先我們增加一個login並缺省test_db數據庫。
--add login
use master
Go
EXEC sp_addlogin 'njslt', 'nJSlt', 'test_db'
Go
use test_db
Go
EXEC sp_adduser 'njslt', 'nJSlt', 'db_owner'
Go
/*
這兒一定要執行以下的過程哦,否則會:
服務器: 消息229,級別14,狀態5,過程xp_cmdshell,行1
拒絕了對對象'xp_cmdshell'(數據庫'master',所有者'dbo')的EXECUTE 權限。
*/
use master
Go
EXEC sp_adduser 'njslt', 'nJSlt', 'db_ddladmin'
Go
GRANT exec ON xp_cmdshell TO nJSlt
GO
接著我們以nJSlt連接數據庫,並打開查詢分析器,執行如下角本:
exec master..xp_cmdshell 'dir c:'
/*
消息50001,級別1,狀態50001
由於LogonUserW 返回錯誤1326,執行xp_cmdshell 失敗。
請確保運行SQL Server 的服務帳戶具有適當的特權。
有關詳細信息,請在聯機叢書中搜索與xp_sqlagent_proxy_account 相關的主題。
*/
好,問題出來了,默認情況下,只有 sysadmin 固定服務器角色的成員才能執行此擴展存儲過程。但是,也可以授予其他用戶執行此存儲過程的權限。
當作為 sysadmin 固定服務器角色成員的用戶喚醒調用 xp_cmdshell 時,將在運行 SQL Server 服務的安全上下文中執行 xp_cmdshell。當用戶不是 sysadmin 組的成員時,xp_cmdshell 將模擬使用 xp_sqlagent_proxy_account 指定的 SQL Server 代理程序的代理帳戶。如果代理帳戶不能用,則 xp_cmdshell 將失敗。這只是針對於 Microsoft® Windows NT® 4.0 和 Windows 2000。在 Windows 9.x 上,沒有模擬,且 xp_cmdshell 始終在啟動 SQL Server 的 Windows 9.x 用戶的安全上下文下執行。
記得以前有人問題這個問題時,我當時想當然的回答了利用SETUSER來臨時切換安全上下文,所以我第一反應想用這個來實現,結果發現失敗了,那如何來解決這個問題呢。我做了兩種方法,大家看看:
一、提升用戶,加入固定服務器角色
根據聯機幫助提示,xp_cmdshell只有是sysadmin固定服務器角色成員才可以,那我加它進sysadmin角色裡,但是一定要注意sysadmin角色在SQLSERVER裡可是能進行任何活動的哦,這是不是有安全隱患?
以SA登錄執行:
exec sp_addsrvrolemember 'nJSlt', 'sysadmin'
GO
二、 模擬使用 xp_sqlagent_proxy_account 指定的 SQL Server 代理程序的代理帳戶
DECLARE
@winuser sysname,
@passWord sysname,
@Nsql varchar(1000);
-- 在操作系統中為xp_cmdshell 代理帳戶建立Windows 用戶
SELECT
@user = N'xpcmdshell',
@passWord = N'xpcmdshell',
@Nsql = 'NET USER "' + @winuser + '" "' + @passWord + '" /ADD';
EXEC xp_cmdshell @Nsql;
go
-- 建立xp_cmdshell 代理帳戶
EXEC master.dbo.xp_sqlagent_proxy_account N'SET',
N'',
@user,
@passWord
這時你在剛才以nJSlt連接用查詢分析器再試試,xp_cmdshell有結果了。
--刪除測試環境:
--drop db user,login , Windows user
/*
use test_db
go
sp_dropuser 'nJSlt'
go
use master
go
sp_dropuser 'nJSlt'
go
sp_droplogin 'nJSlt'
go
DECLARE
@user sysname,
@passWord sysname,
@sql varchar(1000);
SELECT
@user = N'xpcmdshell',
@passWord = N'xpcmdshell',
@sql = 'NET USER ' + @user + ' /delete';
select @sql
EXEC xp_cmdshell @sql;
*/