מבוא
Microsoft פרסמה עלון יידוע בנושא אבטחה אודות פגיעות ב- Microsoft SQL Server אשר עלולה לאפשר ביצוע קוד מרחוק. עלון היידוע כולל תוספת מידע בנושא אבטחה. כדי להציג את עלון היידוע בנושא אבטחה, בקר באתר האינטרנט הבא של Microsoft:
http://www.microsoft.com/technet/security/advisory/961040.mspx מאמר זה כולל VB script שבאפשרותך להשתמש בו כדי להחיל פתרון עוקף על כל המופעים הפועלים של SQL Server במחשב מקומי.
דוגמה של VB SCRIPT שבאפשרותך להשתמש בו כדי להחיל את הפתרון העוקף
באפשרותך להשתמש ב- VB script זה כדי למנוע הרשאת ביצוע לתפקיד הציבורי בפרוצדורה המאוחסנת המורחבת sp_replwritetovarbin בכל הגירסאות המושפעות של SQL Server הפועלות במחשב המקומי.
Microsoft מספקת את דוגמאות התכנות שלהלן להמחשה בלבד וללא כל אחריות, בין מפורשת ובין משתמעת, ובכלל זה, אך לא רק, אחריות לגבי סחירות או התאמה למטרה מסוימת. מאמר זה מבוסס על ההנחה שאתה מכיר את שפת התכנות המודגמת ובקי בהפעלת הכלים המשמשים ליצירת פרוצדורות ולניפוי שגיאות. מהנדסי התמיכה של Microsoft יכולים לסייע להסביר את הפונקציונליות של הליך מסוים. עם זאת, הם לא ישנו דוגמאות אלה כדי לספק פונקציונליות נוספת או יבנו הליכים כדי לספק מענה לצרכיך הספציפיים. העתק קוד זה לקובץ טקסט, שמור את הקובץ תוך שימוש בסיומת שם קובץ .vbs ולאחר מכן הפעל את קובץ ה- script באמצעות CScript.exe. ה- script סובב בין המופעים הפועלים של SQL Server במחשב המקומי ומחיל את הפתרון העוקף על הגירסאות המושפעות. עליך להיות חבר בתפקיד מנהל מערכת בכל מופע של SQL Server כדי להחיל את הפתרון העוקף. אם אין לך חשבון Windows החבר בתפקיד מנהל מערכת בכל השרתים המושפעים שבהם פועלת התוכנית SQL Server, ייתכן שיהיה עליך להפעיל script זה ממספר חשבונות. ב- Windows Server 2008 וב- Windows Vista, אם אתה משתמש בחשבון מנהל של Windows החבר בתפקיד מנהל מערכת, עליך להפעיל script זה משורת פקודה "גבוהה".'*************************************************************************************
'תיאור: script זה סובב סביב כל המופעים הפועלים של SQL Server ' ומונע הרשאת ביצוע ב- sp_replwritetovarbin לציבור בכל ' הגירסאות המושפעות. ' מסופק כפתרון עוקף ואינו מיועד לשימוש במקרה ' שעדכון אבטחה מסופק ומותקן. '************************************************************************************* OPTION EXPLICIT ON ERROR RESUME NEXT ' ערכי Constant 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 הבא 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 הבא End If If instCount2 >0 Then For i = 0 To UBound(sInstances2) sInstances(i+instCount1,0) = sInstances2(i) sInstances(i+instCount1,1) = FALSE הבא 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 הבא 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:
http://technet.microsoft.com/en-us/library/bb490887.aspxהערה מומלץ שלא תשתמש ב- script זה אם סופק עדכון אבטחה והתקנת אותו.
בעיות מוכרות שעלולות להתרחש בעת הפעלת SCRIPT זה
בעיה 1
בעת הפעלת script זה, תקבל הודעת שגיאה זו:
: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.(אין אפשרות למצוא את האובייקט 'sp_replwritetovarbin', מכיוון שאינו קיים או שאין לך הרשאה). :ERROR Could not apply the workaround on <instancename>.(אין אפשרות להחיל את הפתרון העוקף על [שם המופע]).סיבה 1
אתה מקבל הודעת שגיאה זו אם אין לך את ההרשאות הדרושות להחלת השינוי. הודעת שגיאה זו מציינת שלא הצלחת להיכנס בהצלחה למופע "<instancename>".
הודעת שגיאה זו מתרחשת בדרך כלל ב- SQL Server Express שבה הקבוצה "Built-In\Users" כוללת כניסה למסד הנתונים כברירת מחדל. עם זאת, קבוצה זו אינה חברה בתפקיד מנהל המערכת. כמו כן, הודעת שגיאה זו עלולה להתרחש אם שחררת את הפרוצדורה sp_replwritetovarbin זו היתה ההמלצה מדוח של ספק חיצוני. Microsoft אינה ממליצה על שחרור הפרוצדורה המאוחסנת. במקום זאת, מומלץ להחיל פתרון זה.פתרון 1
ודא שהחשבון שאליו אתה מתחבר הוא חבר בתפקיד מנהל המערכת במופע זה של מסד הנתונים. אם החשבון אינו חבר, הוסף את המשתמש שאתה מחבר לתפקיד מנהל המערכת, או השתמש בחשבון של משתמש אחר. עבור SQL Server 2005 וגירסאות קודמות, הקבוצה "Built-in\Administrators" היא חברה בתפקיד מנהל המערכת כברירת מחדל. כאשר אתה מפעיל script זה ב- Windows Vista או ב- Windows Server 2008, ודא שאתה מפעיל אותו משורת פקודה "גבוהה".
בעיה 2
אם אתה מפעיל script זה ב- SQL Server 2005, אתה מקבל את הודעת השגיאה הבאה:
Error: Could not connect to <instancename> (אין אפשרות להתחבר ל[שם המופע]).
:ERROR 0x-2147217843 - Login failed for user '<user>'. (כניסה נכשלה עבור המשתמש [שם משתמש]) :ERROR Could not apply the workaround on <instancename>.(אין אפשרות להחיל את הפתרון העוקף על [שם המופע]).סיבה 2
אתה מקבל הודעת שגיאה זו אם לא הצלחת להתחבר למופע ">instancename<" על-אף שמופע זה קיים.
הודעת שגיאה זו מופיעה בדרך כלל כאשר אתה מתחבר למופעים של Windows Internal Database או שלMicrosoft SQL Server 2000 Desktop Edition (Windows). בדרך כלל, לאף חשבון משתמש אין כניסה למסדי נתונים אלה.פתרון 2
ודא שלחשבון שבו אתה משתמש כדי להפעיל את ה- script יש כניסה למסד הנתונים החבר בתפקיד מנהל המערכת.
לא מומלץ להוסיף משתמשים בודדים למסדי נתונים של Windows Internal Database ושלMicrosoft SQL Server 2000 Desktop Edition (Windows). אם תעשה זאת, המשתמשים שתוסיף עלולים להפריע לפעילותם הסדירה של מסדי נתונים אלה. במקרה זה, ודא שאתה מתחבר מחשבון החבר בתפקיד מנהל המערכת. הקבוצה "Built-in\Administrators" ב- Windows היא חברה בתפקיד מנהל המערכת כברירת מחדל עבור SQL Server 2005 וגירסאות קודמות. כאשר אתה מפעיל script זה ב- 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)". הוא מותקן עם כמה מוצרים מאת Microsoft, ביניהם SharePoint Services.
פתרון 3
ה- script של הפתרון העוקף מיועד לפעול עם Windows Internal Database. אין צורך בפעולה מצדך.
מספר יישומים אינם מסירים את Windows Internal Database כאשר התקנתם מוסרת. לקבלת מידע נוסף אודות אופן ההסרה של Windows Internal Database, לחץ על מספר המאמר שלהלן כדי להציגו מתוך מאגר הידע Microsoft Knowledge Base:920277 Windows Internal Database אינו מופיע ברשימה של הכלי הוספה/הסרה של תוכניות ואינו מוסר כאשר אתה מסיר את Windows SharePoint Services 3.0 מהמחשב. (ייתכן שקישור זה מפנה לתוכן שחלק ממנו או כולו מופיע באנגלית)
בעיה 4
בעת הפעלת script זה, תקבל הודעת שגיאה זו:
Error: Could not connect to .\<instancename> (אין אפשרות להתחבר ל[שם המופע]). :ERROR 0x-2147467259 - [DBNETLIB][ConnectionOpen (Connect()).]SQL Server does not exist or access denied (SQL Server אינו קיים או שהגישה נדחתה)
סיבה 4
הודעת שגיאה זו מופיעה כאשר התנאים הבאים מתקיימים:
-
גירסת 32 סיביות של SQL Server 2000 מותקנת במערכת הפעלה של 64 סיביות.
-
במחשב שלך מותקנת גירסת 64 סיביות של SQL Server 2005 או של SQL Server 2008.
הודעת שגיאה זו מופיעה כאשר קובץ Script משתמש בגירסת 64 הסיביות של הקובץ dbmslpcn.dll. לגירסה זו אין אפשרות לנהל תקשורת עם מופעי WoW של SQL Server 2000.
פתרון 4
השתמש בגירסת 32 סיביות של הקובץ cscript.exe שנמצא בתיקיה %WINDOWS%\SysWOW64 כדי להפעיל את קובץ ה- Script. פעולה זו טוענת את גירסת 32 הסיביות של הוקבץ dbmslpcn.dll, שיכולה לזהות מופעי WoW.
מידע נוסף
לקבלת מידע נוסף כיצד לזהות את הגירסה והמהדורה של SQL Server, לחץ על מספר המאמר שלהלן כדי להציג את המאמר ב-Microsoft Knowledge Base:
321185כיצד לזהות את הגירסה והמהדורה של SQL Server
מידע נוסף
בטבלה הבאה רשומים שינויים טכניים משמעותיים שנעשו במאמר זה. מספר המהדורה ותאריך הסקירה במאמר זה עשויים להצביע על שינויי עריכה או שינויי מבנה קטנים במאמר זה שאינם כלולים בטבלה.
תאריך |
מהדורות |
---|---|
31 בדצמבר 2008 |
כולל קובץ Script מעודכן המזהה מופעי אשכולות של מעבר לגיבוי בעת כשל של SQL Server. |
30 בדצמבר 2008 |
כולל קובץ Script מעודכן המזהה גירסאות 32 סיביות של SQL Server שמפעילות גירסאות 64 סיביות של Windows. |