Inicio > Base de datos > Cómo ejecutar un comando de DOS cuando xp_cmdshell está deshabilitado

Cómo ejecutar un comando de DOS cuando xp_cmdshell está deshabilitado

domingo, 17 de marzo de 2024 Dejar un comentario Ir a comentarios

Por razones de seguridad muchos sitios deshabilitan el procedimiento almacenado extendido xp_cmdshell, que se utiliza para ejecutar comandos de DOS o ejecutables. Cuando realmente tienes que ejecutar un comando de DOS o un ejecutable desde un procedimiento almacenado ¿cómo puedes solucionar esta limitación, sin colapsar la seguridad?.

Solución

Deshabilitar xp_cmdshell es más o menos una práctica de seguridad estándar y en SQL Server 2008 esta desactivado por defecto. Esa es una buena idea, porque xp_cmdshell permite ejecutar comandos de DOS o ejecutar con los privilegios del motor de base de datos SQL Server, creando una vulnerabilidad de «privilegios elevados». Los hackers han saben ejecutar comandos como «format c:» por medio de este agujero de seguridad.

Cuando SQL Server se ejecuta con un usuario administrador o con la cuenta de sistema cualquiera que sea capaz de usar xp_cmdshell puede ejecutar cualquier programa o comandos de DOS. Esa es una buena razón para ejecutar SQL Server como un usuario de dominio con privilegios limitados. Esto limita a cualquier hacker a los privilegios concedidos a ese usuario. Esto es aún más de lo que quieres dejar un hacker tener acceso, pero es mejor que los permisos administrativos.

Con el xp_cmdshell deshabilitado, tiendo a ejecutar en situaciones en las que SQL Server tiene que hacer algo fuera de su propio entorno que simplemente no se puede hacer con T-SQL. El ejemplo de este artículo ejecuta el comando attrib del DOS, el cual cambia los atributos en los archivos. Yo lo uso para hacer ciertos archivos de entrada como de sólo lectura después de que hayan sido procesados. Con el xp_cmdshell habilitado ejecute un comando similar a éste:

exec xp_cmdshell 'attrib "c:\temp\foo.bar" +r'

La +r indica que el atributo de sólo lectura esta activado.

Para ver los atributos de un archivo desde el símbolo del sistema CMD ejecuta el comando sin ninguna opción de esta manera:

c:\temp>attrib foo.bar
--the output would look like this
A R C:\temp\foo.bar

La A representa el atributo de archivo, R el atributo de sólo lectura. También existen atributos S para el sistema H para los ocultos para cada archivo. La ausencia de la letra muestra que S y H no están activadas.

Para ejecutar seguramente el comando attrib he creado un procedimiento almacenado personalizado SQLCLR dedicado a esta tarea. Nombre el procedimiento almacenado file_attrib_dos_cmd y lo he construido con un proyecto SQLCLR de Visual Studio 2010. Empiezo por la creación del proyecto y seleccione una base de datos para conectarse en el dialogo «Agregar base de datos de referencia». Luego agregé el procedimiento almacenado al proyecto con el comando de menú «Proyecto/Añadir un procedimiento almacenado…» y le doy el mismo nombre file_attrib_dos_cmd. Para permitir la ejecución del método del framework Process.Start el proyecto debe ser marcado como «UnSafe» en la ficha de Base de datos de las propiedades del proyecto. un procedimiento SQLCLR unsafe no es más «inseguro» que un procedimiento almacenado extendido y eso es lo que file_attrib_dos_cmd sustituye.

Aquí está el código:

using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using System.IO;
using System.Diagnostics;
using System.Text;

public partial class StoredProcedures
{

    [Microsoft.SqlServer.Server.SqlProcedure]
    public static void file_attrib_dos_cmd(SqlString DirectoryPath
                                          ,SqlString FileSpec
                                          ,SqlString arguments)
    {
        // Make sure the file exists
        string FullPath = Path.Combine(DirectoryPath.Value, FileSpec.Value);
        FileInfo fi = new FileInfo(FullPath);
        if (!fi.Exists)
        {
            using (SqlCommand cmd = new SqlCommand())
            {
                cmd.CommandText = string.Format(
                         "raiserror('File ->{0}<- is not found.',16,1)",
                           FileSpec.Value);
                try { SqlContext.Pipe.ExecuteAndSend(cmd); }
                catch { return; }
            }
        }
        // ProcessStartInfo to run the DOS command attrib
        ProcessStartInfo pPStartInfo = new ProcessStartInfo("cmd.exe");
        pPStartInfo.WorkingDirectory = DirectoryPath.Value;
        pPStartInfo.UseShellExecute = true;
        // quote the file name incase it has spaces
        pPStartInfo.Arguments =string.Format(@" /C attrib "{0}""{1}",  
                                   FullPath, arguments.Value);
        // start a new process and wait for it to exit
        Process p = new Process();
        p.StartInfo = pPStartInfo;        
        p.Start();
        p.WaitForExit();
   
    }
};

El método comprueba de que el archivo existe. Si no es así, arroja un error de SQL de una manera que funciona bien en el T-SQL. A continuación, construye una estructura ProcessStartInfo que soporta cmd.exe como el nombre del comando a ejecutar. Si quisiéramos ejecutar un archivo ejecutable, puede ser ejecutado directamente, pero cmd.exe es el programa que implementa comandos de DOS. Los argumentos tienen el formato para el comando attrib y se inicia el proceso y el procedimiento de espera que se complete el comando. Ejecutar el procedimiento no produce ninguna salida. He aquí un comando más habitual:

exec dbo.file_attrib_dos_cmd 'c:\temp\', 'foo.bar', '+r';
GO 
Command(s) completed successfully.

Una alternativa más compleja habría sido escribir un procedimiento almacenado SQLCLR que realice los cambios de atributos directamente. Sin embargo, eso habría sido más complejo y este método es fácilmente extensible a otros comandos, así como a la ejecución de programas ejecutables.

Notas

  • Desactivar xp_cmdshell si es posible.
  • Utiliza procedimientos SQLCLR que son muy específicos para tu necesidad a lograr.
  • Utiliza un nombre único para el procedimiento CLR en lugar de un nombre genérico como «xp_cmdshell2»

Comparte y diviertete:
  • Print
  • Digg
  • StumbleUpon
  • del.icio.us
  • Facebook
  • Yahoo! Buzz
  • Twitter
  • Google Bookmarks
  • BarraPunto
  • Bitacoras.com
  • BlinkList
  • Blogosphere
  • Live
  • Meneame
  • MSN Reporter
  • MySpace
  • RSS
  • Suggest to Techmeme via Twitter
  • Technorati
  • LinkedIn
  • email
  • FriendFeed
  • PDF
  • Reddit
  • Wikio IT
  • Add to favorites
  • blogmarks
Top Footer