从过程以 EXECUTE AS OWNER 调用 xp_cmdshell

Joh*_*ees 5 sql-server xp-cmdshell

我试图了解在用户定义的存储过程中包装 xp_cmdshell 功能的详细信息,以便其他用户可以只获得对存储过程的执行权限,而不是 xp_cmdshell。

此场景中的步骤是:

  1. xp_cmdshell 已启用并且 xp_cmdshell 代理已创建
  2. 具有 db_owner 成员身份的用户创建一个调用 xp_cmdshell 的存储过程 WITH EXECUTE AS OWNER
  3. 用户执行存储过程,因此执行任意shell代码

这出乎我的意料。我不希望只有 db_owner 的用户能够实现这一点。(显然假设系统管理员已经启用了 xp_cmdshell。)

当数据库所有者从 sa 更改为另一个低特权登录名时,用户存储过程将不再能够调用 xp_cmdshell。

USE MASTER;
CREATE DATABASE testdb;
CREATE LOGIN testuser WITH PASSWORD = 'password', CHECK_POLICY=OFF;
CREATE LOGIN dummyuser WITH PASSWORD = 'password', CHECK_POLICY=OFF;
SELECT * from sys.credentials WHERE NAME LIKE '%cmdshell%';
-- returned: 101 ##xp_cmdshell_proxy_account## .....

USE testdb;

EXEC sp_changedbowner 'sa';  
CREATE USER testuser FOR LOGIN testuser;
ALTER ROLE db_owner ADD MEMBER testuser;

EXECUTE AS LOGIN = 'testuser';
GO

CREATE PROCEDURE [dbo].[testproc]
WITH EXECUTE AS OWNER
AS
    SELECT SUSER_NAME() as [SUSER_NAME()], USER_NAME() as [USER_NAME()];  
    exec xp_cmdshell 'echo %time%';
GO

SELECT SUSER_NAME() as [SUSER_NAME()], USER_NAME() as [USER_NAME()];  

EXEC dbo.testproc; 
-- returned: sa dbo  proving that the call to xp_cmdshell has succeeded

EXEC xp_cmdshell 'echo %time%';
-- returned: The EXECUTE permission was denied on the object 'xp_cmdshell'

REVERT

EXEC sp_changedbowner 'dummyuser';  
EXECUTE AS LOGIN = 'testuser';
EXEC dbo.testproc; 
-- returned: The EXECUTE permission was denied on the object 'xp_cmdshell'
-- proving that the sysadmin role of the database owner is relevent

REVERT
Run Code Online (Sandbox Code Playgroud)

请注意,我没有向任何特定用户授予执行 xp_cmdshell 权限。

我认为如果小心地仅授予执行 xp_cmdshell 权限,则启用 xp_cmdshell 是可以的,但我的示例似乎表明情况并非如此。

由于系统管理员通常是数据库所有者,因此此示例是否显示出严重的安全问题,或者我是否误解了什么?

Dan*_*man 2

xp_cmdshellcross database ownership chaining如果在服务器级别、数据库DB_CHAINING的数据库选项testdbEXECUTE AS OWNER在 proc 中指定,则可以在 sa 拥有的数据库中执行而无需直接执行权限。这些都是非默认配置,默认情况下处于关闭状态。重要的是,不应允许非 sysadmin 角色成员在 sa 拥有的数据库中创建 dbo 拥有的对象,以避免权限升级。

尽管在 T-SQL 中使用xp_cmdshell通常是一种可疑的做法,但xp_cmdshell可以通过使用证书对存储过程进行签名来安全地封装在用户存储过程中。这种封装避免了授予直接执行权限xp_cmdshell

  • 不,我执行了OP的代码,并且**在服务器级别没有跨数据库所有权链接**,当然**代码没有将 testdb 标记为值得信赖** (2认同)
  • 在数据库上以不可信的方式执行不会在当前数据库之外添加任何附加权限,此外,对于任何其他数据库,它会抛出错误“数据库主体...无法访问<另一个数据库>”,所以这是一个BUG (2认同)