SQL Server has a special extended stored procedure called xp_cmdshell. This procedure has a lot of power: it allows to execute any command line code on the machine hosting the SQL Server.
Imagine you want to list all the files on C: on the SQL Server Windows host: you could write a T-SQL statement like this one:
This stored procedure, however, is a very dangerous one, as it would allow to execute harmful code. This is the reason why it's disabled by default. Even when enabled, only users on the sysadmin role can use it.
If you ever need some users the ability to run only some specific commands with xp_cmdshell, you can use the method I'll explain below, making use of the EXECUTE AS modifier of the stored procedure definitions in T-SQL.
The proposed solution involves five steps:
- Enabling the xp_cmdshell extended procedure.
- Adding a procedure on the database with the EXECUTE AS modifier as an administrator, controlling which commands are allowed to be executed.
- Modifying or creating the xp_cmdshell_proxy_account, associating it to a user with sysadmin privileges.
- Giving the user(s) you want the EXECUTE privileges to the procedure.
- Grant the proxy account user the privilege to log on as a batch in the Windows server.
The execution of xp_cmdshell must be enabled on the SQL Server. This can be done through the SQL Surface Area Configuration utility or by code. Refer to Figure below on how to activate xp_cmdshell through the SQL Surface Area Configuration.
To enable xp_cmdshell using SQL code, use the sentences below:
This will allow users of the sysadmin role, and no one else, to execute xp_cmdshell.
Now we have to create a special stored procedure that will control the actions used as parameters to xp_cmdshell. This will allow the administrators of the database to have control over which commands they allow to be executed on their servers. The most important part of this procedure is the EXECUTE AS OWNER modifier. By using this modifier, everyone that runs that procedure will be able to run it as if it was the owner of the database, thus having execute permissions to xp_cmdshell (we're assuming the procedure will be created in the master schema. By granting execute permissions on that procedure, you will allow specific users an indirect way to call the xp_cmdshell.
Using this method, only the users of the sysadmin role will be able to execute xp_cmdshell, and only the users you grant EXECUTE permissions on the stored procedure will be able to execute the specific commands that you allow.
To insert the store procedure, log in as a sysadmin on the database and create it with the EXECUTE AS OWNER modifier on it.
For the above procedure to work on non sysadmin accounts there is another step that has to be done. By default, even if you have permissions on the store procedure, you won’t be able to execute it if you’re not on the sysadmin role. This is because those users need a proxy account that is used as the account in which the xp_cmdshell is executed.
So, for this procedure to work, you must create or modify the xp_cmdshell_proxy_account with a user within the sysadmin role. To setup this account, proceed with the code below:
If the above code does not work, try this one:
After the procedure and the proxy account have been set, the users we want to be able to execute the procedure must be granted EXECUTE permission on it. To do so, execute this statement for every user you want to grant permissions:
To grant this permission, use the Local Security Settings on the Administrative Tools interface of the Windows Control Panel. Once there locate the property shown on the screenshot and add the user you gave permissions to the user list.
Note that enabling the xp_cmdshell command may still have some security implications, so try to avoid it when possible.