ב-29 במרץ, ב-05:00:41 בבוקר, מהנדס DevOps בחברת שירותי IT בהודו פתח ב-Cursor תיקיית עבודה בשם cloudshield. שתים עשרה שניות אחר כך רצו על ה-MacBook שלו שני תהליכים שהוא לא הפעיל, אחד בשם SystemUpdate והשני בשם iSync, ושניהם כבר פנו לשרתים בחו"ל. הקבצים האלה ישבו על הדיסק מאז 18 במרץ ולא עשו כלום. הם חיכו שמישהו יפתח את סביבת הפיתוח.

את התיעוד הזה פרסמו ב-18 בספטמבר החוקרים אלברט פריגו, אלכס דלמוט ומתיי הברנק מ-SentinelLabs, במקביל להרצאה בכנס LABScon. שתי הדלתות האחוריות שנמצאו על המחשב הזה הן בדיוק אותן שתיים שהופיעו באפריל בתקיפה של LayerZero, אחת מגניבות הקריפטו הגדולות של השנה. ההבדל היחיד הוא שלחברה ההודית אין שום קשר למסחר בקריפטו. בהמשך נראה איך הנוזקה מגיעה למחשב דרך קובץ תצורה של Terraform, איך היא מוצאת את שרת השליטה שלה בלי להחזיק אף כתובת, ומה הסגיר בסוף את מי שכתב אותה.

מי זו TraderTraitor, ומה קרה באפריל

הקבוצה שמאחורי הקמפיין היא תת-קבוצה של Lazarus שמיוחסת לצפון קוריאה ומוכרת בשמות UNC4899, PUKCHONG ו-Jade Sleet. בניגוד לחלק מהקבוצות הצפון-קוריאניות האחרות, היא לא עוסקת בריגול אלא בכסף. באפריל, לפי דוח האירוע שפרסמה LayerZero, נגנבו 292 מיליון דולר מפרוטוקול KelpDAO דרך פריצה ל-LayerZero עצמה. SentinelLabs מתארת שהתוקפים יצרו אירוע הנפקה מזויף של מטבעות והפעילו במקביל מתקפת השבתה על שרתי האימות, כדי ששרתים שכבר היו בשליטתם יאשרו את ההנפקה.

הדרך פנימה לא עברה דרך חולשה בקוד של אף אחד. לפי אותו דוח, עובד של LayerZero התקין על תחנת עבודה של החברה פרויקט קוד שקיבל כ"משימת בית" בתהליך גיוס. משם הותקנו שתי הדלתות האחוריות, והתוקפים השתמשו בהן כדי לאסוף מפתחות API ולהתרחב לסביבות ה-AWS וה-GCP של הארגון. השיטה עצמה מוכרת: כבר כתבנו על קמפיין המגייסים המזויפים שמיוחס לצפון קוריאה, אבל שם מדובר בקבוצה אחרת ובמשפחות נוזקה אחרות.

קובץ נעילה אחד, ורישום ספקים אחר לגמרי

כשמריצים terraform init, Terraform לא מוריד את רכיבי התשתית מאיפה שמתחשק לו. יש בפרויקט קובץ שרושם בדיוק מאיזה מקור להביא כל רכיב ובאיזו גרסה, כדי ששני מפתחים שעובדים על אותו פרויקט יקבלו בדיוק את אותו דבר. לקובץ הזה קוראים ‎.terraform.lock.hcl‎, והוא בדיוק מה שהתוקפים ערכו.

במאגרי ה-GitHub ששימשו כמשימת הבית לראיון, קובץ הנעילה הצביע על ספק מותאם אישית שיושב על דומיין בשליטת התוקפים. SentinelLabs מצאה שלושה כאלה: registry.hashicorp-aws[.]com, registry.hashicorp-aws[.]io ו-registry.hashicorp-terraform[.]io. כולם נראים כמו הרישום הרשמי של HashiCorp, ואף אחד מהם אינו. ברגע שהמועמד מריץ terraform init עם קובץ הנעילה הזה במקום, Terraform מתייחס לספק המותאם כמקור האמת לפי פרוטוקול רישום הספקים, מוריד את המודולים ומריץ אותם. אין כאן ניצול של חולשה. יש כאן שימוש במנגנון בדיוק כפי שתוכנן.

המאגרים עצמם נבנו כפרויקטי הנדסת תשתיות שמתאימים לחברה שהתוקפים התחזו לה. החוקרים הגיעו אליהם דרך המאגר gtn-candidate-repo שהופיע בדוח של LayerZero, ומצאו בדרך גם את Northwind-IAC, novacart-interview ו-terraform-candidate-repo. לדבריהם לא ברור אם Northwind ו-Novacart הן חברות מומצאות או שמות של חברות אמיתיות שהתוקפים התחזו אליהן. במאגר אחד מצאו החוקרים הערה שהשאיר מועמד קודם, שכתב שהסיר מקובץ הנעילה ספק עם דומיין מתחזה. לפי SentinelLabs ייתכן שהוא חשב שזה חלק מהמבחן.

שתים עשרה שניות אחרי שנפתחה סביבת הפיתוח

הקורבן החדש שמצאה SentinelLabs בטלמטריה שלה הוא ספק שירותי IT מהודו, ומעורב בו מחשב אחד: MacBook עם מעבד Apple Silicon של מהנדס DevOps שהריץ Terraform ו-Ansible מול AWS, OVH ו-OpenStack כמעט בכל יום עבודה. על המחשב היו פרטי אימות לענן וגישה לניהול הקוד. זה בדיוק סוג המחשב ששווה לתוקפים, גם אם הארגון שמסביבו לא מעניין אותם.

מה שקרה באותו בוקר מתועד בטלמטריה לפי שניות. ב-05:00:46 פתח הטרמינל המובנה של Cursor שני shell-ים, ב-05:00:53 השיקה Cursor את שתי ההשתלות בתור תהליכי בן, ב-05:00:55 הן כבר דיברו עם 176.97.114.232 ועם 45.11.59.140, וב-05:00:58 נוספה גם פנייה ל-Telegram. באותה שנייה הסירה ההשתלה הראשונה מהשנייה את מאפיין ההסגר של macOS והוסיפה לה הרשאת הרצה, כך ש-Gatekeeper לא בדק חתימה ולא הציג למשתמש שום אישור. הפרט המעניין בהתנהגות הזאת הוא דווקא מתי הנוזקה שותקת: בין 30 במרץ ל-19 באפריל היא פנתה לשרתים רק כש-Cursor רץ. סוגרים את סביבת הפיתוח, ואין תעבורה.

שתי המשפחות, שנקראות FLATROOF ו-ROOFDECK, הן דלתות אחוריות ל-macOS שנכתבו ב-Rust עבור ARM64. FLATROOF היא הקלה מבין השתיים, ותפקידה איסוף ראשוני והורדת המטען הבא. היא נושאת מודול פייתון שאוסף נתוני דפדפן מ-Chrome, מ-Brave, מ-Firefox ומ-Safari, היסטוריות פקודות מהטרמינל, רשימת אפליקציות מותקנות, תצלום של התהליכים הרצים ופרופיל החומרה והתוכנה של המכונה, וגם עותק גולמי של login.keychain-db, קובץ המפתחות של macOS. את הכול היא מוציאה דרך Telegram, עם bot token מוטמע בקוד. ניתוח מלא של FLATROOF, שמוכרת גם בשם macOS.Gaslight, פורסם ביוני.

איך ROOFDECK מוצאת שרת שאין לה את הכתובת שלו

ROOFDECK לא מגיעה עם כתובת של שרת שליטה. היא מגיעה עם מפתח ציבורי. בהרצה הראשונה היא פונה לרשת חברתית מבוזרת בשם Nostr, שבה פרופילים של משתמשים מפוזרים על שרתי ממסר רבים במקום לשבת על שרת אחד. ההשתלה מושכת רשימת ממסרים פעילים מ-api.nostr[.]watch, מצרפת אליה רשימה קבועה של ממסרים לגיטימיים כמו relay.damus[.]io, nos[.]lol ו-relay.snort[.]social, מחפשת בהם את הפרופיל של המפעיל לפי אותו מפתח ציבורי, וקוראת את שדה האתר בפרופיל. מה שכתוב שם הוא כתובת שרת השליטה. לטכניקה הזאת קוראים dead drop resolver.

היתרון לתוקף ברור: כדי להחליף שרת, מספיק לערוך שדה אחד בפרופיל ציבורי. אין דומיין קבוע שאפשר לחסום מראש, ואין כתובת שנשרפת ברגע שמישהו מפרסם אותה. SentinelLabs מציינת ש-TraderTraitor השתמשה ב-Nostr גם בעבר. משם והלאה הפנייה עוברת ב-HTTPS ל-endpoint קבוע בשם ‎/app_version‎, מול תעודת TLS שההשתלה נושאת בעצמה, והפקודות שמגיעות חתומות במפתח פרטי של המפעיל ונבדקות מול מפתח ציבורי מוטמע לפני שהן רצות.

שימור האחיזה נעשה דרך קובץ LaunchAgent בתיקיית הבית, עם מזהה שנקבע בזמן ריצה ועם פרמטר שגורם לתהליך להיראות כמו תהליך משנה של דפדפן. מעבר לזה, ROOFDECK מממשת בעצמה שורה ארוכה של פקודות קבצים שגרתיות במקום לקרוא לכלי המערכת, תכונה שהחוקרים מזהים גם בכלים צפון-קוריאניים אחרים כמו LightlessCan. יש לה חיפוש רקורסיבי שמיועד לאתר ארנקים, מפתחות ומסמכים, אריזה לארכיון מוצפן לקראת הוצאת מידע, shell הפוך, ופקודה שקוראת וכותבת ללוח הגזירים של macOS, כלומר יכולה גם לתפוס סיסמה שהועתקה וגם להחליף כתובת ארנק שהמשתמש העתיק. ופקודה אחת בתפריט עדיין מחזירה שהיא לא מומשה: צילום מסך.

מה הסגיר את התוקפים

התעודה שההשתלה נושאת נוצרה בכלי mkcert עם הגדרות ברירת המחדל, ושדות ברירת המחדל האלה נושאים את שם המשתמש ואת שם המכונה של מי שהפיק אותה. במקרה הזה, ub@ub-Standard-PC-Q35-ICH9-2009. מהשם אפשר להסיק שמדובר במכונה וירטואלית של QEMU על לינוקס, והחוקרים השתמשו במחרוזת הזאת כדי לאתר עוד דומיינים שמגישים תעודה עם אותו שם נושא.

התזמון של המהלך האחרון הוא הפרט שקשה להתעלם ממנו. ב-20 באפריל, יום אחד אחרי ההודעה הפומבית הראשונה של LayerZero על האירוע, הורידו התוקפים למחשב גרסה חדשה של ROOFDECK, זהה מבחינה תפקודית אבל בלי סמלים ובלי מידע ניפוי שגיאות, והשתמשו בה כדי למחוק את שני הקבצים המקוריים. "אנחנו יכולים רק לשער אם זו הייתה תגובה לפרסום של LayerZero, אבל התזמון בכל זאת מעניין", כתבו החוקרים. הפניות לשרת נמשכו עד 1 ביוני, וב-17 ביוני הקובץ הועבר לאשפה. הערכת SentinelLabs היא שהארגון הזה פשוט לא הניב מספיק ערך כדי להצדיק המשך שהייה בו.

מה זה אומר בפועל

הצד המעשי כאן הוא לא תיקון שצריך להתקין אלא זיהוי של קבוצת סיכון. מי שמחזיק פרטי אימות לענן וגישה לניהול הקוד, כלומר אנשי DevOps ומהנדסי תשתיות, הוא היעד, והמחשב שלו שווה לתוקף בדיוק כמה שהוא מגיע. SentinelLabs ממליצה לסמן את האנשים האלה כקבוצה רגישה לניטור, ולחפש קבצים בינאריים לא חתומים שרצים מתיקיית הבית ותהליכי בן של סביבת פיתוח שאינם רכיבים חתומים שלה.

ולמפתחים עצמם: לפני שמריצים terraform init על פרויקט שהגיע מבחוץ, כדאי לפתוח את קובץ הנעילה ולבדוק מול איזה רישום הוא עובד. כל דומיין שאינו registry.terraform.io ראוי לבדיקה, וגם בתוך הרישום הרשמי שווה לוודא מי פרסם את הספק. ואם הפרויקט הגיע ממגייס, השאלה הראשונה היא בכלל למה הוא נפתח על מחשב של העבודה.