xp_cmdshell (Transact-SQL)

适用于:SQL Server

生成 Windows 命令 shell 并以字符串的形式传递以便执行。 任何输出都作为文本的行返回。

Transact-SQL 语法约定

语法

xp_cmdshell { 'command_string' } [ , NO_OUTPUT ]

参数

command_string

包含要传递给操作系统的命令的字符串。 command_string为 varchar(8000)nvarchar(4000),没有默认值。 command_string 不能包含多个双引号集。 如果文件路径或command_string引用的程序名称中存在任何空格,则需要单对引号。 如果不方便使用内含的空格,则可考虑使用 FAT 8.3 文件名作为解决方法。

NO_ OUTPUT

可选参数,指定不应将输出返回到客户端。

返回代码值

0(成功)或 1(失败)。

结果集

执行以下 xp_cmdshell 语句将返回当前目录的目录列表。

EXEC xp_cmdshell 'dir *.exe';
GO

行在 nvarchar(255) 列中返回。 NO_OUTPUT如果使用此选项,则仅返回以下输出:

The command(s) completed successfully.

注解

生成的 xp_cmdshell Windows 进程具有与 SQL Server 服务帐户相同的安全权限。

注意

xp_cmdshell 是一项功能强大的功能,默认情况下处于禁用状态。 xp_cmdshell 可以使用基于策略的管理或执行 sp_configure来启用和禁用。 有关详细信息,请参阅 Surface area 配置xp_cmdshell(服务器配置选项)。 使用 xp_cmdshell 可以触发安全审核工具。

xp_cmdshell 同步操作。 在命令 shell 命令完成之前,控件不会返回到调用方。 如果在 xp_cmdshell 批处理中执行并返回错误,则批处理将失败。

xp_cmdshell代理帐户

当用户调用不是 sysadmin 固定服务器角色的成员时,xp_cmdshell请使用名为 ##xp_cmdshell_proxy_account## 的凭据中的帐户名和密码连接到 Windows。 如果此代理凭据不存在, xp_cmdshell 则失败。

可以通过执行 sp_xp_cmdshell_proxy_account代理帐户凭据来创建。 此存储过程将 Windows 用户名和密码作为参数使用。 例如,以下命令为具有 Windows 密码 SHIPPING\KobeR 的 Windows 域用户 sdfh%dkc93vcMt0 创建代理凭据。

EXEC sp_xp_cmdshell_proxy_account 'SHIPPING\KobeR', 'sdfh%dkc93vcMt0';

有关详细信息,请参阅sp_xp_cmdshell_proxy_account(Transact-SQL)。

权限

由于恶意用户有时尝试使用 xp_cmdshell提升其权限, xp_cmdshell 因此默认处于禁用状态。 使用 sp_configure基于策略的管理 来启用它。 有关详细信息,请参阅 xp_cmdshell 服务器配置选项

首次启用时,xp_cmdshell需要 CONTROL 标准版RVER 权限才能执行,并且创建的 xp_cmdshell Windows 进程与 SQL Server 服务帐户具有相同的安全上下文。 SQL Server 服务帐户通常具有的权限比由创建 xp_cmdshell的进程执行的工作所需的权限多。 为了增强安全性,应将访问 xp_cmdshell 限制为高特权用户。

若要允许非管理员使用 xp_cmdshell,并允许 SQL Server 使用特权较低的帐户的安全令牌创建子进程,请执行以下步骤:

  1. 使用进程要求的最小特权创建并自定义一个 Windows 本地用户帐户或一个域帐户。

  2. 使用 sp_xp_cmdshell_proxy_account 系统过程进行配置 xp_cmdshell 以使用该最低特权帐户。

    注意

    还可以使用 SQL Server Management Studio 配置此代理帐户,方法是右键单击对象资源管理器中的服务器名称上的“属性”,然后查看“服务器代理帐户”部分的“安全”选项卡。

  3. 在 Management Studio 中,使用 master 数据库执行以下 Transact-SQL 语句,使特定的非 sysadmin 用户能够执行 xp_cmdshell。 指定的用户必须存在于 master 数据库中。

     GRANT exec ON xp_cmdshell TO N'<some_user>';
    

现在,非管理员可以使用你配置的代理帐户的权限启动操作系统进程 xp_cmdshell ,并且这些进程使用你配置的权限运行。 具有 CONTROL 标准版RVER 权限的用户(sysadmin 固定服务器角色的成员)继续接收由其xp_cmdshell启动的子进程的 SQL Server 服务帐户的权限。

若要确定在启动操作系统进程时使用的 xp_cmdshell Windows 帐户,请执行以下语句:

EXEC xp_cmdshell 'whoami.exe';

若要确定另一个登录名的安全上下文,请执行以下 Transact-SQL 代码:

EXEC AS LOGIN = '<other_login>';
GO
xp_cmdshell 'whoami.exe';
REVERT;

示例

A. 返回可执行文件列表

以下示例显示执行目录命令的 xp_cmdshell 扩展存储过程。

EXEC master..xp_cmdshell 'dir *.exe'

B. 不返回输出

以下示例使用 xp_cmdshell 执行命令字符串,且不向客户端返回输出。

USE master;

EXEC xp_cmdshell 'copy c:\SQLbcks\AdvWorks.bck
    \\server2\backups\SQLbcks', NO_OUTPUT;
GO

°C 使用返回状态

在以下示例中 xp_cmdshell ,扩展存储过程还建议返回状态。 返回代码值存储在变量 @result 中。

DECLARE @result INT;

EXEC @result = xp_cmdshell 'dir *.exe';

IF (@result = 0)
    PRINT 'Success'
ELSE
    PRINT 'Failure';

D. 将变量内容写入文件

以下示例将 @var 变量的内容写入当前服务器目录下名为 var_out.txt 的文件中。

DECLARE @cmd SYSNAME,
    @var SYSNAME;

SET @var = 'Hello world';
SET @cmd = 'echo ' + @var + ' > var_out.txt';

EXEC master..xp_cmdshell @cmd;

E. 将命令的结果捕获到文件

以下示例将当前目录的内容写入当前服务器目录下名为 dir_out.txt 的文件中。

DECLARE @cmd SYSNAME,
    @var SYSNAME;

SET @var = 'dir /p';
SET @cmd = @var + ' > dir_out.txt';

EXEC master..xp_cmdshell @cmd;