Aviso de seguridad de Microsoft: una vulnerabilidad en SQL Server podría permitir la ejecución remota de código


INTRODUCCIÓN


Microsoft ha publicado un aviso de seguridad sobre una vulnerabilidad en Microsoft SQL Server que podría permitir la ejecución del código. El aviso de seguridad contiene información adicional relacionada con la seguridad. Para ver el aviso de seguridad, visite el siguiente sitio Web de Microsoft: Este artículo incluye una secuencia de comandos VB que puede utilizar para aplicar una solución a todas las instancias de SQL Server que se estén ejecutando en un equipo local.

EJEMPLO DE UNA SECUENCIA DE COMANDOS VB QUE PUEDE UTILIZAR PARA APLICAR LA SOLUCIÓN


Puede utilizar esta secuencia de comandos VB para denegar el permiso de ejecución a la función pública en el procedimiento almacenado extendido sp_replwritetovarbin en todas las versiones afectadas del SQL Server que se ejecutan en el equipo local.

Microsoft proporciona ejemplos de programación con fines ilustrativos únicamente, sin ninguna garantía, ya sea expresa o implícita. Esto incluye, entre otras, las garantías implícitas de comerciabilidad e idoneidad para un fin determinado. En este artículo se da por supuesto que ya conoce el lenguaje de programación que se muestra, así como las herramientas empleadas para crear y depurar procedimientos. Los ingenieros de soporte técnico de Microsoft pueden ayudar a explicar la funcionalidad de un procedimiento en particular. Sin embargo, no modificarán estos ejemplos para proporcionar una funcionalidad adicional ni crearán procedimientos que se adapten a sus necesidades específicas.


Copie este código en un archivo de texto, guarde el archivo utilizando un archivo con la extensión .vbs y ejecute el archivo de la secuencia de comandos utilizando CScript.exe. La secuencia de comandos recorre las instancias SQL Server que se encuentran en ejecución en el equipo local y aplica la solución en las versiones afectadas. Para aplicar la solución temporal, debe ser miembro de la función sysadmin en cada instancia de SQL Server. Si usted no dispone de una cuenta Windows que le haga miembro de la función sysadmin en todos los servidores afectados que se están ejecutando SQL Server, deberá ejecutar esta secuencia de comandos desde múltiples cuentas. Si está utilizando una cuenta del administrador de Windows que es miembro de la función sysadmin en Windows Server 2008 y en Windows Vista, debe ejecutar esta secuencia de comandos desde un símbolo de sistema elevado.
'*************************************************************************************
'Descripción: esta secuencia de comandos recorre las instancias de SQL Server que se están ejecutando
' y deniega el permiso de ejecución a la función pública en sp_replwritetovarbin en todas
' las versiones afectadas.
' ÉSTA ES UNA SOLUCIÓN TEMPORAL Y NO DEBE UTILIZARSE EN CASO DE QUE
' SE PROPORCIONE E INSTALE UNA ACTUALIZACIÓN DE SEGURIDAD.
'*************************************************************************************

OPTION EXPLICIT
ON ERROR RESUME NEXT

' Constant values
CONST EXIT_SUCCESS = 0
CONST EXIT_FAILURE = 1
CONST EXIT_NOINSTANCES = -1
CONST DEFAULTNAMESPACE = "root\default"
CONST STDREGPROV = "stdregprov"
CONST HKEY_LOCAL_MACHINE = &H80000002
CONST REG_MULTI_SZ = 7
CONST REG_SZ = 1
CONST adCmdText = 1


Call VBMain()

Function VBMain()
Err.Clear
ON ERROR RESUME NEXT

Dim sInstances(), strInstance, i, TotalCount
VBMain = EXIT_SUCCESS
If GetInstances(sInstances, TotalCount) = FALSE Then
WScript.Quit EXIT_FAILURE
End If

If IsEmptyNull(sInstances) Then
WScript.Echo "INFO: No existe ninguna instancia."
VBMain = EXIT_NOINSTANCES
Exit Function
End If

For i = 0 To TotalCount-1
strInstance = sInstances(i,0)
GetFullInstance strInstance, sInstances(i,1)
If ApplyFix(sInstances(i,0), strInstance) = FALSE Then
WScript.Echo "ERROR: No se puedo aplicar la solución en " + sInstances(i,0) + "." + vbCRLF
VBMain = EXIT_FAILURE
End If
Next

WScript.Echo "INFO: el proceso de todas las instancias de SQL que se están ejecutando se ha completado".
End Function

Function GetInstances(ByRef sInstances, ByRef TotalCount)
Err.Clear
ON ERROR RESUME NEXT

Dim sInstances1, sInstances2, i
Dim instCount1, instCount2
GetInstances = FALSE

If NOT GetRegValue ("", HKEY_LOCAL_MACHINE, "Software\Microsoft\Microsoft SQL Server", "InstalledInstances", sInstances1, REG_MULTI_SZ, TRUE) Then
WScript.Echo "ERROR: error al leer las instancias SQL instaladas en el equipo."
Exit Function
End If

sInstances2 = NULL
If IsOs64Bit() = TRUE Then
If NOT GetRegValue ("", HKEY_LOCAL_MACHINE, "Software\Microsoft\Microsoft SQL Server", "InstalledInstances", sInstances2, REG_MULTI_SZ, FALSE) Then
WScript.Echo "ERROR: error al leer las instancias SQL instaladas en el equipo."
Exit Function
End If
End If

If IsEmptyNull(sInstances1) AND IsEmptyNull(sInstances2) Then
+WScript.Echo "INFO: no existe ninguna instancia".
WScript.Quit EXIT_SUCCESS
End If

instCount1 = 0
instCount2 = 0
TotalCount = 0
If IsEmptyNull(sInstances1) = FALSE Then
instCount1 = UBound(sInstances1) + 1
TotalCount = instCount1
End If

If IsEmptyNull(sInstances2) = FALSE Then
instCount2 = UBound(sInstances2) + 1
TotalCount = TotalCount + instCount2
End If

ReDim PRESERVE sInstances(TotalCount,1)
if instCount1 > 0 Then
For i = 0 To UBound(sInstances1)
sInstances(i,0) = sInstances1(i)
sInstances(i,1) = True
Next
End If
If instCount2 >0 Then
For i = 0 To UBound(sInstances2)
sInstances(i+instCount1,0) = sInstances2(i)
sInstances(i+instCount1,1) = FALSE
Next
End If
GetInstances = TRUE
End Function


Function ApplyFix(ByVal strInstance, ByVal strServerName)
Err.Clear
ON ERROR RESUME NEXT

Dim objConn, objCmd, objCmd1, objRS, objRS1
Dim strCommand, strConn
Dim strBuildVersion, strProductLevel, bApplyFix

' Initialize return value
ApplyFix = FALSE

strConn = "Provider=sqloledb;Initial Catalog=master;Integrated Security=SSPI;Data Source=" + strServerName + ";"
' La comprobación de errores se ha mantenido de manera intencionada para reducir el código
Set objConn = CreateObject("ADODB.Connection")
Set objCmd = CreateObject("ADODB.Command")
Set objCmd1 = CreateObject("ADODB.Command")

' Abrir una conexión a la base de datos maestra
objConn.Open strConn
If ErrorOccurred("Error: no se pudo establecer la conexión a " + strInstance) Por consiguiente,
Set objConn = Nothing
Exit Function
End If

' Valide la versión antes de aplicar la solución
strCommand = "select SERVERPROPERTY('ProductVersion') as version, SERVERPROPERTY('productlevel') as productlevel"
objCmd.ActiveConnection = objConn
objCmd.CommandType = adCmdText
objCmd.CommandText = strCommand

Set objRS = objCmd.Execute()
If ErrorOccurred("ERROR: no se pudo ejecutar """ + strCommand + """ on " + strInstance) = TRUE Por consiguiente,
objConn.Close()
Set objConn = Nothing
ApplyFix = FALSE
Exit Function
End If

strBuildVersion = objRS("version")
strProductLevel = UCase(objRS("productlevel"))

bApplyFix = FALSE
' Aplique la solución únicamente en las versiones SQL 2000 y SQL 2005 (RTM, SP1 y SP2)
If (CInt(Mid(strBuildVersion,1,1)) = 8) Then
bApplyFix = TRUE
ElseIf CInt(Mid(strBuildVersion,1,1)) = 9 AND (StrComp(strProductLevel,"RTM") = 0 OR StrComp(strProductLevel,"SP1") = 0 OR StrComp(strProductLevel,"SP2") = 0) Then
bApplyFix = TRUE
End If

If bApplyFix = TRUE Then
strCommand = "deny execute on sp_replwritetovarbin to public"
objCmd1.ActiveConnection = objConn
objCmd1.CommandType = adCmdText
objCmd1.CommandText = strCommand
Set objRS1 = objCmd1.Execute()
If ErrorOccurred("ERROR: no se pudo ejecutar """ + strCommand + """ on " + strInstance) = FALSE Then
WScript.Echo "INFO: se aplicó correctamente la solución en " + strInstance + " (" + strBuildVersion + ")." + vbCRLF
ApplyFix = TRUE
End If
Else
WScript.Echo "INFO: omisión de la recopilación de información para " + strInstance + " (" + strBuildVersion + ") ya que esta instancia no es vulnerable". + vbCRLF
ApplyFix = TRUE
End If

objConn.Close()
Set objConn = Nothing
Set objCmd = Nothing
Set objCmd1 = Nothing
Set objRS = Nothing
Set objRS1 = Nothing
End Function

Private Function GetRegValue (ByVal strMachineName, ByVal hMainKey, ByVal strPath, ByVal strValueName, ByRef strValue, ByVal iValueType, ByVal b32bit)
Err.Clear
ON ERROR RESUME NEXT

Dim objLocator, objServices, objRegistry, objCtx
Dim sMultiStrings, lRc
GetRegValue = TRUE

'Conéctese al servicio WMI y obtenga un objeto para la clase STDREGPROV.
Set objCtx = CreateObject("WbemScripting.SWbemNamedValueSet")
If b32bit = TRUE Then
objCtx.Add "__ProviderArchitecture", 32
Else
objCtx.Add "__ProviderArchitecture", 64
End If
objCtx.Add "__RequiredArchitecture", TRUE
set objLocator = createobject("wbemscripting.swbemlocator")
set objServices = objLocator.connectserver(strMachineName,DEFAULTNAMESPACE, "", "",,,,objCtx)
set objRegistry = objServices.get(STDREGPROV)
If ErrorOccurred ("ERROR: No se pudo conectar al espacio de nombres " + DEFAULTNAMESPACE) Then
GetRegValue = FALSE
Exit Function
End If

lRc = 0
Select Case iValueType
' We only care about REG_MULTI_SZ
Case REG_MULTI_SZ
strValue = ""
lRC = objRegistry.GetMultiStringValue(hMainKey, strPath, strValueName, sMultiStrings)
strValue = sMultiStrings
Case REG_SZ
strValue = ""
lRC = objRegistry.GetStringValue(hMainKey, strPath, strValueName, strValue)
Case Else
GetRegValue = FALSE
End Select

If lRc = 2 Or lRc = 3 Then
GetRegValue = TRUE
strValue = ""
ElseIf Err.Number OR lRc <> 0 Then
GetRegValue = FALSE
End If

Set objLocator = Nothing
Set objServices = Nothing
Set objRegistry = Nothing
End Function

Function IsEmptyNull(sCheck)
IsEmptyNull = FALSE
If IsObject(sCheck) Then Exit Function
If IsArray(sCheck) Then Exit Function
If VarType(sCheck) = vbEmpty Then IsEmptyNull = TRUE : Exit Function
If VarType(sCheck) = vbNull Then IsEmptyNull = TRUE : Exit Function
If sCheck = "" Then IsEmptyNull = TRUE
End Function

Private Function ErrorOccurred (ByVal strIn)
If Err.Number <> 0 Then
WScript.Echo strIn
WScript.Echo "ERROR: 0x" & Err.Number & " - " & Err.Description
Err.Clear
ErrorOccurred = TRUE
Else
ErrorOccurred = FALSE
End If
End Function

Function IsOs64Bit()
Err.Clear
ON ERROR RESUME NEXT

Dim objProc
Set objProc = GetObject("winmgmts:root\cimv2:Win32_Processor='cpu0'")
If objProc.Architecture = 0 Then
IsOs64Bit = FALSE
Else
IsOs64Bit = TRUE
End If
End Function

Function GetFullInstance (ByRef strInstanceName, ByVal b32bit)
Err.Clear
ON ERROR RESUME NEXT

Dim objServices, objClusters, objCluster
Dim strMacName, isEmpty
Dim strKey, strInstID

GetFullInstance = TRUE

If strComp(UCase(strInstanceName), "MICROSOFT##SSEE", 1) = 0 Then
strInstanceName = "np:\\.\pipe\mssql$microsoft##ssee\sql\query"
Exit Function
End if

strMacName = ""
Set objServices = GetObject("winmgmts:root\cimv2")

' Consultar el servicio de clúster
Set objClusters = objServices.ExecQuery ("select * from win32_service where Name='ClusSvc' AND Started = TRUE")
isEmpty = TRUE
If Err.Number = 0 Then
For each objCluster in objClusters
isEmpty = FALSE
Next
End If

Set objServices = Nothing
Set objClusters = Nothing

If isEmpty = TRUE Then
strInstanceName = BuildInstanceName (".", strInstanceName)
Exit Function
End If

' Si logramos llegar hasta aquí, significa que el equipo es un nodo de clúster.
' Así que solicite el registro para determinar si la instancia SQL está agrupada o no.
' Para SQL 2000 solicite el valor siguiente
' HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\<InstanceName>\Cluster
' ClusterName
strKey = "SOFTWARE\Microsoft\Microsoft SQL Server\" + strInstanceName + "\Cluster"
GetRegValue "", HKEY_LOCAL_MACHINE, strKey, "ClusterName", strMacName, REG_SZ, b32bit

If StrComp(strMacName, "") <> 0 Then
strInstanceName = BuildInstanceName (strMacName, strInstanceName)
Exit Function
End If

strKey = "SOFTWARE\Microsoft\" + strInstanceName + "\Cluster"
GetRegValue "", HKEY_LOCAL_MACHINE, strKey, "ClusterName", strMacName, REG_SZ, b32bit

If StrComp(strMacName, "") <> 0 Then
strInstanceName = BuildInstanceName (strMacName, strInstanceName)
Exit Function
End If

' Intente solicitar el valor del registro para las instancias 2005/2008
'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\Instance Names\SQL
' RegValue = InstanceName
strInstID = ""
strKey = "SOFTWARE\Microsoft\Microsoft SQL Server\Instance Names\SQL"
GetRegValue "", HKEY_LOCAL_MACHINE, strKey, strInstanceName, strInstID, REG_SZ, b32bit

If StrComp(strInstID, "") = 0 Then
' Si esta clave no existe, volverá a ser una instancia local SQL 2000
strInstanceName = BuildInstanceName (".", strInstanceName)
Exit Function
End If

strKey = "SOFTWARE\Microsoft\Microsoft SQL Server\" + strInstID + "\Cluster"
GetRegValue "", HKEY_LOCAL_MACHINE, strKey, "ClusterName", strMacName, REG_SZ, b32bit

If StrComp(strMacName, "") = 0 Then
strMacName = "."
End If

strInstanceName = BuildInstanceName (strMacName, strInstanceName)
End Function

Function BuildInstanceName (ByVal strMachineName, ByVal strInstanceName)
Dim strPrefix

strPrefix = ""
If StrComp(strMachineName, ".") = 0 Then
strPrefix = "lpc:"
End If

If strComp(UCase(strInstanceName), "MSSQLSERVER", 1) = 0 Then
BuildInstanceName = strPrefix + strMachineName
Else
BuildInstanceName = strPrefix + strMachineName + "\" + strInstanceName
End if
End Function
Para obtener más información acerca de CScript.exe, visite el siguiente sitio Web de Microsoft: Nota: le recomendamos que no utilice esta secuencia de comandos si ha instalado la actualización de seguridad que se le ha proporcionado.

PROBLEMAS CONOCIDOS QUE PUEDEN PRODUCIRSE AL EJECUTAR ESTA SECUENCIA DE COMANDOS


Problema 1

Cuando ejecuta la secuencia de comandos, recibirá el mensaje de error siguiente:
ERROR: No se puede ejecutar "denegar ejecutar en sp_replwritetovarbin para público" en <instancename>.
ERROR: 0x-2147217900 - no se puede encontrar el objeto 'sp_replwritetovarbin', porque no existe o no tiene permiso.
ERROR: no se puede aplicar la solución en <nombreInstancia>.

Causa 1

Recibirá este mensaje de error si no tiene los permisos necesarios para aplicar el cambio. Este mensaje de error indica que se le permite conectarse correctamente a la instancia "<instancename>."


Este mensaje de error suele ocurrir en SQL Server Express en el que el grupo de "Built-In\Users" tiene un inicio de sesión en la base de datos de forma predeterminada. Sin embargo, este grupo no es miembro de la función sysadmin.

Este mensaje de error podría producirse también si se interrumpe el procedimiento sp_replwritetovarbin. Esta es la recomendación de un informe de otros fabricantes. No se recomienda colocar el procedimiento almacenado. En su lugar, le recomendamos que aplique esta solución.

Resolución 1

Asegúrese de que la cuenta con la que se conecta sea miembro de la función sysadmin en esa instancia de la base de datos. Si la cuenta no es miembro, debe agregar el usuario con el que se está conectando a la función sysadmin o bien, utilizar otra cuenta de usuario. Para SQL Server 2005 y versiones anteriores, el grupo "Built-in\Administrators" es miembro de la función sysadmin de forma predeterminada. Cuando ejecuta esta secuencia de comandos en Windows Vista o en Windows Server 2008, asegúrese de que se ejecute desde un símbolo del sistema con privilegios elevados.

Problema 2

Si ejecuta esta secuencia de comandos en SQL Server 2005, recibirá el siguiente mensaje de error:
Error: no se puede conectar a <nombreInstancia>
ERROR: 0x-2147217843 - error en el inicio de sesión para el usuario '<usuario>'.
ERROR: no se puede aplicar la solución en <nombreInstancia>.

Causa 2

Recibirá este mensaje de error si no se pudo conectar a la instancia "<nombreInstancia>" incluso si existe dicha instancia.


Este mensaje de error suele producirse cuando se conecta a Windows Internal Database o a las instancias de Microsoft SQL Server 2000 Desktop Edition (Windows). Normalmente, no hay cuentas de usuario que tengan inicios de sesión a estas bases de datos.

Resolución 2

Asegúrese de que la cuenta que utiliza para ejecutar la secuencia de comandos tenga un inicio de sesión a la base de datos que sea miembro de la función sysadmin.

No es recomendable que agregue usuarios individuales a Windows Internal Database y a bases de datos de Microsoft SQL Server 2000 Desktop Edition (Windows). Si lo hace, los usuarios que agregue pueden interferir en el funcionamiento normal de estas bases de datos. En este caso, asegúrese de conectarse desde una cuenta que sea miembro de la función sysadmin. El grupo "Built-in\Administrators" de Windows es normalmente miembro de la función sysadmin de forma predeterminada en SQL Server 2005 y en versiones anteriores. Cuando ejecuta esta secuencia de comandos en Windows Vista o en Windows Server 2008, asegúrese de ejecutarla desde un símbolo del sistema con privilegios elevados.

Problema 3

Puede que observe una instancia de una base de datos con nombre MICROSOFT##SSEE. Sin embargo, no ha instalado esta base de datos.

Causa 3

Esta base de datos es la Windows Internal Database, también conocida como "SQL Server Embedded Edition" o, a veces, como "Windows Internal Database" o "Microsoft SQL Server 2000 Desktop Edition (Windows)". Se instala con algunos productos de Microsoft, como SharePoint Services.

Resolución 3

La secuencia de comandos de la solución está diseñada para que funcione con Windows Internal Database. No es necesaria ninguna acción por su parte.

Algunas aplicaciones no eliminan Windows Internal Database cuando no están instaladas.
Para obtener más información acerca de cómo eliminar Windows Internal Database, haga clic en el número de artículo siguiente para verlo en Microsoft Knowledge Base:
920277 Windows Internal Database no se muestra en ninguna herramienta como Agregar o quitar programas y no se elimina cuando borra Windows SharePoint Services 3.0 de su equipo.

Problema 4

Cuando ejecuta la secuencia de comandos, recibirá el mensaje de error siguiente:

Error: No se puede conectar a .\<instancename>
ERROR: 0x-2147467259 - [DBNETLIB][ConnectionOpen (Connect()).]El servidor SQL Server no existe o se denegó el acceso

Causa 4

Usted va a recibir este mensaje de error si se cumplen las condiciones siguientes:
  • Posee una versión de 32 bits de SQL Server 2000 instalado en un sistema operativo de 64 bits.
  • Tiene una versión de 64 bits de SQL Server 2005 o de SQL Server 2008 instalado en el equipo.

Este mensaje de error sucede cuando la secuencia de comandos que se utiliza en la versión de 64 bits del archivo dbmslpcn.dll. Esta versión no se puede comunicar con las instancias WoW de SQL Server 2000.

Resolución 4

Utilice la versión de 32 bits del archivo cscript.exe desde la carpeta %WINDOWS%\SysWOW64 para iniciar la secuencia de comandos. Esto carga la versión de 32 bits del archivo dbmslpcn.dll que puede detectar las instancias WoW.

Referencias


Para obtener más información sobre cómo identificar la versión y edición de SQL Server, haga clic en el número de artículo siguiente para verlo en Microsoft Knowledge Base:
321185 Cómo identificar la versión y la edición de SQL Server

Más información


En la tabla siguiente se enumeran las revisiones técnicas significativas de este artículo. El número de revisión y la fecha de revisión más reciente del artículo podrían indicar revisiones estructurales o revisiones editoriales menores que no se incluyen en la tabla.
FechaRevisiones
31 de diciembre de 2008Incluye una secuencia de comandos actualizada que detecta las instancias de clúster de conmutación por error en SQL Server.
30 de diciembre de 2008Incluye una secuencia de comandos actualizada que detecta las versiones de 32 bits de SQL Server que se están ejecutando en las versiones de Windows de 64 bits.