INLEDNING
Microsoft har gett ut ett säkerhetsmeddelande för ett säkerhetsproblem i Microsoft SQL Server som möjliggör fjärrkörning av kod. Säkerhetsmeddelandet, som innehåller ytterligare säkerhetsrelaterad information, finns på följande Microsoft-webbplats:
http://www.microsoft.com/technet/security/advisory/961040.mspxDenna artikel innehåller ett VB-skript som kan användas för att tillämpa en lösning på alla instanser av SQL Server som körs på en lokal dator.
EXEMPEL PÅ ETT VB-SKRIPT SOM KAN ANVÄNDAS FÖR ATT TILLÄMPA LÖSNINGEN
Du kan använda detta VB-skript för att neka Public-rollen körbehörighet för den utökade lagrade sp_replwritetovarbin-proceduren i alla berörda versioner av SQL Server som körs på den lokala datorn.
Microsoft tillhandahåller programmeringsexempel enbart i förklarande syfte och gör inga utfästelser, varken uttryckligen eller underförstått. Detta omfattar men begränsas inte till underförstådd garanti för säljbarhet eller lämplighet för ett visst syfte. I denna artikel förutsätts att du känner till det programmeringsspråk som demonstreras och de verktyg som används för att skapa och felsöka procedurer. Microsofts supporttekniker kan förklara hur en viss procedur fungerar, men de ändrar inte exemplen för att utöka funktionerna och konstruera procedurer som motsvarar dina behov. Kopiera denna kod till en textfil, spara filen med filnamnstillägget .vbs och kör sedan skriptfilen med hjälp av CScript.exe. Skriptet upprepas för de instanser av SQL Server som körs på den lokala datorn, och lösningen används på de versioner som berörs. Du måste vara medlem av rollen sysadmin i varje instans av SQL Server för att kunna använda lösningen. Om du inte har ett Windows-konto som är medlem av rollen sysadmin på alla berörda servrar där SQL Server körs, måste du kanske köra skriptet från flera konton. I Windows Server 2008 och Windows Vista måste du köra skriptet från en kommandotolk med "förhöjd rättighet", om du använder ett Windows-administratörskonto som är medlem av rollen sysadmin.'*************************************************************************************
'Beskrivning: Detta skript upprepas i alla instanser av SQL Server som körs ' och nekar Public-rollen körbehörighet på sp_replwritetovarbin i alla ' berörda versioner. ' DETTA ÄR EN TILLFÄLLIG LÖSNING OCH BÖR INTE ANVÄNDAS OM EN SÄKERHETSUPPDATERING ' HAR GJORTS TILLGÄNGLIG OCH INSTALLERATS. '************************************************************************************* OPTION EXPLICIT ON ERROR RESUME NEXT ' Konstanta värden 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: Det finns inte några instanser." 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 "FEL: Det gick inte att använda lösningen på " + sInstances(i,0) + "." + vbCRLF VBMain = EXIT_FAILURE End If Next WScript.Echo "INFO: Alla SQL-instanser som körs har bearbetats." 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 "FEL:Det går inte att läsa SQL-instanser som är installerade på datorn." 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 "FEL:Det går inte att läsa SQL-instanser som är installerade på datorn." Exit Function End If End If If IsEmptyNull(sInstances1) AND IsEmptyNull(sInstances2) Then WScript.Echo "INFO: Det finns inte några instanser." 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 ' Initiera returvärde ApplyFix = FALSE strConn = "Provider=sqloledb;Initial Catalog=master;Integrated Security=SSPI;Data Source=" + strServerName + ";" ' Felkontroll utesluts avsiktligt för att koden ska bli kort Set objConn = CreateObject("ADODB.Connection") Set objCmd = CreateObject("ADODB.Command") Set objCmd1 = CreateObject("ADODB.Command") ' Öppna en anslutning till huvuddatabasen objConn.Open strConn If ErrorOccurred("Fel: Det gick inte att ansluta till " + strInstance) Then Set objConn = Nothing Exit Function End If ' Kontrollera versionen innan korrigeringen installeras strCommand = "välj SERVERPROPERTY('ProductVersion') som version, SERVERPROPERTY('productlevel') som produktnivå" objCmd.ActiveConnection = objConn objCmd.CommandType = adCmdText objCmd.CommandText = strCommand Set objRS = objCmd.Execute() If ErrorOccurred("FEL: Det gick inte att köra """ + strCommand + """ på " + strInstance) = TRUE Then objConn.Close() Set objConn = Nothing ApplyFix = FALSE Exit Function End If strBuildVersion = objRS("version") strProductLevel = UCase(objRS("productlevel")) bApplyFix = FALSE ' Lösningen ska endast användas på SQL 2000 och SQL 2005 (RTM, SP1 och 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 = "neka Public-rollen körbehörighet på sp_replwritetovarbin" objCmd1.ActiveConnection = objConn objCmd1.CommandType = adCmdText objCmd1.CommandText = strCommand Set objRS1 = objCmd1.Execute() If ErrorOccurred("FEL: Det gick inte att köra """ + strCommand + """ på " + strInstance) = FALSE Then WScript.Echo "INFO: Lösningen har installerats på " + strInstance + " (" + strBuildVersion + ")." + vbCRLF ApplyFix = TRUE End If Else WScript.Echo "INFO: Information för " + strInstance + " (" + strBuildVersion + ") samlas inte in, eftersom denna instans inte är sårbar." + 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 'Anslut till WMI och få ett objekt till STDREGPROV-klassen. 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 ("FEL: Det gick inte att ansluta till WMI-namnområde " + DEFAULTNAMESPACE) Then GetRegValue = FALSE Exit Function End If lRc = 0 Select Case iValueType ' Endast REG_MULTI_SZ är av intresse 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 "FEL: 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") ' Fråga klustertjänst 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 ' Om vi kommer hit innebär det att datorn är en klusternod. ' Låt oss därför förfråga registret för att fastställa om SQL-instansen är klustrad. ' Förfråga följande värde för SQL 2000 ' HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\<Instansnamn>\Cluster ' Klusternamn strKey = "SOFTWARE\Microsoft\Microsoft SQL Server\" + strInstanceName + "\Cluster" GetRegValue "", HKEY_LOCAL_MACHINE, strKey, "Klusternamn", 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, "Klusternamn", strMacName, REG_SZ, b32bit If StrComp(strMacName, "") <> 0 Then strInstanceName = BuildInstanceName (strMacName, strInstanceName) Exit Function End If ' Låt oss försöka förfråga registervärdet för 2005/2008-instanser '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 ' Om denna nyckel inte finns, återgå som en lokal SQL 2000-instans strInstanceName = BuildInstanceName (".", strInstanceName) Exit Function End If strKey = "SOFTWARE\Microsoft\Microsoft SQL Server\" + strInstID + "\Cluster" GetRegValue "", HKEY_LOCAL_MACHINE, strKey, "Klusternamn", 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
Mer information om CScript.exe finns på följande Microsoft-webbplats:
http://technet.microsoft.com/en-us/library/bb490887.aspxObs! Vi rekommenderar att du inte använder detta skript om en säkerhetsuppdatering har tillhandahållits och du har installerat den.
KÄNDA PROBLEM SOM KAN UPPSTÅ VID KÖRNING AV DETTA SKRIPT
Problem 1
När skriptet körs visas följande felmeddelande:
FEL: Det gick inte att köra "neka Public-rollen körbehörighet på sp_replwritetovarbin" på <instansnamn>
FEL: 0x-2147217900 - Det går inte att hitta objektet 'sp_replwritetovarbin'. Objektet finns inte eller så har du inte den behörighet som krävs. FEL: Det gick inte att använda lösningen på <instansnamn>.Orsak 1
Detta felmeddelande visas om du inte har den behörighet som krävs för att göra ändringen. Felmeddelandet anger att du kunde logga in på instansen "<instansnamn>".
Detta felmeddelande förekommer vanligen i SQL Server Express, där gruppen "Built-In\Users" har ett inloggningsnamn till databasen som standard. Denna grupp är emellertid inte medlem av rollen sysadmin. Felmeddelandet kan även förekomma om du har släppt proceduren sp_replwritetovarbin, vilket rekommenderades i en tredjepartsrapport. Vi rekommenderar inte att du släpper den lagrade proceduren, utan att du i stället använder denna lösning.Lösning 1
Se till att det konto du ansluter med är medlem av rollen sysadmin i denna instans av databasen. Om kontot inte är medlem lägger du till den användare du ansluter som till rollen sysadmin eller använder ett annat användarkonto. För SQL Server 2005 och tidigare är gruppen "Built-in\Administrators" medlem av rollen sysadmin som standard. När du kör detta skript i Windows Vista eller Windows Server 2008 måste du se till att köra det från en kommandotolk med "förhöjd behörighet".
Problem 2
Om du kör detta skript i SQL Server 2005 visas följande felmeddelande:
Fel: Det gick inte att ansluta till <instansnamn>
FEL: 0x-2147217843 - Inloggning misslyckades för användare '<användare>'. FEL: Det gick inte att använda lösningen på <instansnamn>.Orsak 2
Detta felmeddelande visas om du inte har kunnat ansluta till instansen "<instansnamn>", trots att den finns.
Felmeddelandet visas vanligen när du ansluter till Windows Internal Database eller till Microsoft SQL Server 2000 Desktop Edition (Windows)-instanser. Normalt har inga användarkonton inloggningsnamn för dessa databaser.Lösning 2
Se till att det konto du använder för att köra skriptet har ett databasinloggningsnamn som är medlem av rollen sysadmin.
Vi rekommenderar inte att du lägger till enskilda användare till Windows Internal Database och till Microsoft SQL Server 2000 Desktop Edition (Windows)-databaser. Om du gör detta kan de användare du lägger till störa den normala funktionen hos dessa databaser. I detta fall måste du se till att ansluta från ett konto som är medlem av rollen sysadmin. Gruppen "Built-in\Administrators" i Windows brukar i standardfallet vara medlem av rollen sysadmin i SQL Server 2005 och i tidigare versioner. När du kör detta skript i Windows Vista eller Windows Server 2008 måste du se till att köra det från en kommandotolk med "förhöjd behörighet".Problem 3
Det kan förekomma en instans av en databas med beteckningen MICROSOFT##SSEE, som du inte har installerat.
Orsak 3
Denna databas är Windows Internal Database, även kallad "SQL Server Embedded Edition" eller ibland "Windows Internal Database" eller "Microsoft SQL Server 2000 Desktop Edition (Windows)". Den installeras tillsammans med vissa produkter från Microsoft, däribland SharePoint Services.
Lösning 3
Lösningsskriptet är konstruerat för att fungera med Windows Internal Database, och du behöver inte vidta några åtgärder.
Vissa program tar inte bort Windows Internal Database när de avinstalleras. Om du vill veta mer om hur du tar bort Windows Internal Database, klickar du på följande artikelnummer och läser artikeln i Microsoft Knowledge Base:920277 Windows Internal Database visas inte i Lägg till eller ta bort program och tas inte bort när Windows SharePoint Services 3.0 tas bort från datorn (Länken kan leda till en webbplats som är helt eller delvis på engelska)
Problem 4
När skriptet körs visas följande felmeddelande:
Fel: Det gick inte att ansluta till .\<instansnamn> FEL: 0x-2147467259 - [DBNETLIB][ConnectionOpen (Connect()).]SQL Server finns inte eller åtkomst nekad
Orsak 4
Detta felmeddelande visas under följande förutsättningar:
-
En 32-bitars version av SQL Server 2000 är installerad i ett x64-bitars operativsystem.
-
En 64-bitars version av SQL Server 2005 eller SQL Server 2008 är installerad på datorn.
Detta felmeddelande visas när en 64-bitars version av filen dbmslpcn.dll används av skriptet. Denna version kan inte kommunicera med WoW-instanserna av SQL Server 2000.
Lösning 4
Använd 32-bitarsversionen av filen cscript.exe från mappen %WINDOWS%\SysWOW64 för att starta skriptet. Därmed läser du in 32-bitarsversionen av filen dbmslpcn.dll, som kan identifiera WoW-instanser.
Referenser
Om du vill veta mer om hur du tar reda på version och utgåva för SQL Server, klickar du på följande artikelnummer och läser artikeln i Microsoft Knowledge Base:
321185Identifiera version och utgåva för SQL Server (Länken kan leda till en webbplats som är helt eller delvis på engelska)
Mer Information
Viktiga tekniska revideringar av den här artikeln anges i följande tabell. Revisionsnummer och datum för senaste granskning i artikeln kan avspegla mindre redaktionella eller strukturella revideringar som inte ingår i tabellen.
Datum |
Revideringar |
---|---|
31 december 2008 |
Innehåller ett uppdaterat skript som identifierar SQL Server-instanser av kluster för växling vid fel. |
30 december 2008 |
Innehåller ett uppdaterat skript som identifierar 32-bitars versioner av SQL Server som körs i 64-bitars versioner av Windows. |