使用 Microsoft 登入
登入或建立帳戶。
您好:
選取其他帳戶。
您有多個帳戶
選擇您要用來登入的帳戶。

簡介

Microsoft 已針對 Microsoft SQL Server 的弱點發佈資訊安全諮詢,該弱點可能會允許遠端程式碼執行。此資訊安全諮詢包含其他安全性相關資訊。如果要檢視此資訊安全諮詢,請造訪下列 Microsoft 網站:

http://www.microsoft.com/taiwan/technet/security/advisory/961040.mspx本文包含 VB 指令碼,可讓您將因應措施套用至本機電腦上 SQL Server 之所有執行中的執行個體。

您可用於套用因應措施的 VB 指令碼範例

在本機電腦上執行之所有受影響版本的 SQL Server 上,您可以使用此 VB 指令碼來拒絕 sp_replwritetovarbin 延伸預存程序中「公用」角色的「執行」權限。

Microsoft 僅提供示範性的程式設計範例,不做任何明示或默示的保證。其中包括 (但不限於) 其適售性與適合某特定用途之默示擔保。本文將假設您已相當熟悉示範所使用的程式設計語言,以及用於建立和偵錯程序的工具。Microsoft 技術支援工程師可以協助說明特定程序的功能,但不會修改這些範例以提供附加功能或建構程序來滿足您的特定需求。


將此程式碼複製到文字檔案,再使用 .vbs 副檔名來儲存該檔案,接著執行使用 CScript.exe 的指令檔案。該指令碼會逐一查看本機電腦上 SQL Server 之執行中的執行個體,並將因應措施套用至受影響的版本。在 SQL Server 之各執行個體上,您必須為系統管理員 (sysadmin) 角色的成員,才能套用因應措施。在所有執行 SQL Server 之受影響的伺服器上,如果您沒有系統管理員 (sysadmin) 角色成員的 Windows 帳戶,則您可能必須從多個帳戶執行此指令碼。在 Windows Server 2008 和 Windows Vista 上,如果您使用的是系統管理員 (sysadmin) 角色成員的 Windows 系統管理員帳戶,則您必須從「提高權限」的命令提示字元中執行此指令碼。

'*************************************************************************************
'Description:This script iterates through all the running instances of SQL Server
' and denies execute permission on sp_replwritetovarbin to public on all
' the affected versions.
' THIS IS PROVIDED AS A WORKAROUND AND SHOULD NOT BE USED IN THE EVENT THAT
' A SECURITY UPDATE IS PROVIDED AND INSTALLED.
'*************************************************************************************

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「資訊:沒有執行個體。」
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「錯誤:無法在『+ sInstances(i,0) +』上套用因應措施。」+ vbCRLF
VBMain = EXIT_FAILURE
End If
Next

WScript.Echo「資訊:Completed processing all the running SQL instances."
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「錯誤:無法讀取安裝在機器上的 SQL 執行個體。」
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「錯誤:無法讀取安裝在機器上的 SQL 執行個體。」
Exit Function
End If
End If

If IsEmptyNull(sInstances1) AND IsEmptyNull(sInstances2) Then
WScript.Echo「資訊:No instances present."
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 + ";"
' Error checking is intentionally left to keep the code short
Set objConn = CreateObject("ADODB.Connection")
Set objCmd = CreateObject("ADODB.Command")
Set objCmd1 = CreateObject("ADODB.Command")

' Open a Connection to the master Database
objConn.Open strConn
If ErrorOccurred("Error:Could not connect to " + strInstance) Then
Set objConn = Nothing
Exit Function
End If

' Validate the version before applying the fix
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:Could not execute """ + strCommand + """ on " + strInstance) = TRUE Then
objConn.Close()
Set objConn = Nothing
ApplyFix = FALSE
Exit Function
End If

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

bApplyFix = FALSE
' Apply the workaround only for SQL 2000 and SQL 2005 (RTM, SP1 and SP2) versions
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:Could not execute """ + strCommand + """ on " + strInstance) = FALSE Then
WScript.Echo「資訊:Successfully applied the workaround on " + strInstance + " (" + strBuildVersion + ")."+ vbCRLF
ApplyFix = TRUE
End If
Else
WScript.Echo「資訊:Skipping collecting information for " + strInstance + " (" + strBuildVersion + ") as this instance is not 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

'Connect to WMI and get an object to STDREGPROV class.
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:Could not connect to WMI namespace " + 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「錯誤: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")

'「查詢叢集」服務
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

' 如果我們執行到這個步驟,就表示該部機器為叢集節點。
' 因此,請讓查詢登錄決定 SQL 執行個體是否為叢集。
' 如為 SQL 2000,請查詢下列值
' 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

' 針對 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
' 如果該機碼不存在,則會返回為 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

如需有關 CScript.exe 的詳細資訊,請造訪下列 Microsoft 網站:

http://technet.microsoft.com/en-us/library/bb490887.aspx注意如果您已經安裝了提供的安全性更新,我們建議您不要使用此指令碼。

執行此指令碼之後可能發生的已知問題

問題 1

當您執行指令碼時,收到下列錯誤訊息:

錯誤:無法執行 <instancename> 上的「deny execute on sp_replwritetovarbin to public」
錯誤:0x-2147217900 - 找不到物件「sp_replwritetovarbin」,因為它不存在,或是您沒有權限。
錯誤:無法將因應措施套用至 <instancename>。

原因 1

如果您沒有具備套用此變更的權限,則會收到此錯誤訊息。此錯誤訊息表示您能夠成功登入執行個體「<instancename>」。


此錯誤訊息通常在 SQL Server Express 中發生,其中的「Built-In\Users」群組在預設情況下會擁有一筆資料庫登入。但是,此群組並非系統管理員 (sysadmin) 角色的成員。

此錯誤訊息也可能在您卸除 sp_replwritetovarbin 程序時發生。此為協力廠商報告上的建議。我們不建議您卸除預存程序。相反地,我們建議您套用此解決方式。

解決方式 1

請確定您在此資料庫執行個體中連線的帳戶為系統管理員 (sysadmin) 角色的成員。如果您使用的帳戶並非成員,您可以將正在連線的帳戶新增至系統管理員 (sysadmin) 角色,或使用另一個使用者帳戶。若為 SQL Server 2005 及較舊版本,「Built-in\Administrators」群組在預設情況下是系統管理員 (sysadmin) 角色的成員。當您在 Windows Vista 或 Windows Server 2008 中執行此指令碼時,請確定您是從「提高權限」的命令提示字元中執行此指令碼。

問題 2

如果在 SQL Server 2005 中執行此指令碼,您收到下列錯誤訊息:

錯誤:無法連線到 <instancename>
錯誤:0x-2147217843 - 使用者「<user>」登入失敗。
錯誤:無法將因應措施套用至 <instancename>。

原因 2

如果您無法連線到執行個體「<instancename>」,即使該執行個體存在,仍會收到此錯誤訊息。


此錯誤訊息通常在您連線到 Windows Internal Database 或 Microsoft SQL Server 2000 Desktop Edition (Windows) 執行個體時發生。通常,使用者帳戶沒有這些資料庫的登入。

解決方式 2

請確定您用來執行指令碼的帳戶,在系統管理員 (sysadmin) 角色成員的資料庫有登入。

我們不建議您將個別使用者新增至 Windows Internal Database 和 Microsoft SQL Server 2000 Desktop Edition (Windows) 資料庫。如果您執行這項操作,您新增的使用者可能會干擾這些資料庫的一般操作。在此情況下,請確定您所連線的帳戶為系統管理員 (sysadmin) 角色的成員。在 SQL Server 2005 和較舊版本中,「Built-in\Administrators」群組在預設情況下是系統管理員 (sysadmin) 角色的成員。當您在 Windows Vista 或 Windows Server 2008 中執行此指令碼時,請確定您是從「提高權限」的命令提示字元中執行此指令碼。

問題 3

您可能會注意到資料庫中有一個名為 MICROSOFT##SSEE 的執行個體。但是,您並未安裝此資料庫。

原因 3

此資料庫為 Windows Internal Database,也稱為「SQL Server Embedded Edition」,有時又稱為「Windows Internal Database」或「Microsoft SQL Server 2000 Desktop Edition (Windows)」。您可以使用如 SharePoint Services 這類的 Microsoft 產品來安裝此資料庫。

解決方式 3

此因應措施指令碼專為與 Windows Internal Database 搭配運作所設計。您不須執行任何動作。

解除安裝某些應用程式時,它們並沒有移除 Windows Internal Database。
如需有關如何移除 Windows Internal Database 的詳細資訊,請按一下下面的文件編號,檢視「Microsoft 知識庫」中的文件:

920277[新增或移除程式] 工具中沒有列出 Windows Internal Database,且當您從電腦中移除 Windows SharePoint Services 3.0 時,沒有將其移除。

問題 4

當您執行指令碼時,收到下列錯誤訊息:


錯誤:無法連線到 .\<instancename>
錯誤:0x-2147467259 - [DBNETLIB][ConnectionOpen (Connect()).]SQL Server 不存在或拒絕存取

原因 4

當下列情況成立時,您會收到錯誤訊息:

  • 您已將 32 位元版本的 SQL Server 2000 安裝在 x64 位元作業系統。

  • 您已將 64 位元版本的 SQL Server 2005 或 SQL Server 2008 安裝在電腦上。


當指令碼使用 64 位元版本的 dbmslpcn.dll 檔案時,便會出現錯誤訊息。該版本無法與 SQL Server 2000 的 WoW 執行個體進行通訊。

解決方式 4

從 [%WINDOWS%\SysWOW64] 資料夾中使用 32 位元版本的 cscript.exe 檔案來啟動指令碼。該檔案會載入可偵測 WoW 執行個體之 32 位元版本的 dbmslpcn.dll 檔案。

参考

如需有關如何識別您 SQL Server 的版本與版別的詳細資訊,請按一下下面的文件編號,檢視「Microsoft 知識庫」中的文件:

321185如何識別 SQL Server 的版本

其他相關資訊

下表列出本文的重要技術修訂。本文的修訂編號與最後檢閱日期,可能會指出本文內未包含在此表格中的編輯或結構方面的小幅度修訂。

修訂

日期

2008 年 12 月 31 日

包含更新指令碼,該指令碼可偵測 SQL Server 容錯移轉叢集執行個體。

2008 年 12 月 30 日

包含更新指令碼,該指令碼可偵測在 64 位元版本的 Windows 上執行之 32 位元版本的 SQL Server。

需要更多協助嗎?

想要其他選項嗎?

探索訂閱權益、瀏覽訓練課程、瞭解如何保護您的裝置等等。

社群可協助您詢問並回答問題、提供意見反應,以及聆聽來自具有豐富知識的專家意見。

這項資訊有幫助嗎?

您對語言品質的滿意度如何?
以下何者是您會在意的事項?
按下 [提交] 後,您的意見反應將用來改善 Microsoft 產品與服務。 您的 IT 管理員將能夠收集這些資料。 隱私權聲明。

感謝您的意見反應!

×