はじめに
マイクロソフトは、リモートでコードが実行される可能性がある Microsoft SQL Server の脆弱性に関するマイクロソフト セキュリティ アドバイザリをリリースしました。セキュリティ アドバイザリには、この問題に関連する追加のセキュリティ関連の情報が含まれています。セキュリティ アドバイザリを参照するには、次のマイクロソフト Web サイトにアクセスしてください。
http://www.microsoft.com/japan/technet/security/advisory/961040.mspxこの資料では、ローカル コンピュータ上の SQL Server で実行中のすべてのインスタンスに回避策を適用する VB スクリプトを掲載しています。
回避策を適用する VB スクリプトの例
この VB スクリプトを使用して、ローカル コンピュータで実行中の SQL Server で影響を受けるすべてのバージョンで、sp_replwritetovarbin 拡張ストアド プロシージャのパブリック ロールの実行権限を禁止できます。
マイクロソフトは、この情報をプログラミング言語の使用方法の一例として提供するだけであり、市場性および特定目的への適合性を含めて、明示的にも黙示的にも、一切の保証をいたしません。この資料は、例示されているプログラミング言語やプロシージャの作成およびデバッグに使用するツールについて理解されているユーザーを対象としています。Microsoft Support 担当者は、特定のプロシージャの機能についての問い合わせにはお答えできますが、ユーザー固有の目的に合わせた機能の追加、プロシージャの作成などの内容変更は行っておりません。 以下のコードをテキスト ファイルにコピーし、拡張子 .vbs で保存し、CScript.exe を使用してスクリプトを実行します。スクリプトはローカル コンピュータ上の SQL Server で実行中のインスタンスで繰り返し処理され、影響を受けるバージョンに回避策を適用します。SQL Server に回避策を適用するには、各インスタンスで sysadmin ロールのメンバである必要があります。SQL Server を実行中の影響を受けるすべてのサーバーで sysadmin ロールのメンバである Windows アカウントを持っていない場合、複数アカウントでこのスクリプトを実行する必要がある可能性があります。Windows Server 2008 か Windows Vista で、sysadmin ロールのメンバである Windows administrator アカウントを使用している場合、このスクリプトは管理者特権のコマンド プロンプトで実行する必要があります。'*************************************************************************************
説明 : このスクリプトは SQL Server の実行中のすべてのインスタンスで繰り返し処理され、 ' 影響を受けるすべてのバージョンでパブリックへの sp_replwritetovarbin の実行権限 ' を禁止します。 ' このスクリプトは回避策として提供されており、セキュリティ更新プログラムが提供され、インストール ' されている場合は使用しないでください。 '************************************************************************************* OPTION EXPLICIT ON ERROR RESUME NEXT ' 定数値 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 ' 戻り値を初期化 ApplyFix = FALSE strConn = "Provider=sqloledb;Initial Catalog=master;Integrated Security=SSPI;Data Source=" + strServerName + ";" ' コードを短く維持するため、エラー チェックが意図的に残されている Set objConn = CreateObject("ADODB.Connection") Set objCmd = CreateObject("ADODB.Command") Set objCmd1 = CreateObject("ADODB.Command") ' マスタ データベースへの接続を開く objConn.Open strConn If ErrorOccurred("Error:Could not connect to " + strInstance) Then Set objConn = Nothing Exit Function End If ' 修正プログラムを適用する前にバージョンを検証する 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 ' SQL 2000 および SQL 2005 (RTM、SP1 および 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: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 ' WMI に接続し、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:Could not connect to WMI namespace " + DEFAULTNAMESPACE) Then GetRegValue = FALSE Exit Function End If lRc = 0 Select Case iValueType ' 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") ' クエリ クラスタ サービス 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 ' クラスタ名 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 の詳細については、次のマイクロソフト Web サイトを参照してください。
http://technet.microsoft.com/en-us/library/bb490887.aspx注 : セキュリティ更新プログラムが提供されていて、それをインストールした場合は、このスクリプトを使用しないことを推奨します。
このスクリプトを実行した場合に発生する可能性のある既知の問題
問題 1
スクリプトを実行すると、次のエラー メッセージが表示される。
ERROR: Could not execute "deny execute on sp_replwritetovarbin to public" on <instancename>
ERROR: 0x-2147217900 - Cannot find the object 'sp_replwritetovarbin', because it does not exist or you do not have permission. ERROR: Could not apply the workaround on <instancename>.原因 1
変更を適用するのに必要なアクセス許可がない場合、このエラー メッセージが表示されます。このエラー メッセージは、インスタンス "<instancename>" にログインできなかったことを示しています。
このエラー メッセージは通常、"Built-In\Users" グループが既定でデータベースにログインする SQL Server Express で表示されます。しかし、このグループは sysadmin ロールのメンバではありません。 また、sp_replwritetovarbin プロシージャをドロップした場合にも、このエラー メッセージが表示される場合があります。これはサードパーティ レポートからの勧告でした。マイクロソフトでは、ストアド プロシージャをドロップすることは推奨しません。代わりに、次の解決方法を適用することを推奨します。解決方法 1
接続に使用するアカウントを、データベースの当該インスタンスの sysadmin ロールのメンバにします。アカウントがメンバでない場合は、接続に使用するユーザーを sysadmin ロールに追加するか、別のユーザー アカウントを使用します。SQL Server 2005 以前では、"Built-in\Administrators" グループは既定で sysadmin ロールのメンバです。Windows Vista または Windows Server 2008 でこのスクリプトを実行する場合は、管理者特権のコマンド プロンプトから実行します。
問題 2
SQL Server 2005 でこのスクリプトを実行すると、次のエラー メッセージが表示される。
Error: Could not connect to <instancename>
エラー: 0x-2147217843 - ユーザー '<user>' はログインできませんでした。 ERROR: Could not apply the workaround on <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 および以前のバージョンでは、Windows の "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 などのマイクロソフトの一部の製品と共にインストールされます。
解決方法 3
回避策のスクリプトは、Windows Internal Database と共に動作するように設計されています。ユーザー側では操作は必要ありません。
一部のアプリケーションでは、アンインストール時に Windows Internal Database が削除されません。 Windows Internal Database を削除する方法の関連情報を参照するには、以下の「サポート技術情報」 (Microsoft Knowledge Base) をクリックしてください。920277Windows Internal Database が [プログラムの追加と削除] に表示されず、コンピュータから Windows SharePoint Services 3.0 を削除しても削除されない
問題 4
スクリプトを実行すると、次のエラー メッセージが表示される。
Error: Could not connect to .\<instancename> エラー: 0x-2147467259 - [DBNETLIB][ConnectionOpen (Connect()).]SQL Server が存在しないか、アクセスが拒否されました。
原因 4
このエラー メッセージは、以下の条件に該当する場合に表示されます。
-
x64 ビット オペレーティング システムに 32 ビット版の SQL Server 2000 をインストールしている。
-
コンピュータに 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 Knowledge Base) をクリックしてください。
321185 SQL Server のバージョンとエディションを識別する方法
詳細
次の表は、この資料に加えられた重要な技術上の改定の一覧です。この資料のリビジョン番号と最新のレビュー日には、この表に含まれていない、軽微な編集上の改定または構造上の改定が反映されていることがあります。
日付 |
改訂内容 |
---|---|
2008 年 12 月 31 日 |
SQL Server フェールオーバー クラスタリング インスタンスを検出する更新されたスクリプトを追加。 |
2008 年 12 月 30 日 |
64 ビット版の Windows で動作する 32 ビット版の SQL Server を検出する更新されたスクリプトを追加。 |