はじめに
Microsoft は、リモートでコードを実行できる可能性がある Microsoft SQL Serverの脆弱性に関するセキュリティ アドバイザリをリリースしました。 セキュリティ アドバイザリには、この問題に関連する追加のセキュリティ関連の情報が含まれています。 セキュリティ アドバイザリを参照するには、次のマイクロソフト Web サイトにアクセスしてください。
http://www.microsoft.com/technet/security/advisory/961040.mspxこの記事には、ローカル コンピューター上のSQL Serverのすべての実行中のインスタンスに回避策を適用するために使用できる VB スクリプトが含まれています。
回避策を適用するために使用できる VB スクリプトの例
この VB スクリプトを使用すると、ローカル コンピューターで実行されているすべての影響を受けるバージョンのSQL Serverで、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 "INFO: No instances are present."
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: Could not apply the workaround on " + sInstances(i,0) + "." + vbCRLF
VBMain = EXIT_FAILURE
End If
Next
WScript.Echo "INFO: 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 "ERROR:Failed to read SQL instances installed on the machine."
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:Failed to read SQL instances installed on the machine."
Exit Function
End If
End If
If IsEmptyNull(sInstances1) AND IsEmptyNull(sInstances2) Then
WScript.Echo "INFO: 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 "INFO: Successfully applied the workaround on " + strInstance + " (" + strBuildVersion + ")." + vbCRLF
ApplyFix = TRUE
End If
Else
WScript.Echo "INFO: 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 "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")
' 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
' If we reach here that means the machine is a clustered node.
' So lets query registry to determine whether the SQL instance is clustered or not.
' For SQL 2000 query the following value
' 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
' Lets try querying the registry value for 2005/2008 instances
'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
' If this key doesnt exist, then return back as a SQL 2000 local instance
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 Web サイトを参照してください。
http://technet.microsoft.com/en-us/library/bb490887.aspx 注 このスクリプトは、セキュリティ更新プログラムが提供されていてインストールされている場合は使用しないことをお勧めします。
このスクリプトを実行するときに発生する可能性がある既知の問題
問題 1
スクリプトを実行すると、次のエラー メッセージが表示されます。
注
エラー: <instancename で "sp_replwritetovarbin からパブリックへの実行を拒否する" を実行できませんでした>
ERROR: 0x-2147217900 - オブジェクト 'sp_replwritetovarbin' が見つかりません。存在しないか、アクセス許可がないためです。
エラー: <instancename>で回避策を適用できませんでした。
原因 1
変更を適用するために必要なアクセス許可がない場合は、このエラー メッセージが表示されます。 このエラー メッセージは、インスタンス "<instancename>" に正常にログインできたことを示します。
このエラー メッセージは、通常、"組み込み\Users" グループが既定でデータベースにログインしているSQL Server Expressで発生します。 ただし、このグループは sysadmin ロールのメンバーではありません。
このエラー メッセージは、sp_replwritetovarbin プロシージャを削除した場合にも発生する可能性があります。 これは、サード パーティのレポートからの推奨事項でした。 ストアド プロシージャを削除することはお勧めしません。 代わりに、この解決策を適用することをお勧めします。
解決方法 1
接続するアカウントが、データベースのそのインスタンスの sysadmin ロールのメンバーであることを確認します。 アカウントがメンバーでない場合は、接続しているユーザーを sysadmin ロールに追加するか、別のユーザー アカウントを使用します。 SQL Server 2005 以前の場合、"組み込み\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 ロールのメンバーであるアカウントから接続してください。 Windows の "組み込み\Administrators" グループは、通常、SQL Server 2005 以前のバージョンでは既定で sysadmin ロールのメンバーです。 Windows Vista または Windows Server 2008 でこのスクリプトを実行する場合は、"管理者特権" コマンド プロンプトから実行してください。
問題 3
MICROSOFT##SSEE という名前のデータベースのインスタンスに気付く場合があります。 ただし、このデータベースはインストールされませんでした。
原因 3
このデータベースは、"SQL Server Embedded Edition" とも呼ばれるWindows Internal Databaseであり、"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
次の条件に該当する場合、このエラー メッセージが表示されます。
- x64 ビット オペレーティング システムに 32 ビット バージョンの SQL Server 2000 がインストールされています。
- コンピューターには、64 ビット バージョンの SQL Server 2005 または SQL Server 2008 がインストールされています。
このエラー メッセージは、スクリプトが dbmslpcn.dll ファイルの 64 ビット バージョンを使用している場合に発生します。 このバージョンは、SQL Server 2000 の WoW インスタンスと通信できません。
解決策 4
スクリプトを開始するには、%WINDOWS%\SysWOW64 フォルダーの cscript.exe ファイルの 32 ビット バージョンを使用します。 これにより、WoW インスタンスを検出できる 32 ビット バージョンの dbmslpcn.dll ファイルが読み込まれます。
参考資料
SQL Serverのバージョンとエディションを識別する方法の詳細については、次の記事番号をクリックして、Microsoft サポート技術情報の記事を参照してください。
321185 SQL Server のバージョンとエディションを識別する方法
追加情報
次の表に、この記事の重要な技術的なリビジョンを示します。 この記事のリビジョン番号と最終レビュー日は、表に含まれていない、この記事の軽微な編集リビジョンまたは構造リビジョンを示している可能性があります。
| 日付 | リビジョン |
|---|---|
| 2008 年 12 月 31 日 | フェールオーバー クラスタリング インスタンスSQL Server検出する更新されたスクリプトが含まれています。 |
| 2008 年 12 月 30 日 | 64 ビット バージョンの Windows で実行されている 32 ビット バージョンのSQL Serverを検出する更新されたスクリプトが含まれています。 |