ההתחברות נראית תקינה, חוץ מכתובת ה-IP: המפתח של ConnectWise Cloud Backup בידי תוקף, ו-162 tenant-ים עם התחברות לא מורשית
בלוג ההתחברויות של Entra הוא לא המקום שבו מחפשים דרמה. השורה שנרשמה שם ב-15 באוקטובר ב-06:13 UTC נראית תקינה לחלוטין: אפליקציית הגיבוי של ספק השירות מתחברת ל-tenant, מבקשת token ל-Microsoft Graph, מקבלת אותו. פרט אחד לא במקום. כתובת ה-IP שממנה הגיעה הבקשה, 144.172.64.128, שייכת לספק hosting, והאפליקציה הזאת יוצאת בדרך כלל מתוך כתובות פרטיות של Azure.
חוקר Huntress ג'ונתן סמון פרסם ב-16 באוקטובר שהמפתח הסודי של ConnectWise Cloud Backup, שירות הגיבוי שנקרא בעבר SkyKick, נמצא בידיים עוינות, ושהוא כבר שימש להתחברות לא מורשית לסביבות Microsoft 365 של לקוחות. עד 19:00 UTC באותו יום אימתה Huntress התחברויות כאלה ב-162 tenant-ים; The Hacker News דיווח למחרת על 173. שני המספרים הם רצפה ולא תקרה, והסיבה פשוטה: המפתח עובד מול כל tenant שהאפליקציה הותקנה בו. בהמשך נראה למה מפתח אחד פותח מאות ארגונים בבת אחת, מה קרה בלוגים בין ה-13 ל-15 באוקטובר, ולמה דווקא כאן יומני מיקרוסופט לא יספרו לכם את כל הסיפור.
מה עושה אפליקציית גיבוי בתוך ה-tenant שלכם
ConnectWise Cloud Backup נבנתה בשביל ספקי שירות מנוהל (MSP), חברות ה-IT שמתחזקות את הסביבות של עשרות או מאות לקוחות קטנים. התפקיד שלה פשוט למדי: להעתיק לעצמה את הדואר, הקבצים וההודעות של כל לקוח, ולהחזיר אותם כשמשהו נמחק או ננעל. כדי לעשות את זה היא צריכה לקרוא את תיבות הדואר, את OneDrive, את SharePoint, את Teams ואת נתוני הספרייה הארגונית בכל tenant שהיא מותקנת בו, ובשביל השחזור היא צריכה גם הרשאת כתיבה בחזרה לשם.
ההרשאות האלה לא ניתנות במקום מרכזי אחד. מנהל בכל tenant מאשר אותן אצלו, והאישור נשמר שם גם אחרי שהמנהל ההוא כבר לא עובד בארגון. זה המודל הרגיל של אפליקציות ענן שמשרתות הרבה ארגונים במקביל, והוא עובד בסדר גמור עד הרגע שבו מישהו זר משיג את המפתח של האפליקציה.
אז למה הסיסמאות וה-MFA של הארגון לא עצרו את זה?
כשאדם מתחבר ל-Microsoft 365 הוא מקליד סיסמה, מאשר MFA, והמכשיר שלו נבדק מול מדיניות Conditional Access. אפליקציה שעובדת ברקע לא עוברת אף אחד מהשלבים האלה. היא שולחת ל-Entra את מזהה האפליקציה שלה ומפתח סודי שרק היא מחזיקה, ומקבלת בחזרה token עם ההרשאות שמנהל כבר אישר לה. אין משתמש, אין מכשיר, ואין בקשת MFA. לזרימה הזאת קוראים client credentials, ומיקרוסופט מתעדת אותה במפורש: ההרשאות ניתנות לאפליקציה עצמה על ידי מנהל, והמשאב בודק שלאפליקציה יש הרשאה לפעולה, כי אין מאחוריה שום משתמש.
המפתח עצמו יכול להיות מחרוזת סוד (client secret) או חתימה על תעודה (client assertion). Huntress קובעת שההתחברויות כאן נעשו עם client assertion, ולפרט הזה יש משמעות חדה אחת: המפתח יושב ב-tenant של היצרן, לא אצל הלקוח. שום דבר שלקוח עשה או לא עשה בסביבה שלו לא יכול היה לייצר אותו, ושום החלפת סיסמה אצלו לא מבטלת אותו. הגיבוי קיבל מפתח לבית, והמפתח נגנב מהגיבוי.
מה הלוגים מראים, לפי שעות
התמונה ש-Huntress מרכיבה מתחילה יומיים לפני ההתחברויות עצמן. ב-13 וב-14 באוקטובר אותה כתובת IP ניסתה סיסמאות מול ארבעה tenant-ים של משרדי עריכת דין. הבקשות היו אוטומטיות לגמרי, עם User-Agent של curl/7.88.1, ומנגנון הנעילה החכמה של מיקרוסופט נעל שני חשבונות. התחברות מוצלחת של משתמש מהכתובת הזאת לא נראתה בטלמטריה של Huntress.
ב-15 באוקטובר, מ-01:58 UTC, קרה משהו אחר לגמרי. בכ-50 tenant-ים שבניטור Huntress, ה-service principal-ים של אפליקציות ConnectWise Cloud Management (אלה של Exchange Online, של Teams ושל Graph) הקצו לעצמם תפקידי ניהול בספרייה, בעיקר Exchange Administrator. את החלק הזה החוקרים לא תולים בתוקף: ה-User-Agent היה kiota-dotnet, אותו SDK שהאפליקציות של ConnectWise עצמן משתמשות בו, מה שמצביע לדעתם על אוטומציה של היצרן. הם כותבים במפורש שלא אימתו את זה מול ConnectWise.
בין 06:13 ל-08:34 UTC התחברה האפליקציה מ-144.172.64.128 ואספה token-ים ל-Graph. הסדר הוא הפרט המעניין כאן: התוקף עבר בין ה-tenant-ים לפי סדר ה-GUID שלהם, בהפרשים של שניות בודדות. "זה מצביע על סקריפט שעובד מתוך רשימת מטרות", כתב סמון. ב-17 מתוך כ-290 ה-tenant-ים הראשונים שנבדקו נמצאה התחברות כזאת, והם פרושים על 17 חשבונות שותף שונים.
חמש הדקות שהפכו שתי אפליקציות אחרות לדלת כניסה
בין 03:44 ל-03:49 UTC, ב-tenant אחד של לקוח, קרה הדבר שהופך את התקרית ממפתח שדלף למשהו שנשאר גם אחרי שמחליפים אותו. האפליקציה ConnectWise Cloud Management for Microsoft Teams הוסיפה את עצמה לתפקיד Global Administrator, ב-03:44 ושוב ב-03:48. מההרשאות החדשות רץ סקריפט פייתון (User-Agent של Python-urllib/3.12) שעשה תשעה שינויים בשתי אפליקציות אחרות באותו tenant: אפליקציה לניהול MSP, ואפליקציה של Huntress עצמה. שישה מהשינויים הצליחו, שלושה נכשלו. ניסיון להוסיף תעודה נדחה בגלל אי-התאמה בטביעת האצבע שלה, אבל ה-client secret-ים שנוספו אחריו נכנסו. תאריך התפוגה שהוגדר להם הוא 2028.
מי שמייצר client secret רואה את הערך שלו פעם אחת, ברגע היצירה, ומאז הוא מחזיק פרטי אימות עובדים לאפליקציה הזאת עד שמישהו ימחק אותם ביד. זאת טכניקת שימור אחיזה מוכרת, שממופה ב-MITRE ATT&CK כ-T1098.001. והיא מסבירה את ההמלצה הכי פחות אינטואיטיבית בדוח: השבתת האפליקציות של ConnectWise לא מסירה פרטי אימות שכבר נוספו לאפליקציות אחרות. שתי האפליקציות שקיבלו סוד חדש הן בדיוק הסוג שכדאי לתוקף להחזיק, כי אפליקציה לניהול MSP מאושרת בדרך כלל גם ב-tenant-ים של הלקוחות של אותו MSP, וסוד על אפליקציה של כלי אבטחה נותן למחזיק בו את מה שהכלי הזה מורשה לעשות.
Huntress מדגישה שהיא לא קושרת את שני השלבים לאותו מפעיל. שינוי התפקיד הגיע כשעתיים וחצי לפני ההתחברויות הראשונות מכתובת ה-IP, ולפעולות שאפליקציה מבצעת בלי משתמש אין בכלל כתובת מקור ביומן. וזה רק ההתחלה של מה שהיומנים כאן לא מראים.
ביומן הביקורת של מיקרוסופט נרשמות הקצאות תפקיד ושינויים באפליקציות, כולל זהות האפליקציה שביצעה אותם. מה שלא נרשם שם: כתובת המקור של פעולות שבוצעו בלי משתמש, הפרטים של פרטי האימות שנוספו, ומה בדיוק קראה אפליקציה דרך Microsoft Graph. קריאה של נתוני הספרייה הארגונית דרך Graph לא משאירה עקבות ביומן כלל, וזאת הסיבה שהחוקרים ממליצים לפעול עכשיו ולא לחכות להוכחה שמידע נלקח.
לכן מה ש-Huntress אומרת על ההיקף זהיר במתכוון. ב-tenant היחיד שבו עברו על יומן הביקורת לעומק לא נראתה גישה לדואר או לקבצים, והחוקרים כותבים שזה לא אומר שלא נלקח מידע. המצב, בלשונם, הוא ש-token-ים הונפקו ושום דבר לא נראה נלקח. Todyl, חברת אבטחה שחקרה את אותו מקרה, הוסיפה לפי דיווח של The Hacker News נקודה מעשית: ביטול ה-session-ים של המשתמשים לא מסיים את הגישה הזאת, והשבתת האפליקציה ב-tenant עוצרת הנפקה של token-ים חדשים אבל token שהונפק קודם נשאר תקף עד 90 דקות. ConnectWise מצידה סגרה את הגישה לאפליקציית Cloud Backup עד להודעה חדשה, ולפי Huntress אישרה את התקרית באתר שלה ואת הקשר בין כתובת ה-IP לפעילות לא מורשית. החברה אמרה שלא מצאה עדות לפגיעה בנתוני הגיבוי של השותפים.
ספק אחד, מאות ארגונים: נקודת הכשל שחוזרת
התקרית הזאת לא מעניינת בגלל תחכום טכני. אין כאן חולשה, אין מטען ואין נוזקה. יש מפתח אחד ששמור אצל ספק, והרשאות רחבות שמנהלים ברחבי העולם אישרו לו פעם ומזמן שכחו מהן. המודל שבו אפליקציה אחת משרתת הרבה ארגונים הופך כל ספק כזה לנקודת כשל יחידה שעוברת רוחבית בין כל הלקוחות שלו באותו רגע, ובשרשרת MSP האפקט מוכפל: אפליקציית ניהול שמקבלת סוד חדש נושאת את הגישה הלאה ללקוחות של אותו ספק.
זה גם השבוע השני שבו תשתית של ספק גיבוי היא נקודת הכניסה. פרשת שרתי העדכון של AOMEI Backupper עבדה אחרת לחלוטין מבחינה טכנית, אבל התוצאה דומה: ארגונים שעשו בדיוק את מה שאומרים להם לעשות, גיבוי ועדכון, קיבלו את זה דרך צינור שהם לא שולטים בו.
מה זה אומר בפועל
אם אתם MSP או ארגון שמשתמש ב-ConnectWise Cloud Backup, הצעד הראשון הוא להשבית את האפליקציה (Application ID 506e08f9-6e9a-4da4-942b-a099a03644ae) בכל tenant. להשבית, לא למחוק, כי מחיקה מבטלת את האישור ותחייב אישור מחדש כדי להחזיר את השירות. Huntress ממליצה להשבית גם את שאר אפליקציות ConnectWise Cloud Management עד שיתברר שהן תקינות, ולא להפעיל שום דבר מחדש לפני שהחברה תודיע שכל פרטי האימות הוחלפו.
הבדיקה החשובה יותר רחבה מ-ConnectWise. עברו על ה-client secret-ים והתעודות של כל האפליקציות הארגוניות שלכם, ובמיוחד של כלי ניהול ואבטחה, וחפשו פרטי אימות שנוספו מה-13 באוקטובר והלאה ולא אתם יצרתם אותם. את ההתחברויות עצמן אפשר לראות ביומן ההתחברויות של Entra רק בלשונית Service principal sign-ins, לא בלשונית המשתמשים שנפתחת כברירת מחדל. ואם יש לכם מדיניות Conditional Access שמחריגה את האפליקציה הזאת מחסימה לפי מקום גיאוגרפי, כדאי לדעת שההחרגה הזאת עבדה גם לטובת התוקף.
תגובות