El procedimiento almacenado xp_cmdshell es esencialmente un mecanismo para ejecutar llamadas en el sistema operativo utilizando el contexto de SQL Server (es decir, la cuenta de Windows utilizada para iniciar el servicio del SQL Server) o una cuenta proxy que puede ser configurada para ejecutar xp_cmdshell con diferentes credenciales. Si bien habilitar y utilizar este procedimiento almacenado no es una buena práctica, ciertas aplicaciones usan esta técnica y a veces puede ser necesario acceder a la línea de comandos del sistema operativo para ejecutar algún programa fuera del SQL Server. En estos casos tenemos que tener mucho cuidado en como habilitamos y damos permisos para que el usuario pueda acceder a los recursos del sistema operativo con mínimos permisos. En este artículo analizaremos algunos detalles y de cómo habilitarlo con menos permisos que los indicado en la ayuda.
El procedimiento almacenado xp_cmdshell
Para ejecutar un programa fuera del contexto del SQL Server se utiliza el procedimiento almacenado extendido xp_cmdshell, Con este procedimiento almacenado extendido podemos ejecutar cualquier proceso de línea de comandos, por lo que no solo se pueden ejecutar programas EXE sino que se puede ejecutar un archivo de lotes (BAT o CMD).
Debemos tener sumo cuidado en cómo se utiliza este procedimiento almacenado ya que si el contexto de ejecución tiene permisos de administrador local del equipo por ejemplo el programa o un código inyectado pueden agregar un usuario administrador del equipo (del WIndows) utilizando NET USER y NET GROUP.
En SQL Server 2000, por los riesgos de seguridad que implica y para limitar el acceso al xp_cmdshell , su uso está restringido por defecto o en forma predeterminada solo a los miembros de la función de servidor o rol sysadmin. Para extender los derechos a otros usuarios se puede utilizar el comando GRANT.
En SQL Server 2005 el uso de xp_cmdshell está desactivado por defecto como mecanismo de protección para minimizar los riesgos de seguridad de código no deseado en ejecución dentro o fuera de SQL Server de SQL Server. Por ello, si no se habilita la ejecución del xp_cmdshell ni siquiera los administradores del SQL Server (grupo de servidor sysadmin) podrán ejecutarlo.
Por ejemplo si ejecutamos como administradores:
exec xp_cmdshell 'dir c:\*.*'
El resultado es:
Msg 15281, Level 16, State 1, Procedure xp_cmdshell, Line 1
SQL Server blocked access to procedure 'sys.xp_cmdshell' of component 'xp_cmdshell' because this component is turned off as part of the security configuration for this server. A system administrator can enable the use of 'xp_cmdshell' by using sp_configure. For more information about enabling 'xp_cmdshell', see "Surface Area Configuration" in SQL Server Books Online.
Para poder ejecutar el procedimiento almacenado extendido xp_cmdshell debemos habilitarlo haciendo:
--Habilito la ejecucion del xp_cmdshell
EXEC sp_configure 'show advanced options', 1
GO
RECONFIGURE
GO
EXEC sp_configure 'xp_cmdshell', 1
GO
RECONFIGURE
GO
Ahora vemos que si volvemos a ejecutar el scrip T-SQL anterior como administrador del SQL Server vemos que nos responde cuando estamos autenticados como administradores. El proceso de Windows creado por xp_cmdshell dispone de los mismos derechos de seguridad que la cuenta de servicio de SQL Server la cual tenía los permisos adecuados en la raíz del disco.
Cuenta proxy para el xp_cmdshell
Cuando es llamada por un usuario que no pertenece al rol (función de servidor) sysadmin, el xp_cmdshell se conecta a Windows con el nombre de la cuenta y la contraseña almacenados en la credencial con el nombre ##xp_cmdshell_proxy_account## en lugar de usar la cuenta de servicio por lo que habrá que indicarla previamente o sino dará error.
Vamos a probar ahora con un login que solo tiene permisos mínimos
--Creamos el login
CREATE LOGIN [Prueba]
WITH PASSWORD=N'<la contraseña del usuario>',
DEFAULT_DATABASE=[master],
CHECK_EXPIRATION=OFF, CHECK_POLICY=OFF
GO
Para crear la credencial de la cuenta de proxy hay que ejecutar sp_xp_cmdshell_proxy_account y como parámetros el nombre del usuario y la contraseña de Windows.
-- Asigno la proxy account
EXEC sp_xp_cmdshell_proxy_account
N'sqltotal\mariano',
N'<la contraseña del usuario>'
El resultado es:
Msg 15137, Level 16, State 1, Procedure sp_xp_cmdshell_proxy_account, Line 1
An error occurred during the execution of sp_xp_cmdshell_proxy_account. Possible reasons: the provided account was invalid or the '##xp_cmdshell_proxy_account##' credential could not be created. Error code: '5'.
Aquí nos encontramos con un nuevo problema si estamos usando Windows Vista como es mi caso. No podemos asignar esta contraseña por más que el usuario usado sea administrador del SQL Server debido al UAC. Por lo tanto debemos ejecutar este comando en una nueva instancia del SQL Server Management Studio como administrador usando la opción “RUN AS ADMINISTRATOR” (ejecutar como administrador).
Luego de asignar la cuanta proxy como administrador local y del SQL Server abrimos una nueva ventana con el usuario prueba y verificamos que pasa:
exec xp_cmdshell 'dir c:\*.*'
Y el resultado es:
Msg 229, Level 14, State 5, Procedure xp_cmdshell, Line 1
The EXECUTE permission was denied on the object 'xp_cmdshell', database 'mssqlsystemresource', schema 'sys'.
En este punto si revisamos la ayuda en el link siguiente podemos verificar que nos dice que se requiere el permiso CONTROL SERVER, para poder ejecutar xp_cmdshell el cual no es adecuado ya que posibilita tomar el control total del SQL Server.
xp_cmdshell en la ayuda del SQL Server
Por lo tanto vamos a crear el usuario dentro de la base de datos master relacionado con el login y asignar solo el permiso de ejecución del procedimiento almacenado:
-- Creo el usuario en la base de datos
-- master para el login anterior
USE [master]
GO
CREATE USER [Prueba] FOR LOGIN [Prueba]
GO
-- Asigno el permiso de ejecucion al usuario
use [master]
GO
GRANT EXECUTE ON [sys].[xp_cmdshell]
TO [Prueba]
GO
Si ahora probamos veremos que es posible ejecutar el procedimiento almacenado xp_cmdshell sin ser administrador sin asignar permisos de CONTROL SERVER.
Veamos qué pasa si tenemos asignado solo el permiso de ejecución del procedimiento almacenado pero no existe la credencial.
Como administradores eliminamos la cuenta proxy:
EXEC sp_xp_cmdshell_proxy_account null
Probamos la ejecucion del procediemiento almacenado nuevamente con el usuario prueba
exec xp_cmdshell 'dir c:\*.*'
El resultado es:
Msg 15153, Level 16, State 1, Procedure xp_cmdshell, Line 1
The xp_cmdshell proxy account information cannot be retrieved or is invalid. Verify that the '##xp_cmdshell_proxy_account##' credential exists and contains valid information.
Conclusiones
- No es recomendable utilizar el procedimiento almacenado xp_cmdshell.
- Para poder ejecutarlo se requiere habilitar su ejecución en la configuración del SQL Server utilizando el procedimiento almacenado sp_configure.
- Si somos administradores podemos ejecutar el procedimiento xp_cmdshell el cual utiliza la cuenta de servicio del SQL Server
- Si no somos administradores utiliza la cuenta proxy que debe estar definida.
- Si no somos administradores solo debemos tener permiso de ejecución en el procedimiento almacenado xp_cmdshell y no hace falta asignar el permiso CONTROL SERVER como dice la ayuda.