WPROWADZENIE
Firma Microsoft wydała dokument Security Advisory dotyczący luki w zabezpieczeniach programu Microsoft SQL Server umożliwiającej zdalne wykonywanie kodu. Zawiera on dodatkowe informacje związane z zabezpieczeniami. Aby przeczytać ten dokument, odwiedź następującą witrynę firmy Microsoft w sieci Web:
http://www.microsoft.com/poland/technet/security/advisory/961040.mspxNiniejszy artykuł zawiera skrypt w języku Visual Basic umożliwiający zastosowanie obejścia problemu we wszystkich działających wystąpieniach programu SQL Server na komputerze lokalnym.
PRZYKŁADOWY SKRYPT VISUAL BASIC UMOŻLIWIAJĄCY OBEJŚCIE PROBLEMU
Ten skrypt w języku Visual Basic odmawia uprawnienia do wykonywania roli publicznej (Public) w rozszerzonej procedurze składowanej sp_replwritetovarbin dla wszystkich wersji programu SQL Server, których dotyczy ten problem, uruchomionych na komputerze lokalnym.Firma Microsoft podaje przykłady programowania wyłącznie do celów informacyjnych, bez jakichkolwiek gwarancji wyrażonych wprost lub domyślnie. Dotyczy to także, ale nie ograniczając się do tego zapisu, gwarancji przydatności handlowej lub do określonego celu. W tym artykule zakłada się, że czytelnik zna prezentowany język programowania oraz narzędzia używane do tworzenia i debugowania procedur. Pracownicy pomocy technicznej firmy Microsoft mogą służyć pomocą, wyjaśniając funkcję konkretnej procedury. Nie będą jednak modyfikować tych przykładów ani dodawać żadnej funkcji i konstruować nowych procedur w celu dostosowania ich do konkretnych potrzeb użytkownika. Należy skopiować poniższy kod do pliku tekstowego, zapisać plik z rozszerzeniem vbs, a następnie uruchomić skrypt za pomocą programu CScript.exe. Skrypt będzie wykonywany (jako iteracja) kolejno dla wszystkich wystąpień programu SQL Server na komputerze lokalnym i spowoduje zastosowanie obejścia problemu w odpowiednich wersjach. Aby można było zastosować obejście, użytkownik musi mieć uprawnienia administratora systemu (rola sysadmin) w poszczególnych wystąpieniach programu SQL Server. W przypadku braku dostępu do konta systemu Windows z uprawnieniami roli sysadmin na wszystkich serwerach z uruchomionym programem SQL Server, których dotyczy problem, może być konieczne uruchomienie tego skryptu z kilku różnych kont. W systemach Windows Server 2008 i Windows Vista uruchomienie tego skryptu za pomocą konta administratora systemu Windows z uprawnieniami roli sysadmin wymaga podniesienia poziomu uprawnień w wierszu polecenia.
'*************************************************************************************'Opis: Ten skrypt będzie wykonywany (jako iteracja) kolejno dla wszystkich uruchomionych wystąpień programu SQL Server' i odmówi uprawnienia do wykonywania roli publicznej w procedurze sp_replwritetovarbin' dla wszystkich wersji, których dotyczy ten problem.' JEST TO TYLKO OBEJŚCIE PROBLEMU I NIE NALEŻY GO UŻYWAĆ W PRZYPADKU' UDOSTĘPNIENIA I ZAINSTALOWANIA AKTUALIZACJI ZABEZPIECZEŃ.'*************************************************************************************OPTION EXPLICITON ERROR RESUME NEXT' Wartości stałychCONST EXIT_SUCCESS = 0CONST EXIT_FAILURE = 1CONST EXIT_NOINSTANCES = -1CONST DEFAULTNAMESPACE = "root\default"CONST STDREGPROV = "stdregprov"CONST HKEY_LOCAL_MACHINE = &H80000002CONST REG_MULTI_SZ = 7CONST REG_SZ = 1CONST adCmdText = 1Call 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 "INFORMACJA: Brak wystąpień." 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 "BŁĄD: nie można zastosować obejścia dla wystąpienia " + sInstances(i,0) + "." + vbCRLF VBMain = EXIT_FAILURE End If Next WScript.Echo "INFORMACJA: Przetwarzanie wszystkich uruchomionych wystąpień programu SQL zostało zakończone."End FunctionFunction 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 "BŁĄD: nie można odczytać wystąpień programu SQL zainstalowanych na komputerze." 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 "BŁĄD: nie można odczytać wystąpień programu SQL zainstalowanych na komputerze." Exit Function End If End If If IsEmptyNull(sInstances1) AND IsEmptyNull(sInstances2) Then WScript.Echo "INFORMACJA: Brak wystąpień." 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 = TRUEEnd FunctionFunction ApplyFix(ByVal strInstance, ByVal strServerName) Err.Clear ON ERROR RESUME NEXT Dim objConn, objCmd, objCmd1, objRS, objRS1 Dim strCommand, strConn Dim strBuildVersion, strProductLevel, bApplyFix ' Inicjowanie wartości zwracanej ApplyFix = FALSE strConn = "Provider=sqloledb;Initial Catalog=master;Integrated Security=SSPI;Data Source=" + strServerName + ";" ' Sprawdanie błędów zostało celowo pominięte, aby nie przedłużać kodu Set objConn = CreateObject("ADODB.Connection") Set objCmd = CreateObject("ADODB.Command") Set objCmd1 = CreateObject("ADODB.Command") ' Otwieranie połączenia z wzorcem bazy danych objConn.Open strConn If ErrorOccurred("Błąd: nie można nawiązać połączenia z " + strInstance) Then Set objConn = Nothing Exit Function End If ' Sprawdzanie wersji przed zastosowaniem poprawki 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("BŁĄD: nie można wykonać polecenia """ + strCommand + """ dla " + strInstance) = TRUE Then objConn.Close() Set objConn = Nothing ApplyFix = FALSE Exit Function End If strBuildVersion = objRS("version") strProductLevel = UCase(objRS("productlevel")) bApplyFix = FALSE ' Zastosowanie obejścia tylko dla wersji SQL 2000 i SQL 2005 (RTM, SP1 i 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("BŁĄD: nie można wykonać polecenia """ + strCommand + """ dla " + strInstance) = FALSE Then WScript.Echo "INFORMACJA: pomyślnie zastosowano obejście dla wystąpienia " + strInstance + " (" + strBuildVersion + ")." + vbCRLF ApplyFix = TRUE End If Else WScript.Echo "INFORMACJA: pomijanie gromadzenia informacji dla wystąpienia " + strInstance + " (" + strBuildVersion + "), ponieważ nie dotyczy go problem." + vbCRLF ApplyFix = TRUE End If objConn.Close() Set objConn = Nothing Set objCmd = Nothing Set objCmd1 = Nothing Set objRS = Nothing Set objRS1 = NothingEnd FunctionPrivate 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 'Połączenie z usługą WMI i pobranie obiektu do klasy 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("BŁĄD: nie można nawiązać połączenia z obszarem nazw WMI " + DEFAULTNAMESPACE) Then GetRegValue = FALSE Exit Function End If lRc = 0 Select Case iValueType ' Chodzi tylko o wartość 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 = NothingEnd FunctionFunction 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 = TRUEEnd FunctionPrivate Function ErrorOccurred (ByVal strIn) If Err.Number <> 0 Then WScript.Echo strIn WScript.Echo "BŁĄD: 0x" & Err.Number & " - " & Err.Description Err.Clear ErrorOccurred = TRUE Else ErrorOccurred = FALSE End IfEnd FunctionFunction 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 IfEnd FunctionFunction 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") ' Query Cluster service 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 ' Osiągnięcie tego miejsca oznacza, że komputer jest węzłem klastrowanym. ' Dlatego należy wykonać kwerendę w rejestrze sprawdzającą, czy wystąpienie programu SQL jest klastrowane. ' Dla wersji SQL 2000 kwerenda powinna dotyczyć następującej wartości: ' HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\<nazwa_wystąpienia>\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 ' Kwerenda zwracająca wartości rejestru dla wystąpień programu SQL 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 ' Jeśli ten klucz nie istnieje, przyjmowane jest założenie, że jest to lokalne wystąpienie programu 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 FunctionFunction 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 ifEnd Function
Aby uzyskać więcej informacji o programie CScript.exe, odwiedź następującą witrynę firmy Microsoft w sieci Web:
http://technet.microsoft.com/en-us/library/bb490887.aspxUwaga Nie zaleca się korzystania z tego skryptu w przypadku zainstalowania wydanej aktualizacji zabezpieczeń.
ZNANE PROBLEMY MOGĄCE WYSTĄPIĆ PO URUCHOMIENIU TEGO SKRYPTU
Problem 1
Komunikat o błędzie po uruchomieniu skryptu:
BŁĄD: nie można wykonać polecenia "deny execute on sp_replwritetovarbin to public" dla <nazwa_wystąpienia> BŁĄD: 0x-2147217900 - Nie można odnaleźć obiektu „sp_replwritetovarbin”, ponieważ obiekt nie istnieje lub nie masz do niego uprawnień dostępu. BŁĄD: nie można zastosować obejścia dla wystąpienia <nazwa_wystąpienia>.
Przyczyna 1
Ten komunikat o błędzie pojawia się w przypadku braku uprawnień wymaganych do wprowadzenia zmiany. Oznacza on, że udało się pomyślnie zalogować do wystąpienia <nazwa_wystąpienia>.Ten błąd występuje zwykle w programie SQL Server Express, w którym grupa „Built-In\Users” ma domyślnie uprawnienia do logowania w bazie danych. Nie ma ona jednak uprawnień roli sysadmin. Ten komunikat o błędzie może także pojawić się po porzuceniu procedury sp_replwritetovarbin. Takie zalecenie zostało zgłoszone zewnętrznie. Firma Microsoft nie zaleca porzucania tej procedury składowanej. Zamiast tego zaleca się zastosowanie następującego rozwiązania.
Rozwiązanie 1
Upewnij się, że konto, z którego nawiązujesz połączenie, ma uprawnienia roli sysadmin w tym wystąpieniu bazy danych. Jeśli tak nie jest, dodaj nazwę użytkownika konta do grupy roli sysadmin lub użyj innego konta. W przypadku programu SQL Server 2005 i starszych wersji grupa „Built-in\Administrators” domyślnie należy do roli sysadmin. W systemach Windows Server 2008 i Windows Vista pamiętaj, aby uruchamiać ten skrypt z podniesionym poziomem uprawnień w wierszu polecenia.
Problem 2
Komunikat o błędzie po uruchomieniu skryptu w programie SQL Server 2005:
Błąd: nie można nawiązać połączenia z <nazwa_wystąpienia> BŁĄD: 0x-2147217843 - Logowanie użytkownika <użytkownik> nie powiodło się. BŁĄD: nie można zastosować obejścia dla wystąpienia <nazwa_wystąpienia>.
Przyczyna 2
Ten komunikat o błędzie pojawia się, gdy nie można połączyć się z wystąpieniem <nazwa_wystąpienia>, nawet jeśli to wystąpienie istnieje.Ten błąd występuje zwykle w przypadku połączenia z wystąpieniem wewnętrznej bazy danych systemu Windows lub bazy danych programu Microsoft SQL Server 2000 Desktop Edition (Windows). Najczęściej żadne konta użytkowników nie mają uprawnień do logowania do tych baz danych.
Rozwiązanie 2
Upewnij się, że konto, z którego uruchamiasz skrypt, ma uprawnienia do logowania w bazie danych na poziomie roli sysadmin. Nie zaleca się dodawania pojedynczych użytkowników do wewnętrznej bazy danych systemu Windows lub do bazy danych programu Microsoft SQL Server 2000 Desktop Edition (Windows). Dodanie użytkowników może zakłócić normalne działanie tych baz danych. W takim przypadku należy pamiętać, aby nawiązywać połączenie z konta należącego do grupy roli sysadmin. W programie SQL Server 2005 i starszych wersjach grupa „Built-in\Administrators” w systemie Windows zazwyczaj domyślnie należy do roli sysadmin. W systemach Windows Server 2008 i Windows Vista pamiętaj, aby uruchamiać ten skrypt z podniesionym poziomem uprawnień w wierszu polecenia.
Problem 3
Może pojawić się wystąpienie bazy danych o nazwie MICROSOFT##SSEE. Taka baza danych nie została jednak zainstalowana.
Przyczyna 3
Ta baza danych to wewnętrzna baza danych systemu Windows (inne jej nazwy to SQL Server Embedded Edition lub Microsoft SQL Server 2000 Desktop Edition). Jest ona instalowana wraz z niektórymi produktami firmy Microsoft, na przykład z programem SharePoint Services.
Rozwiązanie 3
Skrypt obejścia został zaprojektowany pod kątem współpracy z wewnętrzną bazą danych systemu Windows. Nie jest wymagana żadna akcja ze strony użytkownika. Niektóre aplikacje podczas dezinstalacji nie usuwają wewnętrznej bazy danych systemu Windows. Aby uzyskać więcej informacji dotyczących usuwania wewnętrznej bazy danych systemu Windows, kliknij następujący numer artykułu w celu wyświetlenia tego artykułu z bazy wiedzy Microsoft Knowledge Base:
920277 Wewnętrzna baza danych systemu Windows nie jest wymieniona na liście narzędzia Dodaj lub usuń programy i nie jest usuwana po usunięciu z komputera programu Windows SharePoint Services 3.0 (j. ang.)
Problem 4
Komunikat o błędzie po uruchomieniu skryptu:
Błąd: nie można nawiązać połączenia z .\<nazwa_wystąpienia>BŁĄD: 0x-2147467259 - [DBNETLIB][ConnectionOpen (Connect()).]Serwer SQL nie istnieje lub odmówiono do niego dostępu.
Przyczyna 4
Ten komunikat o błędzie jest wyświetlany, gdy są spełnione następujące warunki:
-
W 64-bitowym systemie operacyjnym jest zainstalowana 32-bitowa wersja programu SQL Server 2000.
-
Na komputerze jest zainstalowana 64-bitowa wersja programu SQL Server 2005 lub SQL Server 2008.
Ten błąd występuje, gdy skrypt używa 64-bitowej wersji pliku dbmslpcn.dll. Ta wersja nie komunikuje się z wystąpieniami programu SQL Server 2000 w trybie WoW.
Rozwiązanie 4
Należy uruchomić skrypt przy użyciu 32-bitowej wersji pliku cscript.exe z folderu %WINDOWS%\SysWOW64. Zostanie wówczas załadowana 32-bitowa wersja pliku dbmslpcn.dll, która wykrywa wystąpienia w trybie WoW.
Materiały referencyjne
Aby uzyskać więcej informacji dotyczących sposobu ustalania wersji i wydania programu SQL Server, kliknij następujący numer artykułu w celu wyświetlenia tego artykułu z bazy wiedzy Microsoft Knowledge Base:
321185 JAK: Identyfikowanie wersji i wydania dodatku Service dla programu SQL Server
Więcej informacji
W poniższej tabeli wymieniono ważne poprawki techniczne w tym artykule. Numer poprawki i data ostatniej korekty tego artykułu mogą dotyczyć drobnych poprawek redakcyjnych lub strukturalnych, które nie zostały wymienione w tabeli.
|
Data |
Poprawki |
|---|---|
|
31 grudnia 2008 |
Zaktualizowany skrypt wykrywa wystąpienia programu SQL Server w ramach klastra pracy awaryjnej. |
|
30 grudnia 2008 |
Zaktualizowany skrypt wykrywa 32-bitowe wersje programu SQL Server działające w 64-bitowych wersjach systemu Windows. |