本文介绍了SQL Server中xp_cmdshell和sp_xp_cmdshell_proxy_account系统存储过程,以及开发人员如何使用它们来执行Windows命令。
什么是xp_cmdshell存储过程?
简而言之,xp_cmdshell是SQL Server中的一个系统存储过程。它允许从SQL Server环境中执行Windows shell命令。当命令被作为输入字符串传递时,shell的输出被作为文本行返回。
xp_cmdshell需要两个参数;一个是必需参数,一个是最佳参数。
- Windows shell命令:(必填,方向:输入,数据类型。NVarchar(4000)或Varchar(8000))。将被传递给Windows操作系统的命令
- no_output(可选,方向:输入):当这个关键字被传递给xp_cmdshell时,不会返回任何输出。
xp_cmdshell的默认目录是Windows system32文件夹。(C:\Windows\System32)。
让我们检查一下在Windows shell中执行命令和使用xp_cmdshell存储过程的区别。让我们执行dir命令,列出这个目录下的所有可执行文件。让我们首先从Windows命令壳中执行该命令。下面的图片显示了该命令的输出。
图1 - Windows cmd输出
现在,如果我们使用xp_cmdshell存储过程执行同样的命令,我们可以检查输出是否相同。
图2 - xp_cmdshell输出
现在,让我们尝试使用no_output关键字。如下面的图片所示,没有返回任何结果。
图3 - 使用no_ouptut参数
xp_cmdshell是如何启用的?
默认情况下,当我们试图执行xp_cmdshell存储过程时,会抛出以下异常。
SQL Server阻止了对组件 "xp_cmdshell "的存储过程 "sys.xp_cmdshell "的访问,因为作为该服务器安全配置的一部分,这个组件已经关闭。系统管理员可以通过使用sp_configure来启用'xp_cmdshell'的使用。关于启用 "xp_cmdshell "的更多信息,请在SQL Server Books Online中搜索 "xp_cmdshell"。
根据微软的文档,这个功能被禁用,因为恶意用户有时会试图通过使用它来提升自己的权限。要启用这个功能,我们必须首先使用sp_configure存储过程来启用高级配置,然后启用xp_cmdshell的使用。
EXEC sp_configure 'show advanced options', 1;
GO
RECONFIGURE;
GO
EXEC sp_configure 'xp_cmdshell', 1;
GO
RECONFIGURE;
GO
xp_cmdshell是如何执行Windows命令的?
我们可以想到一个问题,xp_cmdshell是如何执行Windows命令的?用户账户是用来做什么的?
当它被一个属于SysAdmin角色的用户调用时,xp_cmdshell使用SQL Server服务账户在Windows中执行命令。主要的漏洞是,服务账户的权限往往超过执行进程的要求,这意味着它应该只为一些特定的用户启用。
图4 - 检查用于执行Windows命令的windows用户
如果用户不是SysAdmin角色的成员,xp_cmdshell将使用存储在名为*##xp_cmdshell_proxy_account##*的凭证中的账户名和密码执行命令。如果这个代理凭证不存在,xp_cmdshell将失败。
使用sp_xp_cmdshell_proxy_account存储过程
假设我们需要从一个不属于SysAdmin角色的用户执行xp_cmdshell存储过程。在这种情况下,我们首先需要使用以下命令授予映射的数据库用户执行。
GRANT EXECUTE ON xp_cmdshell TO TestUser
图5 - 授予xp_cmdshell存储过程的执行权
或者抛出以下异常。
在对象'xp_cmdshell',数据库'mssqlsystemresource',模式'sys'上拒绝了EXECUTE权限。
图6 - 当执行权限未被授予时抛出的异常
当它被一个不属于sysadmin固定服务器角色的用户调用时,xp_cmdshell通过使用存储在名为*##xp_cmdshell_proxy_account##的凭证中的账户名和密码连接到Windows。*如果这个代理凭证不存在,xp_cmdshell将以下面的错误信息失败。
xp_cmdshell代理账户信息不能被检索到或者是无效的。验证'##xp_cmdshell_proxy_account##'凭证是否存在并包含有效信息。
创建一个代理账户凭证
为了配置*##xp_cmdshell_proxy_account##*,我们需要使用sp_xp_cmdshell_proxy_account系统存储过程。这个存储过程有两个使用情况:创建和删除一个代理账户凭证。
为了创建一个代理账户凭证,我们应该向sp_xp_cmdshell_proxy_account存储过程传递两个参数:windows用户名和密码,如下所示。
EXEC sp_xp_cmdshell_proxy_account 'account_name' , 'password'
即使我们向sp_xp_cmdshell_proxy_account存储过程传递了正确的凭证,也会抛出一个 "访问被拒绝 "的异常。
在执行sp_xp_cmdshell_proxy_account的过程中发生了一个错误。可能的原因是:提供的账户无效,或者'##xp_cmdshell_proxy_account##'证书不能被创建。错误代码。5(访问被拒绝。),错误状态。0.
我们应该关闭SQL Server Management Studio,并以管理员身份再次启动它,以解决这个错误。
图7 - 以管理员身份启动SSMS
重新启动SQL Server Management Studio后,存储过程被成功执行。
图8 - 命令成功执行
#xp_cmdshell_proxy_account#证书将被创建,并在服务器资源管理器的 "Credentials "文件夹中查看。
图9 - 创建的代理账户凭证
现在,让我们尝试执行 "Whoami "命令,检查在Windows上执行xp_cmdshell命令的Windows用户。下面的图片显示,该命令是使用代理账户中定义的Windows凭证执行的。

图10 - 执行Whoami命令
删除代理账户凭证
要删除现有的代理账户凭证,你应该给sp_xp_cmdshell_proxy_account存储过程传递一个NULL值。
EXEC sp_xp_cmdshell_proxy_account NULL
总结
这篇文章解释了SQL Server中的xp_cmdshell系统存储过程以及如何使用它。此外,它还解释了如何使用存储过程sp_xp_cmdshell_proxy_account创建一个代理账户凭证。