نصائح إرشادية للأمان من Microsoft: وجود ثغرة أمنية في SQL Server قد تسمح بتنفيذ تعليمات برمجية عن بعد

مقدمة

قامت Microsoft بإصدار أمان استشارية حول وجود ثغرة أمنية في Microsoft SQL Server مما قد يسمح بتنفيذ تعليمات برمجية عن بعد. النصائح الإرشادية للأمان معلومات إضافية متعلقة بالأمان. لعرض "النصائح الإرشادية للأمان"، قم بزيارة موقع Microsoft التالي على الويب:تتضمن هذه المقالة VB script التي يمكنك استخدامها لتطبيق حل لكافة المثيلات قيد التشغيل من SQL Server على كمبيوتر محلي.

مثال على VB SCRIPT التي يمكنك استخدامها لتطبيق الحل البديل

يمكنك استخدام هذا البرنامج النصي VB لرفض تنفيذ الإذن بدور عام في sp_replwritetovarbin توسيع الإجراء المخزن على كافة المتأثرة إصدارات SQL Server التي يتم تشغيلها على الكمبيوتر المحلي.

تقدم Microsoft أمثلة برمجية للتوضيح فقط، دون أي ضمان صريح أو ضمني. هذا يتضمن، على سبيل المثال لا الحصر، الضمانات الضمنية الخاصة بالتسويق أو الملاءمة لغرض معين. تفترض هذه المقالة أنك معتاد على لغة البرمجة التي يتم شرحها والأدوات المستخدمة لإنشاء الإجراءات وتصحيحها. يساعد مهندسو الدعم لدى Microsoft شرح وظيفة إجراء محدد. ومع ذلك، لن يقوموا بتعديل هذه الأمثلة لتقديم وظيفة إضافية أو إنشاء إجراءات تستوفي متطلبات محددة.


نسخ هذه التعليمة البرمجية إلى ملف نصي، احفظ الملف باستخدام ملحق اسم ملف.vbs ثم قم بتشغيل الملف النصي باستخدام CScript.exe. السيناريو يتكرر عبر مثيلات SQL Server قيد التشغيل على الكمبيوتر المحلي وتطبيق الحل البديل على الإصدارات المتأثرة. يجب أن تكون عضوا في دور مسؤول النظام sysadmin في كل مثيل من SQL Server لتطبيق الحل البديل. ليس لديك حساب Windows عضو دور sysadmin على كافة الملقمات المتأثرة التي تستخدم SQL Server، قد تضطر إلى تشغيل هذا البرنامج النصي من حسابات متعددة. في Windows Server 2008 و Windows Vista، إذا كنت تستخدم حساب مسؤول 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 التالي على الويب:ملاحظة: نوصي بعدم استخدام هذا البرنامج النصي إذا تم توفير تحديث أمني وتثبيته.

المشكلات المعروفة التي قد تحدث عند تشغيل هذا البرنامج النصي

المشكلة الأولى

عند تشغيل البرنامج النصي، تتلقى رسالة الخطأ التالية:
خطأ: تعذر تنفيذ "رفض تنفيذ على sp_replwritetovarbin للجمهور" على < اسم المثيل >
خطأ: 0 x-2147217900-تعذر العثور على الكائن 'sp_replwritetovarbin'، لأنه غير موجود أو ليس لديك إذن.
خطأ: تعذر تطبيق الحل البديل على < اسم المثيل >.

السبب الأول

تتلقى رسالة الخطأ هذه إذا لم يكن لديك الأذونات المطلوبة لتطبيق التغيير. تشير رسالة الخطأ هذه إلى لم تتمكن من تسجيل الدخول بنجاح إلى المثيل "< اسم المثيل >."


تظهر رسالة الخطأ هذه عادة في SQL Server Express فيه على مجموعة "بني In\Users" تسجيل دخول إلى قاعدة البيانات بشكل افتراضي. ومع ذلك، هذه المجموعة ليست عضوا دور مسؤول النظام.

قد تظهر رسالة الخطأ هذه أيضا إذا قمت بإفلاته الإجراء sp_replwritetovarbin. كانت هذه التوصية من تقرير الجهة الخارجية. لا نوصي بإسقاط الإجراء المخزن. بدلاً من ذلك، نوصي بتطبيق هذا القرار.

القرار 1

تأكد من أن الحساب الذي يمكنك الاتصال بعضو دور sysadmin على ذلك المثيل لقاعدة البيانات. إذا لم يكن الحساب عضوا، إضافة المستخدم الذي تقوم بالاتصال فيما يتعلق بدور مسؤول النظام، أو استخدم حساب مستخدم آخر. ل SQL Server 2005 أو الإصدارات السابقة له، مجموعة "بني in\Administrators" عضوا دور مسؤول النظام بشكل افتراضي. عند تشغيل هذا البرنامج النصي على نظام التشغيل Windows Vista أو Windows Server 2008، تأكد من تشغيلها من موجه أوامر "غير مقيد".

المشكلة الثانية

إذا قمت بتشغيل هذا البرنامج النصي في SQL Server 2005، تتلقى رسالة الخطأ التالية:
خطأ: تعذر الاتصال < اسم المثيل >
X-2147217843 خطأ: 0-فشل تسجيل الدخول للمستخدم '< المستخدم >'.
خطأ: تعذر تطبيق الحل البديل على < اسم المثيل >.

السبب الثاني

تتلقى رسالة الخطأ هذه إذا لم تكن قادراً على الاتصال بالمثيل "< اسم المثيل >" على الرغم من وجود هذا المثيل.


عادة ما تظهر رسالة الخطأ هذه عند الاتصال بقاعدة البيانات الداخلية ل Windows أو لمثيلات Microsoft SQL Server 2000 Desktop Edition (في Windows). عادة، يكون لأية حسابات المستخدمين تسجيل الدخول إلى قواعد البيانات هذه.

القرار 2

تأكد من أن الحساب الذي تستخدمه لتشغيل البرنامج النصي على تسجيل دخول قاعدة عضو دور sysadmin.

لا نوصي بإضافة المستخدمين إلى قاعدة البيانات الداخلية ل Windows وقواعد بيانات Microsoft SQL Server 2000 Desktop Edition (في Windows). إذا قمت بذلك، المستخدمين الذين تم إضافتهم قد تتداخل مع العملية العادية لقواعد البيانات هذه. في هذه الحالة، تأكد من أن الاتصال من حساب يكون عضوا دور مسؤول النظام. مجموعة "بني in\Administrators" في Windows عادة تكون عضوا دور مسؤول النظام بشكل افتراضي في SQL Server 2005 وفي الإصدارات السابقة. عند تشغيل هذا البرنامج النصي على نظام التشغيل Windows Vista أو Windows Server 2008، تأكد من تشغيلها من موجه أوامر "غير مقيد".

المشكلة الثالثة

قد تلاحظ مثيل قاعدة بيانات تسمى MICROSOFT ##SSEE. ومع ذلك، لم تقم بتثبيت قاعدة البيانات هذه.

السبب الثالث

قاعدة البيانات هذه هي Windows Internal Database، كما تعرف باسم "خادم SQL المضمنة النسخة" أو تعرف أحياناً باسم "Windows Internal Database" أو "Microsoft SQL Server 2000 الطبعة سطح المكتب (في Windows)." يتم تثبيته مع بعض المنتجات من Microsoft، بما في ذلك خدمات SharePoint.

القرار 3

تم تصميم البرنامج النصي الحل البديل لتعمل مع Windows Internal Database. أي إجراء من جانبك.

بعض التطبيقات لا إزالة Windows Internal Database عندما يتم إلغاء تثبيت.
لمزيد من المعلومات حول كيفية إزالة Windows Internal Database، انقر فوق رقم المقالة التالي لعرضها في "قاعدة المعارف ل Microsoft":
920277 قاعدة البيانات الداخلية ل Windows غير مسرود في أداة إضافة أو إزالة البرامج ولا تتم إزالة عند إزالة Windows SharePoint Services 3.0 من الكمبيوتر

المسألة 4

عند تشغيل البرنامج النصي، تتلقى رسالة الخطأ التالية:

خطأ: تعذر الاتصال ب. \ < اسم المثيل >
خطأ: x-2147467259 0-[DBNETLIB] [كونيكتيونوبين (Connect()).] ملقم SQL غير موجود أو تم رفض الوصول

السبب الرابع

تظهر رسالة الخطأ هذه إذا تحققت الشروط التالية:
  • لديك إصدار 32 بت من SQL Server 2000 مثبت على نظام تشغيل x64 بت.
  • لديك إصدار 64 بت من SQL Server 2005 أو SQL Server 2008 مثبتاً على جهاز الكمبيوتر.

تظهر رسالة الخطأ هذه عند استخدام البرنامج النصي الإصدار 64 بت من الملف dbmslpcn.dll. لا يمكن الاتصال هذا الإصدار مع مثيلات WoW من SQL Server 2000.

القرار 4

استخدام إصدار 32 بت من الملف cscript.exe من المجلد %WINDOWS%\SysWOW64 لبدء تشغيل البرنامج النصي. وهذا يحمل إصدار 32 بت من الملف dbmslpcn.dll الذي يمكن لمثيلات WoW.

المراجع

لمزيد من المعلومات حول كيفية تحديد إصدار SQL Server ونسخته الخاصة بك، انقر فوق رقم المقالة التالي لعرضها في "قاعدة المعارف ل Microsoft":
321185 كيفية تحديد إصدار SQL Server ونسخته الخاصة بك

مزيد من المعلومات

يسرد الجدول التالي مراجعات تقنية هامة لهذه المقالة. قد يشير إلى رقم المراجعة وتاريخ المراجعة الأخيرة في هذه المقالة مراجعات تحريرية ثانوية أو مراجعات بنائية على هذه المقالة غير مدرجة في الجدول.
التاريخمراجعات
31 كانون الأول/ديسمبر 2008تتضمن برنامجا نصياً محدثاً يكشف مثيلات SQL Server تجاوز الفشل نظام المجموعة.
30 كانون الأول/ديسمبر 2008تتضمن برنامجا نصياً محدثاً يكشف إصدارات 32 بت من SQL Server تعمل على إصدارات 64 بت من Windows.
خصائص

رقم الموضوع: 961040 - آخر مراجعة: 14‏/01‏/2017 - المراجعة: 3

تعليقات