בקשה לאייקון שמחזירה 404, ובתוכה תשובה של web shell: מה השאירו התוקפים על שערי NetScaler שנפרצו
בקשה לאייקון בכתובת /vpn/media/e6ee7c85.ico נראית כמו כל בקשה אחרת שדפדפן שולח לשער ה-VPN בדרך לדף ההתחברות. השרת מחזיר עליה 404, כאילו הקובץ לא קיים. מי שמסתכל רק על קוד התשובה ממשיך הלאה. מי שמסתכל על הגודל של גוף התשובה מגלה שבתוך ה-404 הזה חזרה תשובה של web shell.
חוקרי Mandiant ו-Google Threat Intelligence Group פרסמו ב-29 בספטמבר ניתוח של ערכת הכלים שתוקפים השאירו על שערי Citrix NetScaler ADC ו-NetScaler Gateway שנפרצו דרך CVE-2026-88772, חולשת יום-אפס שלפי החברה נוצלה לפחות מתחילת ספטמבר. למחרת פרסם צוות ה-THOR של LevelBlue ממצאים משלו על החולשה השנייה באותו גל, CVE-2026-88771. בהמשך נעבור על איך התוקפים הפכו את שרת ה-web של הקופסה למכונה שמריצה את הקוד שלהם, מה עושות שתי הנוזקות החדשות שנמצאו שם, ומה נשאר על הדיסק אחרי שהן מסיימות.
NetScaler ADC ו-NetScaler Gateway הן הקופסאות שיושבות בין האינטרנט לרשת הפנימית: מאזנות עומסים בין שרתים, ומשמשות גם כשער ה-VPN שדרכו עובדים נכנסים מהבית. הגל הזה התחיל בסוף ספטמבר, כששמועות על שתי חולשות הרצת קוד מרחוק בלי תיקון הסתובבו בין מנהלי רשת עוד לפני ש-Citrix פרסמה משהו. ב-27 בספטמבר יצאה הודעת האבטחה עם התיקון ועם ה-CVE-ים. מה שחסר עד השבוע היה הצד השני של הסיפור: מה התוקפים עשו בפועל על הקופסאות שהם כבר הספיקו לפרוץ. לפי Mandiant מדובר בעשרות ארגונים בצפון אמריקה ובאירופה, בממשל, בשירותים פיננסיים, בטכנולוגיה, בחינוך ובמקצועות המשפטיים.
איך מלמדים שרת web להריץ קובץ שנראה כמו חבילת התקנה
כדי להריץ פקודות על הקופסה שוב ושוב, התוקף צריך קובץ שהשרת יסכים להריץ. שרת ה-web של NetScaler יודע להריץ PHP, אבל קובץ PHP שיושב בספרייה ציבורית הוא בדיוק מה שכל סריקה אוטומטית מחפשת. אז התוקפים עשו משהו אחר: הם ערכו את קובץ ההגדרות של שרת ה-web והוסיפו לו שורה שמורה לו להתייחס לסיומת תמימה לגמרי כאילו היא קוד PHP. אחרי השינוי, קובץ עם הסיומת .deb, הסיומת של חבילות התקנה של דביאן, מורץ כקוד בכל פעם שמבקשים אותו. למנגנון הזה ב-Apache קוראים handler, ובפועל התוקפים רשמו handler חדש לסיומת שאף אחד לא בודק. את ה-web shell עצמו הם העמידו בספריית סקריפטים פנימית של ממשק ה-VPN.
הווריאציה השנייה אלגנטית יותר. במקום להסתפק בסיומת חדשה, הוסיפו התוקפים כלל שממפה כל בקשה לאייקון תחת הנתיב /vpn/media/ לקובץ עם סיומת .sig באותו שם, שיושב באותה ספריית סקריפטים. התוצאה היא שבקשה לקובץ /vpn/media/e6ee7c85.ico מוגשת על ידי ה-web shell שנקרא e6ee7c85.sig. ביומני השרת זו בקשה לאייקון.
LevelBlue ראתה את אותו רעיון על החולשה השנייה, עם הסוואה אחרת. שם ה-web shell הושתל בנתיב /var/netscaler/logon/LogonPoint/.local_journal, ושינוי בהגדרות שרת ה-web מיפה אליו כתובות שנראות כמו קובצי העיצוב הלגיטימיים של דף ההתחברות, בהן LogonUISimple.html.style.min.css וגרסאות שלו עם מחרוזות הקסדצימליות רנדומליות. בקשה לקובץ CSS של דף הלוגין היא הדבר השגרתי ביותר שאפשר לדמיין.
WHIPSHOT: הפקודות נוסעות ב-header, התשובה חוזרת בתוך 404
ה-web shell שעליו Mandiant נותנת את מרב הפירוט, ושאותו היא מכנה WHIPSHOT, לא מקבל את הפקודות שלו בשדות הכתובת או בגוף הבקשה, המקומות שבהם מערכות ההגנה מחפשות אותן. הוא קורא אותן מתוך header של HTTP: שדה בשם HTTP_X_UX, ועוד שדות ממוספרים באותו שם כשהפקודה ארוכה מכדי להיכנס לאחד. הפקודות מועברות בקידוד Base64, כך שגם מי שמסתכל ישר על ה-header רואה מחרוזת אקראית ולא פקודה קריאה.
התשובה חוזרת בכיוון ההפוך, ובאותה גישה. WHIPSHOT מחזיר כלפי חוץ קוד 404, התשובה הסטנדרטית ל"הקובץ לא נמצא", ומכניס את הפלט האמיתי לתוך גוף התשובה. הוא גם מכבה את הדיווח על שגיאות PHP, כדי שתקלה בקוד שלו לא תייצר רשומה ביומן השרת. וריאנטים אחרים שהחוקרים מצאו, קבצים בשם nginstaller עם מספר בסוף, קוראים את הפקודות מ-header-ים אחרים שנראים כמו שדות אמיתיים של NetScaler, וגם הם מחזירים 404 מדומה.
SLAPSHOT: מנהרה שמוחקת את עצמה
עד כאן איך התוקף מריץ פקודה בודדת על הקופסה. הכלי השני מעניין יותר, כי הוא מה שהופך גישה לקופסה אחת לגישה לרשת שמאחוריה.
SLAPSHOT הוא כלי שכתוב ב-Python ותפקידו להעביר תעבורת TCP. הוא מקבל הוראות מ-WHIPSHOT דרך חיבור מקומי בתוך הקופסה עצמה, ומעביר זרמי TCP לכתובות ולפורטים ברשת הפנימית. בפועל זו נקודת מעבר: התוקף יושב מחוץ לרשת, מדבר עם שער ה-VPN בבקשות HTTP שנראות תקינות, ומגיע דרכו לשרתים פנימיים כאילו הוא עומד בתוך הרשת. "SLAPSHOT הוא כלי מנהור TCP שכתוב ב-Python", כתבו החוקרים, "הוא מתפקד כגשר לרשת הפנימית, מקבל פקודות מ-WHIPSHOT ומעביר זרמי TCP שרירותיים למחשבים פנימיים". בחקירות שהחברה ראתה, מה שעבר במנהרה היה סריקה ידנית של הרשת, חילוץ פרטי אימות ותנועה רוחבית.
החלק שמסביר למה הכלי קשה לתפוס הוא מה שהוא עושה כשאין עבודה. חיבור בודד שלא זז נסגר אחרי 15 דקות. התהליך כולו יוצא אחרי עשר דקות בלי פקודות ובלי חיבורים פעילים, והמשתנה שקובע את הזמן הזה ניתן לשינוי. לפני שהוא יוצא הוא מוחק את שני הקבצים שהשאיר תחת /tmp, אחד שבו רשום הפורט שהוא מאזין עליו והשני קובץ נעילה שמונע ממנו לרוץ פעמיים במקביל. מי שמגיע לקופסה שעה אחרי הפעילות לא מוצא תהליך, ולא מוצא את הקבצים שהיו מספרים עליו.
מה נשאר על הקופסה אחרי אתחול
כאן נכנס לתמונה הממצא של LevelBlue, שמשלים את התמונה מהצד של שימור האחיזה. הסקריפט שהצוות ניתח, update_c08937.pl, נמשך משרת חיצוני ועושה כמה דברים בזה אחר זה. הוא יוצר על הקופסה חשבון מקומי בשם sec_monitor ומשייך לו את הרשאות superuser, וזה לא שינוי שנעלם באתחול הבא: הוא נכתב לתוך קובץ התצורה ns.conf, הקובץ שממנו הקופסה טוענת את ההגדרות שלה בכל עלייה. הוא גם ארכב את כל ספריית התצורה לקובץ אחד תחת /tmp, מה שבפועל מכין את התצורה המלאה של המכשיר להוצאה החוצה.
שתי הקבוצות דיווחו גם על אותה פעולה על /bin/sh, קובץ ההרצה של ה-shell עצמו: הדלקה של הסיביות שגורמות לכל מי שמריץ אותו לקבל את ההרשאות של בעל הקובץ, כלומר root. מכאן כל פקודה שתרוץ על הקופסה רצה בהרשאות הגבוהות ביותר, בלי להיזדקק שוב לחולשה. הסקריפט של LevelBlue סוגר אחרי עצמו מסודר, מוחק את הארכיון ואת עצמו, "והפעולות שנצפו יחד מדגימות פעילות שחורגת מאימות בסיסי של החולשה", כתבו שם. בצד של Mandiant, חלק מהווריאנטים מנקים גם את ההתייחסות לספרייה שממנה הותקנו משורות ה-crontab.
אז למה דווקא הקופסאות האלה?
את ההסבר לכל הקמפיין Mandiant כותבת במשפט אחד: המכשירים האלה "נשארים מטרה אטרקטיבית כי הם חשופים לאינטרנט, יושבים מחוץ להישג ידם של כלי EDR, ולעיתים מאחסנים או מעבדים פרטי אימות שאפשר להשתמש בהם כדי להתקדם עמוק יותר לתוך הרשת".
שלושת החלקים האלה מופיעים כאן בדיוק. שער VPN חייב להיות חשוף לאינטרנט כדי לתפקד, אחרת אין לעובדים דרך להתחבר. כלי ה-EDR שמותקנים על ה-endpoint-ים ברשת לא מותקנים על מערכת ההפעלה הסגורה של הקופסה, כך שה-web shell שרץ עליה לא נראה לאף סוכן. והקופסה עצמה מעבדת את פרטי האימות של כל מי שמתחבר מהבית. מי שמחזיק אותה לא צריך להתקדם הרבה.
מה זה אומר בפועל
אם יש לכם NetScaler ADC או Gateway, התיקון הוא הצעד הראשון ולא האחרון. הדוח ממליץ לעלות לגרסה 14.1-73.37 ומעלה במסלול 14.1, או ל-13.1-64.23 ומעלה במסלול 13.1, עם גרסאות נפרדות ל-FIPS ול-NDcPP. אבל קופסה שנפרצה לפני העדכון נשארת פרוצה גם אחריו, כי שימור האחיזה כאן יושב בהגדרות ובתצורה, לא בחולשה שנסגרה.
מה ששווה בדיקה ידנית זה בעיקר שלושה דברים: שורות handler בקובץ ההגדרות של שרת ה-web שמורות עליו להריץ כקוד סיומות שלא אמורות להיות קוד, חשבונות בתצורה שאף אחד אצלכם לא יצר, וההרשאות של /bin/sh. שתי הקבוצות פרסמו רשימות סימנים מלאות, וכתובות ה-IP וה-header-ים החריגים שמופיעים בהן שווים חיפוש ביומנים אחורה עד תחילת ספטמבר.
תגובות