מעמקי הווירטואליזציה של Windows (חלק 2) — זיכרון שאפילו הליבה לא יכולה לראות: איך VBS, HVCI ו-Credential Guard עובדים
· Go Komura · Windows, וירטואליזציה, אבטחה, VBS, HVCI, Credential Guard
הייתה תקופה שבה הרשאות מנהל היו ה”יעד” לתוקף ב-Windows. טוענים מנהל התקן ליבה כמנהל, מריקים את הזיכרון של תהליך LSASS, ויש לכם גיבובי סיסמאות וכרטיסי Kerberos. משם זו רק שאלה של הליכה למחשב אחר עם הגיבובים הגנובים.
ב-Windows 11 הנוכחי עם Credential Guard רץ — המצב כברירת מחדל מ-22H2 ואילך במכשירים שעומדים בדרישות הרישיון כמו Enterprise ו-Education, ועוד דרישות החומרה — מחברת התווים הזו לא עובדת. תוקף שלקח במלואה את הליבה יכול לחפש בזיכרון כמה שהוא רוצה, והגיבובים האמיתיים של אישורי המתחם המוגנים לא נמצאים “בתוך מערכת ההפעלה הזו”. אם זה לא רץ, הסכנה הישנה נשארת, אז קראו זאת יחד עם שיטות האישור בהמשך המאמר.
אז איפה הם? התשובה היא “עולם אחר, שנוצר בתוך אותו מחשב”. כפי שראינו בחלק 1, Windows המארח רץ במחיצת השורש מעל ההיפרווייזור (“היכן Windows שלכם באמת רץ?”). המאמר הזה ממשיך משם ועוקב אחרי עוד קו גבול אחד שההיפרווייזור משרטט בתוך אותה מחיצה.
השאלה שחלק 2 עונה עליה היא אחת בלבד.
לאן Windows שם סודות שאף מנהל ואף הליבה לא יכולים לקרוא?
קהל היעד הוא מפתחות, מפתחים ומפעילים שראו מילים כמו Core isolation, Memory integrity ו-Credential Guard במסך הגדרות או במקרה פתרון תקלות, ורוצים להבין את הדבר האמיתי מהמנגנון ומעלה. דרישות מוקדמות הן Windows 10/11 x64 או Windows Server עדכני (כמו בחלק 1, דיון הטבעות ו-SLAT מניח x64; ל-Arm64 יש מנגנון אחר כמו רמות חריגה). הרקע הנדרש הוא מושגי המחיצות ו-SLAT שכוסו בחלק 1. רמת הקושי היא בינונית. המטרה היא הסבר המבנה, לא מדריך להגדרת תכונות האבטחה.
1. השורה התחתונה קודם
Windows הוסיף ציר הרשאה שנקרא VTL (Virtual Trust Level) ושם את הסודות ב-VTL1. אי אפשר לקרוא זיכרון ב-VTL1 מהליבה הרגילה שרצה ב-VTL0. מה ששומר על הגבול אינו הליבה עצמה, אלא ההיפרווייזור שמחזיק את טבלאות תרגום SLAT.
זה שלד האבטחה מבוססת הווירטואליזציה (VBS). VBS משתמש בהיפרווייזור כדי ליצור סביבה מבודדת ומשכן שם תכונות אבטחה. הוא מתוכנן מתוך הנחה שהסביבה המבודדת נשארת מוגנת גם אם הליבה נפרצת.1
flowchart TB
accTitle: שני העולמות ש-VBS יוצר
accDescr: VTL0 ו-VTL1 יושבים בתוך אותה מחיצה; VTL0 מחזיק את הליבה הרגילה ואת היישומים, VTL1 מחזיק את Secure Kernel ואת תכונות האבטחה המבודדות, וההיפרווייזור שומר על הגבול
subgraph vtl0 ["VTL0 (העולם הרגיל)"]
apps["יישומים (טבעת 3)"]
ntk["ליבת NT ומנהלי התקנים (טבעת 0)"]
end
subgraph vtl1 ["VTL1 (העולם המבודד)"]
ium["תכונות אבטחה מבודדות"]
sk["Secure Kernel"]
end
hv["היפרווייזור (אוכף את הגבול דרך SLAT)"] --- vtl0
hv --- vtl1
ntk -.->|לא יכול לקרוא| ium
איור 1: יש שני עולמות בתוך Windows אחד, וליבת VTL0 לא יכולה לגשת לזיכרון VTL1.
הנקודה החשובה היא שזה אינו “הקמת מכונה וירטואלית אחרת”. VTL0 ו-VTL1 נמצאים בתוך אותה מחיצה, בתוך אותו Windows. נסתכל בתורו איך הפיצול הזה ממומש.
2. גבולות מודל הטבעות — השומר והשמור יושבים באותו גובה
אבטחת Windows המסורתית נבנתה על סולם הטבעות (רמות הרשאה). מצב משתמש (טבעת 3) נשמר על ידי מצב ליבה (טבעת 0). אז מי שומר על טבעת 0 — אף אחד לא יכול. טבעת 0 היא ההרשאה הגבוהה ביותר.
למבנה הזה יש שתי חולשות מבניות.
- הליבה אינה מונולית. בטבעת 0, לא רק Windows עצמו אלא מספר גדול של מנהלי התקנים צד שלישי רצים. אם לאחד מהם יש פגיעות, תוקף משיג ביצוע קוד בטבעת 0.
- מתוך טבעת 0, הכול גלוי. כמה שתהליך במצב משתמש כמו LSASS יגן על עצמו, הזיכרון שלו חופשי לקריאה לתוקף שלקח את הליבה. גם תכונות הגנה וגם טבלאות דפים מנוהלות על ידי הליבה עצמה.
flowchart TB
accTitle: נתיב גניבת האישורים במודל הטבעות המסורתי
accDescr: תוקף שלוקח את טבעת 0 דרך מנהל התקן פגיע יכול לקרוא זיכרון של תהליך LSASS בסמכות המלאה של הליבה ולהשיג גיבובי סיסמאות
mal["קוד תוקף"] -->|מנצל מנהל התקן פגיע| r0["לוקח שליטה בטבעת 0"]
r0 --> readall["יכול לקרוא את כל הזיכרון הפיזי"]
readall --> lsass["משיג גיבובים מזיכרון LSASS"]
lsass --> lateral["מנוצל לתנועה רוחבית למחשבים אחרים"]
איור 2: מכיוון שהשומר (הליבה) והשמור (הסודות) יושבים באותו גובה, החולשה היסודית היא שאם טבעת 0 נופלת, הכול נופל.
מה שנדרש, אם כן, הוא “מקום גבוה יותר מטבעת 0”. המקום הזה כבר הופיע בחלק 1. ההיפרווייזור רץ בהרשאה גבוהה מהליבה ומונופול על השליטה בהרשאות הגישה לזיכרון של המעבד (SLAT) מוקדם. אזור מבודד שההיפרווייזור שומר עליו מוגן גם מפני גישה מתוכנת מערכת הפעלה במצב מפקח (טבעת 0).2
3. VSM ו-VTL — הוספת עוד ציר הרשאה אחד
3.1. רמות אמון וירטואליות (VTL)
משפחת תכונות ההיפרווייזור שמספקת את הבידוד הזה נקראת VSM (Virtual Secure Mode). VSM הוא היסוד ל-Device Guard, ל-Credential Guard, ל-TPM וירטואלי וכדומה.2
המושג המרכזי של VSM הוא ה-VTL (Virtual Trust Level). הנקודות המרכזיות הן כדלקמן.2
- VTL היררכיים, וככל שהמספר גבוה יותר, ההרשאה גבוהה יותר. VTL0 הוא הנמוך ביותר; VTL1 בעל הרשאה גבוהה יותר מ-VTL0.
- ארכיטקטונית מוגדרות עד 16 רמות, אבל מה שממומש כרגע הוא שתיים: VTL0 ו-VTL1.
- לכל VTL יש הגנות גישה לזיכרון עצמאיות. ההגנות האלה מנוהלות על ידי ההיפרווייזור מול מרחב הכתובות הפיזי של המחיצה, כך שתוכנת מערכת בתוך המחיצה לא יכולה לשנות אותן.
- למעבד וירטואלי יש מצב אוגרים ומנגנון פסיקות נפרדים לכל VTL, ו-VTL נמוך יותר לא יכול להציץ במצב של VTL גבוה יותר.
flowchart TB
accTitle: שלוש עצמאויות שמרכיבות את בידוד VTL
accDescr: הגנות גישה לזיכרון, מצב אוגרי מעבד וירטואלי ומנגנון פסיקות עצמאיים לכל VTL, ו-VTL נמוך יותר לא יכול לגעת באף אחד מהם ב-VTL גבוה יותר
vtl["מה עצמאי לכל VTL"] --> m1["הגנות גישה לזיכרון"]
vtl --> m2["מצב אוגרי מעבד וירטואלי"]
vtl --> m3["מנגנון פסיקות"]
m1 -.-> rule["VTL נמוך לא יכול לגעת ב-VTL גבוה"]
m2 -.-> rule
m3 -.-> rule
איור 3: הפיכת לא רק הזיכרון אלא גם מצב המעבד והפסיקות לעולם נפרד היא החבילה התלת-חלקית שלא משאירה חור הצצה.
אם טבעות (0 ו-3) הן הציר שמפריד “מערכת הפעלה ויישומים”, VTL הם ציר שני שמפריד “העולם הרגיל והעולם המבודד”. שני הצירים אורתוגונליים, ובתוך VTL1 יש גם מצב ליבה וגם מצב משתמש.
flowchart TB
accTitle: ארבעה אזורים שנוצרים משני צירי הטבעות וה-VTL
accDescr: ציר הטבעות מפריד מצב ליבה ממצב משתמש, ציר ה-VTL מפריד את העולם הרגיל מהעולם המבודד, והשילוב מייצר ארבעה אזורים: יישומים רגילים, ליבת NT, trustlets של IUM, ו-Secure Kernel
subgraph ax0 ["VTL0 (עולם רגיל)"]
a0["טבעת 3: יישומים רגילים"]
k0["טבעת 0: ליבת NT ומנהלי התקנים"]
end
subgraph ax1 ["VTL1 (עולם מבודד)"]
a1["טבעת 3: IUM (trustlets)"]
k1["טבעת 0: Secure Kernel"]
end
a0 --- k0
a1 --- k1
k0 ~~~ a1
איור 4: עכשיו יש שני צירי הרשאה, ו”האם זו הליבה?” ו”האם זה העולם המבודד?” הפכו לשאלות נפרדות.
3.2. מהות הגבול היא SLAT
בחלק 1 אמרנו שטבלאות התרגום ברמה השנייה שממפות כתובת פיזית של האורח (GPA) על RAM אמיתי (SPA) — SLAT — מוחזקות על ידי ההיפרווייזור. VSM משתמש בדיוק בתכונה הזו. בידוד VTL נוצר באמצעות ההיפרווייזור של Hyper-V ו-SLAT.3
כש-VTL1 מכריז “את הזיכרון הזה אין להראות ל-VTL0”, ההיפרווייזור מוריד את הרשאת הגישה לדף הזה מטבלאות התרגום של VTL0. מכאן ואילך, גם אם ליבת VTL0 מנסה לגעת בכתובת הזו, היא נדחית בשלב תרגום הכתובות של המעבד. זה חסר תועלת שהליבה תשכתב את טבלאות הדפים שלה עצמה כמה שהיא רוצה. טבלאות הדפים (GVA→GPA) אולי שייכות לליבה, אבל התרגום שמעבר לזה (GPA→SPA) והרשאת הגישה הסופית שייכים להיפרווייזור.
flowchart TB
accTitle: הזרימה שבה גישה מ-VTL0 לזיכרון VTL1 נדחית
accDescr: כשליבת VTL0 מנסה לקרוא זיכרון VTL1, היא יכולה לעבור את טבלת הדפים שלה עצמה אבל נדחית על ידי הגנת הגישה של SLAT, והשליטה עוברת להיפרווייזור
try["ליבת VTL0 מנסה לקרוא דף VTL1"] --> pt["עוברת את טבלת הדפים של הליבה"]
pt --> slat{"האם הגנת הגישה של SLAT מתירה?"}
slat -->|לא מותר| deny["ההיפרווייזור מתערב ודוחה גישה"]
slat -->|מותר| ok["גישת זיכרון רגילה"]
deny -.-> point["מוגן בשכבה שהליבה לא יכולה לשנות"]
איור 5: המחסום יושב מחוץ לליבה, והגנות SLAT לא ניתנות לשינוי על ידי תוכנה בתוך המחיצה.
בחלק 1 של סדרת הזיכרון כתבנו ש”VAD, PTE ותכונות הגנה מחליטים אם גישה מותרת”. בסביבת VBS אפשר לארגן זאת כך: אחרי שכל אלה עברו, עדיין מחכה מחסום SLAT.
3.3. Secure Kernel ו-IUM
מה שרץ בתוך VTL1 אינו ליבת NT הרגילה אלא ליבה קטנה שנקראת Secure Kernel. מצב משתמש ב-VTL1 נקרא IUM (Isolated User Mode), והתוכניות שרצות שם נקראות trustlets (תהליכים מהימנים).3
Trustlet לא יכול לעשות הכול כמו תהליך רגיל. רוב קריאות המערכת ממושלות לליבת NT בצד VTL0 והעבודה מבוקשת שם.3 VTL1 אינו “עולם עליון שיכול הכול”; הוא בנוי במכוון קטן, ככספת שמחזיקה סודות. ככל שפחות קוד אפשר להכניס לכספת, כך משטח התקיפה קטן יותר.
flowchart TB
accTitle: זרימת קריאות המערכת של trustlet
accDescr: Trustlet ב-VTL1 לא מטפל ברוב קריאות המערכת בעצמו; הוא ממשל אותן לליבת NT של VTL0 ומקבל רק את התוצאה, וזה שומר על VTL1 קטן
tl["Trustlet (IUM ב-VTL1)"] --> sc{"נדרשת קריאת מערכת"}
sc -->|ברוב המקרים| mar["הבקשה ממושלת לליבת NT של VTL0"]
mar --> res["רק התוצאה חוזרת"]
res -.-> small["VTL1 נשאר קטן, ומצמצם את משטח התקיפה"]
איור 6: לכספת אין מתקנים משלה; היא מוציאה את העבודות החוצה וממשיכה לשמור רק על הסודות.
4. HVCI — אימות שלמות קוד הליבה בכספת
4.1. מה מאומת
התכונה הנציגה הראשונה שיושבת על VBS היא Memory integrity — HVCI (שלמות קוד מוגנת-היפרווייזור). ל-Windows יש מנגנון שלמות קוד שבודק מנהלי התקנים וקבצים בינאריים במצב ליבה לפני שהם מתחילים ולא טוען כאלה לא חתומים או לא מהימנים. HVCI מריץ את האימות הזה בתוך הסביבה המבודדת של VBS.1
הסיבה להעברת לוגיקת האימות עצמה ל-VTL1 היא בדיוק החולשה בסעיף 2. אם קוד האימות יושב בתוך ליבת VTL0, תוקף שלקח את הליבה יכול להחליף את האימות. אם הוא ב-VTL1, היד המחליפה לא יכולה להגיע אליו.
flowchart TB
accTitle: ההבדל שנוצר ממקום הימצאות קוד האימות
accDescr: אם קוד האימות יושב בתוך ליבת VTL0 אפשר להשבית אותו בלקיחת הליבה, אבל אם הוא ב-VTL1 גם תוקף שלקח את הליבה לא יכול להגיע אליו והאימות מוגן
atk["תוקף שלקח את הליבה"] --> q{"היכן יושב אימות שלמות הקוד?"}
q -->|"בתוך ליבת VTL0 (קלאסי)"| bad["אפשר להחליף את לוגיקת האימות"]
q -->|"סביבה מבודדת ב-VTL1 (HVCI)"| good["ההחלפה מחוץ להישג יד"]
bad --> res1["קוד לא חתום יכול לרוץ בליבה"]
good --> res2["האימות ממשיך לעבוד אחרי פריצת הליבה"]
איור 7: אל תשימו את המחסום בתוך הצד שעלול להיפרץ — העתקת לוגיקת האימות הזו היא מהות HVCI.
4.2. הכללים לדפים ברי-ביצוע
ההשפעה של HVCI אינה מוגבלת ל”בדיקה בהפעלה”. היא גם מגבילה הקצאת זיכרון ליבה.4
- דף ליבה הופך לבר-ביצוע רק אחרי שעבר אימות שלמות קוד.
- דף בר-ביצוע לא הופך לבר-כתיבה (מה שנקרא W^X).
כששני אלה במקום, גם אם פגיעות כמו גלישת מאגר נותנת לכם לשכתב זיכרון ליבה, אי אפשר להכניס את התוכן המשכתב לביצוע. דף בר-ביצוע אי אפשר לשכתב, ודף שאפשר לשכתב אי אפשר לבצע.4 הגיבוי הסופי של הרשאת הביצוע הוא זכות הביצוע בצד SLAT, שליבת VTL0 לא יכולה לתפעל.
flowchart TB
accTitle: עד שדף ליבה הופך לבר-ביצוע בסביבת HVCI
accDescr: בקשת טעינת מנהל התקן מקבלת אימות שלמות קוד בסביבה המבודדת של VBS; אם היא עוברת היא מותרת כדף בר-ביצוע ולא-בר-כתיבה, ואם היא נכשלת היא נחסמת ונרשמת ביומן CodeIntegrity
load["בקשה לטעון ולבצע קוד ליבה"] --> verify{"אימות שלמות קוד בסביבה המבודדת"}
verify -->|עובר| exec["מותר כדף בר-ביצוע (כתיבות אסורות)"]
verify -->|נכשל| block["הטעינה נחסמת"]
block --> log["נרשם ביומן CodeIntegrity Operational (מזהה אירוע 3087)"]
exec -.-> wx["דפים ברי-כתיבה נשארים לא-ברי-ביצוע"]
איור 8: אימות הכלל שלא נותן לביצוע ולכתיבה לדור בכפיפה אחת נעשה בצד VTL1, וליבת VTL0 לא יכולה להפוך אותו.
מעקב אחרי זה מנקודת המבט של תוקף מבהיר איך הכלל נכנס לתוקף.
flowchart TB
accTitle: הזרימה שבה הזרקת קוד נכשלת בסביבת HVCI
accDescr: גם אם פגיעות נותנת לשכתב זיכרון ליבה, דף שאפשר לכתוב אליו אינו בר-ביצוע, ודף בר-ביצוע אי אפשר לשכתב מלכתחילה, כך שאי אפשר להכניס את הקוד המוזרק לביצוע
inj["ניסיון לשבש זיכרון ליבה דרך פגיעות"] --> which{"איזה דף הוא היעד?"}
which -->|דף בר-כתיבה| wok["הכתיבה מצליחה"]
which -->|דף בר-ביצוע| xfail["הכתיבה עצמה בלתי אפשרית"]
wok --> nx["אבל הדף הזה אינו בר-ביצוע"]
nx --> dead["אי אפשר לבצע את הקוד המוזרק"]
xfail --> dead
איור 9: המשמעות של אי-חציית דפים ברי-כתיבה עם דפים ברי-הרצה היא שלאיזה כניסה שלא תיקחו, מגיעים למבוי סתום.
4.3. המחיר בתאימות מנהלי התקנים
הכלל הזה מתנגש עם מנהלי התקנים בעיצוב ישן. כאלה שמשכתבים את הקוד שלהם עצמם בזמן ריצה, שאין להם חתימה, או שדורשים זיכרון שהוא גם בר-ביצוע וגם בר-כתיבה — מנהלי התקנים כאלה אי אפשר לטעון בסביבת HVCI. את עובדת החסימה אפשר לאשר במציג האירועים תחת Applications and Services Logs\Microsoft\Windows\CodeIntegrity\Operational (מזהה אירוע 3087 הוא הנציג).5
“אחרי שהפעלתי Memory integrity, ציוד היקפי הפסיק לעבוד” — בהרבה מקרים, זו הזהות האמיתית של התקלה. התגובה הנכונה היא לעדכן למנהל התקן תואם-HVCI; השבתת Memory integrity צריכה להיחשב כמוצא אחרון שמוותר על ההגנה במלואה. אם אתם מעורבים באימות הזה מנקודת מבט של פיתוח מנהלי התקנים, ראו גם את מאמר מנהל המסנן (“מנהלי התקן Minifilter ב-Windows”).
flowchart TB
accTitle: בידוד המקרה שבו ציוד היקפי מפסיק לעבוד תחת Memory integrity
accDescr: מזהים את מנהל ההתקן החסום ביומן CodeIntegrity Operational; התגובה הנכונה היא לעדכן לגרסה תואמת-HVCI, לבקש מהספק אם אין כזו, ולהתייחס להשבתה כמוצא אחרון שלא הופכים לקבוע
sym["התקן מפסיק לעבוד אחרי הפעלת Memory integrity"] --> log2["זיהוי מנהל ההתקן החסום ביומן CodeIntegrity"]
log2 --> upd{"יש מנהל התקן תואם-HVCI?"}
upd -->|כן| fix2["עדכון ופתרון תוך השארת HVCI דולק"]
upd -->|לא| ask2["בקשה מהספק לגרסה תואמת"]
ask2 -.-> temp["השבתה היא מוצא אחרון, לא הגדרה קבועה"]
איור 10: הדבר הראשון להסתכל עליו אינו מסך ההגדרות אלא היומן, ומזהה אירוע 3087 יודע מי חסם את הטעינה.
5. Credential Guard — הגיבובים נמצאים בתוך LSAIso
5.1. LSASS ו-LSAIso
התכונה הנציגה השנייה שיושבת על VBS היא התשובה לחידה שבפתיחה: Credential Guard.
Windows המסורתי שמר גיבובי NTLM וכרטיסי Kerberos בזיכרון של תהליך LSA (lsass.exe). כש-Credential Guard מופעל, אחסון הסודות המוגנים מבין אלה — גיבובי NTLM של אישורי מתחם ו-TGT של Kerberos (Ticket Granting Tickets) — עובר ל-LSAIso.exe, trustlet שרץ ב-IUM ב-VTL1.6
- lsass.exe (VTL0) ממשיך לרוץ כדלפק הקבלה לעיבוד אימות, כמו קודם.
- הסודות האמיתיים מוחזקים על ידי LSAIso.exe (VTL1) ואי אפשר לגשת אליהם מ-VTL0.
- השניים מתקשרים דרך RPC (Remote Procedure Call).
- LSAIso לא מארח מנהלי התקנים כלל, ומשכן רק את המינימום של קבצים בינאריים חתומים. החתימות מאומתות עם אישור ש-VBS סומך עליו.6
flowchart TB
accTitle: איפה האישורים יושבים כש-Credential Guard מופעל
accDescr: lsass ב-VTL0 מתקשר עם LSAIso ב-VTL1 דרך RPC כדלפק האימות; הגיבובים וה-TGT האמיתיים של אישורי מתחם מוגנים מוחזקים על ידי LSAIso, כך שתוקף שמשיג הרשאות מנהל ב-VTL0 ומריק את lsass עדיין לא מקבל את המהות המוגנת
subgraph v0 ["VTL0"]
lsassP["lsass.exe (דלפק האימות)"]
att["תוקף (הרשאות מנהל)"]
end
subgraph v1 ["VTL1"]
iso["LSAIso.exe (כספת לסודות)"]
end
lsassP <-->|RPC| iso
att -->|הריקת זיכרון| lsassP
att -.->|לא יכול להגיע| iso
איור 11: מכיוון שדלפק הקבלה והכספת הופרדו, הריקת lsass כבר לא מניבה את הגיבובים האמיתיים של אישורי המתחם המוגנים.
מ-Windows 11 גרסה 22H2 ואילך, במכשירים שעומדים בדרישות הרישיון (Enterprise E3/E5, Education A3/A5) ובדרישות החומרה, VBS ו-Credential Guard מופעלים כברירת מחדל. במהדורות כמו Pro, Credential Guard אינו מופעל אוטומטית (יש חריגים, כמו כשמחשב שהופעל תחת רישיון מתאים מורד לאחר מכן בדרגה).7 “מחברת התווים כבר לא עובדת” שבפתיחה אינו סיפור על מוצר הרחבה מיוחד; זהו המצב הסטנדרטי של Windows הנוכחי במהדורות היעד.
flowchart TB
accTitle: זרימת האישורים מכניסה ועד אימות
accDescr: אחרי כניסה הסודות האמיתיים מאוחסנים ב-LSAIso ב-VTL1; בכל פעם שנדרש אימות, lsass ב-VTL0 מבקש חישוב דרך RPC, ורק תוצאת עיבוד האימות חוזרת ל-VTL0 בלי שהסודות ארוכי הטווח המוגנים עצמם יוחזרו
signin["המשתמש נכנס"] --> front["lsass מטפל כדלפק הקבלה"]
front --> store["הסודות האמיתיים מאוחסנים ב-LSAIso"]
auth["בקשות אימות הבאות"] --> front
front -->|"בקשת חישוב דרך RPC"| store
store -->|"מחזיר את התוצאה (לא מחזיר את הסוד)"| front
איור 12: הסודות ארוכי הטווח המוגנים עצמם לעולם לא עוזבים את הכספת; מה שחוזר ל-VTL0 הוא תוצאת עיבוד האימות, כמו כרטיס.
5.2. דעו במדויק מה אינו מוגן
Credential Guard אינו מגן לכל מטרה. מה שמוגן הוא גיבובי NTLM של אישורי מתחם, TGT של Kerberos (Ticket Granting Tickets), ודברים שנשמרו כאישורי מתחם. הבאים מחוץ להיקף.8
- כרטיסי שירות של Kerberos (TGT מוגנים)
- אישורים של חשבונות מקומיים ושל חשבונות Microsoft
- גניבת קלט על ידי keylogger, ותקיפות פיזיות
- אישורים בנתיבים שמשתמשים ב-NTLMv1, MS-CHAPv2, Digest או CredSSP
- הפנים של תוכנת צד שלישי שמנהלת אישורים בעצמה
בנוסף, כש-Credential Guard מופעל, NTLMv1, האצלת Kerberos לא-מוגבלת וכדומה הופכים לבלתי ניתנים לשימוש, כך שמערכות עסקיות שתלויות באימות מיושן צריכות בדיקת תאימות.8 לא “מפעילים ונגמר”, אלא תופסים מה בפנים ומה מחוץ לטווח ההגנה וממלאים את השאר בבקרות אחרות — זו הדרך הנכונה להשתמש בזה בפועל.
flowchart TB
accTitle: טווח ההגנה של Credential Guard
accDescr: גיבובי NTLM של מתחם ו-TGT, ואישורי מתחם שמורים, מוגנים, ואילו כרטיסי שירות, חשבונות מקומיים, keylogger, תקיפות פיזיות ואישורים שמורים באופן פרטי על ידי יישום מחוץ להיקף
scope{"באיזה צד של גבול ההגנה הסוד הזה?"} --> inA["גיבובי NTLM של מתחם ו-TGT"]
scope --> outA["כרטיסי שירות וחשבונות מקומיים"]
inA --> prot["מוגן ב-LSAIso"]
outA --> unprot["לא מוגן (נדרשות בקרות אחרות)"]
unprot -.-> outB["הקלדות, תקיפות פיזיות ומאגרים פרטיים של יישום גם מחוץ להיקף"]
איור 13: טווח ההגנה מצויר בקו ברור, ומחוץ לקו ממלאים באימות רב-גורמי ובתכנון בצד היישום.
6. ראו זאת בעצמכם
אפשר לאשר את מצב הריצה של VBS ושל כל תכונה במחשב שלכם.
Get-CimInstance -Namespace root/Microsoft/Windows/DeviceGuard `
-ClassName Win32_DeviceGuard |
Select-Object VirtualizationBasedSecurityStatus,
SecurityServicesConfigured,
SecurityServicesRunning
איך לקרוא זאת כדלקמן.9
- אם
VirtualizationBasedSecurityStatusהוא 2, VBS מופעל ורץ. - אם
SecurityServicesRunningמכיל 1, Credential Guard רץ; אם הוא מכיל 2, Memory integrity (HVCI) רץ.
כדי לאשר את מצב הריצה בממשק הגרפי, הסתכלו על השדה “Virtualization-based security” ב-msinfo32 (שירותים שרצים רשומים, כמו “Hypervisor enforced Code Integrity”). מתג “Memory integrity” תחת “Device security > Core isolation” ביישום האבטחה של Windows הוא מסך שמשקף הגדרות; הוא יכול להיראות דולק גם בזמן ש-HVCI לא באמת רץ — בהמתנה לאתחול מיד אחרי הפעלה, או בבעיית תאימות בהפעלה — ולכן שפטו אם זה רץ מ-msinfo32 או מ-SecurityServicesRunning של Win32_DeviceGuard.5
יש גם עקבה בלשונית הפרטים של מנהל המשימות. במחשב שבו VBS רץ תראו תהליך בשם “Secure System”. LsaIso.exe הוא התהליך שמופיע כששירות Isolated LSA מאוחסן ב-VTL1, והוא בדרך כלל לא מופיע בתצורה שבה רק HVCI מופעל. נוכחות או היעדר תהליך הם רק עקבה, עם זאת, ולכן שפטו אם Credential Guard רץ מ-SecurityServicesRunning (האם הוא מכיל 1), כפי שלמעלה. שניהם חלונות גלויים מ-VTL0 שמתאימים לעולם בצד VTL1.
flowchart TB
accTitle: איך לבדוק שתכונות הקשורות ל-VBS רצות
accDescr: מאשרים ש-VBS רץ בשאילתה ל-Win32_DeviceGuard, שופטים את Credential Guard ו-HVCI מערכי SecurityServicesRunning, ומסתכלים על יומן CodeIntegrity לבעיות מנהלי התקנים
q0["Win32_DeviceGuard"] --> q1{"מצב VBS הוא 2?"}
q1 -->|לא| off["VBS לא רץ"]
q1 -->|כן| q2{"מכיל 1 או 2?"}
q2 -->|1| cg["Credential Guard דולק"]
q2 -->|2| hvciR["HVCI דולק"]
hvciR -.-> ev["CodeIntegrity 3087"]
איור 14: אישור מצב מתקדם בשלושה שלבים: VBS עצמו, כל שירות מעליו, והיומן כשמתרחשת בעיה.
7. שלוש קריאות שגויות להימנע מהן בפועל
7.1. “הגנה על הרשאות מנהל מספיקה. VBS הוא סיפור של צד שרת”
מה ש-Credential Guard מונע הוא התפשטות נזק אחרי שלקחו הרשאות מנהל (הוצאת גיבובים ותנועה רוחבית). במילים אחרות VBS הוא שכבת הגנה לעומק שמניחה פריצה, והוא אפקטיבי במחשבי לקוח. ב-Windows 11 שעומד בדרישות, הפעלה-כברירת-מחדל היא הסטנדרט, ולכן היציבה הנכונה אינה “לזה אין קשר אלינו” אלא “נהלו תאימות מתוך הנחה שזה כבר רץ”.
flowchart TB
accTitle: שלבי פריצה והיכן VBS נכנס לתוקף
accDescr: גישה ראשונית מכוסה בבקרות אחרות כמו אימות רב-גורמי והדרכה; HVCI חוסם הזרקת קוד לליבה אחרי העלאת הרשאות; Credential Guard חוסם גניבת סודות מתחם מוגנים ותנועה רוחבית, אבל לא מגיע לסודות מחוץ להיקף שלו
s1["גישה ראשונית (פישינג וכדומה)"] --> s2["העלאת הרשאות"]
s2 --> s3["הזרקת קוד לליבה"]
s3 --> s4["גניבת סודות מתחם מוגנים ותנועה רוחבית"]
s1 -.-> d1["MFA, הדרכה ו-EDR מכסים זאת"]
s3 -.-> d2["HVCI חוסם את השלב הזה"]
s4 -.-> d3["Credential Guard חוסם זאת (סודות מוגנים בלבד)"]
איור 15: VBS אינו טכנולוגיית “אל תתנו להם להיכנס”; הוא טכנולוגיית “אל תתנו להם לנצח אחרי שהם בפנים”, והשלב שהוא שומר שונה.
7.2. “אם Memory integrity גורם לבעיה, פשוט מכבים אותו”
כיבוי יגרום לדברים לעבוד לרגע, אבל הוא מוריד את המחסום מפני הזרקת קוד לליבה במלואו. התגובה הנכונה היא קודם לזהות את מנהל ההתקן החסום ביומן CodeIntegrity ולהחיל את הגרסה המעודכנת של הספק. גם אם משביתים זמנית לאימות, מומלץ תפעול שלא הופך זאת להגדרה קבועה.
7.3. “עם Credential Guard, אי אפשר לגנוב סיסמאות”
זו ביטחון-יתר מערבוב טווח ההגנה. כרטיסי שירות, חשבונות מקומיים, ההקלדות עצמן, ואישורים שמורים באופן פרטי על ידי יישום מחוץ להיקף.8 פישינג ו-keylogger צריכים בקרות אחרות (אימות רב-גורמי, Windows Hello, וסקירה של ניהול אישורים בצד היישום).
8. סיכום
- VBS משתמש בהיפרווייזור כדי ליצור סביבה מבודדת ומגן על תכונות אבטחה מתוך הנחה שהליבה יכולה להיפרץ.1
- יחידת הבידוד היא ה-VTL; כרגע ממומשות שתי רמות, VTL0 (העולם הרגיל) ו-VTL1 (Secure Kernel ו-IUM).2
- מהות הגבול היא הגנת גישה לזיכרון של SLAT, שתוכנה בתוך המחיצה — כולל הליבה — לא יכולה לשנות.2
- HVCI מריץ אימות שלמות קוד בסביבה המבודדת ואוכף “לא בר-ביצוע עד שהאימות עובר” ו”דף בר-ביצוע אינו בר-כתיבה”.4 המחיר הוא שצריך לנהל תאימות מנהלי התקנים.5
- Credential Guard מבודד גיבובי NTLM של אישורי מתחם ו-TGT ל-LSAIso ב-VTL1. מ-Windows 11 22H2 ואילך הוא מופעל כברירת מחדל במכשירים שעומדים בדרישות הרישיון (Enterprise, Education) ובדרישות החומרה (השתמשו בזה יחד עם בדיקת מצב הריצה).67
- אפשר לאשר את מצב הריצה מ-SecurityServicesRunning של
Win32_DeviceGuard(1 = Credential Guard, 2 = HVCI).9
ההמשך בחלק 3, “מכונות וירטואליות שעולות בשניות — WSL2, Windows Sandbox וקונטיינרים”.
עד כאן הסתכלנו על וירטואליזציה מצד “חוזק הבידוד”. הפרק האחרון מסתכל מהצד ההפוך, צד ה”קלילות”, ועוקב אחרי היכן המכונות הווירטואליות קלות-המשקל שהשליכו את משקל מכונה וירטואלית מלאה מקצרות פינות.
מאמרים קשורים
- מעמקי הווירטואליזציה של Windows (חלק 1) — היכן Windows שלכם באמת רץ? ההיפרווייזור והמחיצות
- מעמקי הזיכרון של Windows (חלק 1) — הרגע שבו כתובת וירטואלית הופכת ל-RAM פיזי: שגיאת דף מההתחלה ועד הסוף
- מעמקי ה-I/O של Windows (חלק 6, אחרון) — מנהלי מסנן ו-Minifilter: למה Procmon וסורקי אנטי-וירוס יכולים ליירט I/O
- פענוח קודי שגיאה של Windows — המבנה התלת-שכבתי של שגיאות Win32, HRESULT ו-NTSTATUS
תחומי ייעוץ קשורים
KomuraSoft LLC מטפלת בחקירות תאימות בין יישומי Windows לתכונות אבטחה, בניתוח כשלים שנגרמו ממנהלי התקנים, ובאימות טכני של סביבות מחשב פנים-ארגוניות.
קישורים
-
Microsoft Learn, Virtualization-based Security (VBS). על כך ש-VBS משתמש בווירטואליזציית חומרה ובהיפרווייזור של Windows כדי ליצור סביבה מבודדת ומתייחס אליה כשורש האמון של מערכת ההפעלה מתוך הנחה שהליבה יכולה להיפרץ; על כך ש-Memory integrity מריץ אימות שלמות קוד במצב ליבה בתוך הסביבה המבודדת הזו; ועל כך ש-SLAT הוא דרישה קשיחה ל-VBS. ↩ ↩2 ↩3
-
Microsoft Learn, Virtual Secure Mode. על כך ש-VSM הוא היסוד ל-Device Guard, ל-Credential Guard, ל-TPM וירטואלי וכדומה; על כך שגישה לאזורים מבודדים נשלטת רק דרך ההיפרווייזור ומוגנת גם מתוכנת מערכת הפעלה בטבעת 0; על כך ש-VTL היררכיים עם 2 מתוך מקסימום 16 רמות ממומשות; ועל כך שהגנות גישה לזיכרון לפי-VTL אינן ניתנות לשינוי על ידי תוכנת מערכת בתוך המחיצה. ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn, Isolated User Mode (IUM) Processes. על כך ש-VSM יוצר VTL באמצעות ההיפרווייזור של Hyper-V ו-SLAT; על כך ש-Secure Kernel ו-IUM רצים ב-VTL1; על כך ש-trustlets ממשלים קריאות מערכת לליבת VTL0; ועל כך ש-LSAIso רץ ב-VTL1 ומתקשר עם lsass דרך RPC. ↩ ↩2 ↩3
-
Microsoft Learn, Memory integrity and virtualization-based security. על כך ש-Memory integrity (HVCI) מריץ אימות שלמות קוד בסביבה מבודדת, ועל כך שדפי זיכרון ליבה הופכים לברי-ביצוע רק אחרי שעברו אימות ודפים ברי-ביצוע לא הופכים לברי-כתיבה. ↩ ↩2 ↩3
-
Microsoft Learn, Memory integrity and VBS enablement. על כך ש-Memory integrity מופעל כברירת מחדל בהתקנה נקייה של Windows 11 אם החומרה תואמת; על אישור מצב ב-msinfo32 וביישום האבטחה של Windows; ועל אישור מנהל התקן חסום דרך מזהה אירוע 3087 ביומן CodeIntegrity Operational. ↩ ↩2 ↩3
-
Microsoft Learn, How Credential Guard works. על כך שה-LSA מתקשר עם תהליך Isolated LSA (LSAIso.exe) כדי לאחסן סודות כש-Credential Guard מופעל; על כך שהנתונים המאוחסנים מוגנים על ידי VBS ואינם נגישים משאר מערכת ההפעלה; ועל כך שתהליך Isolated LSA לא מארח מנהלי התקנים ומשכן רק מינימום של קבצים בינאריים מאומתי-חתימה. ↩ ↩2 ↩3
-
Microsoft Learn, Credential Guard overview. על כך ש-Credential Guard מופעל כברירת מחדל מ-Windows 11 גרסה 22H2 ואילך במכשירים שעומדים בדרישות הרישיון, החומרה והתוכנה ולא הושבתו במפורש; על כך שהמהדורות/הרישיונות המתאימים הם Enterprise (E3/E5) ו-Education (A3/A5), ו-Pro מחוץ להיקף; ועל כך שמחשב Pro שהופעל קודם תחת רישיון מתאים נשאר יעד מופעל-כברירת-מחדל אחרי הורדת דרגה. ↩ ↩2
-
Microsoft Learn, Credential Guard protection limits. על כך שכרטיסי שירות, חשבונות מקומיים, keylogger, תקיפות פיזיות וכדומה מחוץ להיקף ההגנה של Credential Guard; על כך ש-TGT מוגנים בעוד שכרטיסי שירות אינם; ועל כך ש-NTLMv1 והאצלה לא-מוגבלת הופכים לבלתי ניתנים לשימוש כשהוא מופעל. ↩ ↩2 ↩3
-
Microsoft Learn, Enable virtualization-based protection of code integrity. על איך לאשר את מצב VBS ו-Memory integrity דרך המחלקה Win32_DeviceGuard, ועל משמעות ערכי SecurityServicesRunning (1 הוא Credential Guard, 2 הוא Memory integrity). ↩ ↩2
מאמרים קשורים
מאמרים עדכניים עם אותן תגיות, להעמקה בנושאים קרובים.
מעמקי הווירטואליזציה של Windows (חלק 3) — מכונות וירטואליות שעולות בשניות: למה WSL2, Windows Sandbox וקונטיינרים כל כך קלים
למה WSL2 ו-Windows Sandbox עולים בשניות ומרגישים כל כך קלים? המאמר מסביר את המנגנונים, מתמונות בסיס דינמיות ומ-direct map דרך הקצאת זיכרו...
מעמקי הווירטואליזציה של Windows (חלק 1) — היכן Windows שלכם באמת רץ? ההיפרווייזור והמחיצות
כשמפעילים Hyper-V, Windows המארח עצמו רץ מעל ההיפרווייזור כמחיצת השורש. המאמר מסביר את יסודות הווירטואליזציה דרך התפקידים של VT-x, SLAT ...
Named Pipes בפועל — ה-IPC הסטנדרטי של Windows, מתכנון ועד אבטחה
מדריך מעשי ל-Named Pipes, התקשורת הסטנדרטית בין תהליכים ב-Windows. המאמר מסדר ממקורות ראשוניים את הבחירה בין מצב בתים למצב הודעות, תכנון ...
Win32 Thread Pool API — מקביליות בלי ליצור תהליכונים, דרך CreateThreadpoolWork
מפזרים קריאות CreateThread בכל הקוד הנייטיב? המאמר מסביר את ה-API של מאגר התהליכונים של Win32 שעוצב מחדש ב-Vista — ארבעת האובייקטים work,...
רשימת בדיקה לטיפול בטוח בתהליכי ילד ביישום Windows
כדי לטפל בבטחה בתהליכי ילד ביישום Windows, תכנון הבעלות על עץ התהליכים ונוהל הסיום חשוב יותר מבחירת ה-API להפעלה. המאמר מסדר את Job Objec...
נושאים קשורים
העמודים האלה ממקמים את הנושא בהקשר רחב יותר של שירותים והחלטות.
נושאים טכניים ב-Windows
שער לנושאי פיתוח Windows, חקירת תקלות וניצול נכסים קיימים.
שירותים הקשורים לנושא הזה
המאמר קשור ישירות לשירותים הבאים.
פיתוח יישומי Windows
יישומים עסקיים, חיבור התקנים וכלי תקשורת, מהגדרת הדרישות ועד הפיתוח.
שאלות נפוצות
שאלות נפוצות בפניות בנושא המאמר.
- האם VBS (אבטחה מבוססת וירטואליזציה) ו-Core isolation הם אותו דבר?
- במובן הצר, הם שונים. VBS היא טכנולוגיית היסוד שיוצרת סביבה מבודדת עם ההיפרווייזור, ו"Core isolation" ביישום האבטחה של Windows הוא שם של מסך שמקבץ כמה הגנות הבנויות על VBS. הנציגה היא "Memory integrity", שמתייחסת ל-HVCI (שלמות קוד מוגנת-היפרווייזור). אשרו את מצב הריצה של כל שירות בשאילתה ל-Win32_DeviceGuard, לא מתצוגת המסך.
- האם באמת אי אפשר לקרוא זיכרון VTL1, גם עם הרשאות מנהל או ממנהל התקן בליבה?
- אי אפשר. הגנות גישה לזיכרון לפי-VTL מנוהלות על ידי ההיפרווייזור מול מרחב הכתובות הפיזי של המחיצה, ותוכנה שרצה בתוך המחיצה לא יכולה לשנות אותן. גם קוד שרץ בליבה (טבעת 0) אינו מורשה לגשת לזיכרון VTL1 מ-VTL0.
- למה הפעלת Memory integrity (HVCI) יכולה לעצור מנהל התקן מלעבוד?
- בסביבת HVCI, דף ליבה הופך לבר-ביצוע רק אחרי שעבר אימות שלמות, וכתיבות לדפים ברי-ביצוע אינן מותרות. מנהל התקן לא חתום, או מנהל התקן בעיצוב ישן שמשכתב זיכרון בר-ביצוע, לא יכול לעמוד באילוץ הזה והטעינה שלו נחסמת. אפשר לאשר את החסימה ביומן CodeIntegrity Operational (מזהה אירוע 3087 וכדומה).
- מה Credential Guard מגן, ומה הוא לא מגן?
- הוא מגן על גיבובים של סיסמאות NTLM של אישורי מתחם, על TGT של Kerberos, ועל דברים שיישום שמר כאישורי מתחם, בסביבה מבודדת. כרטיסי שירות של Kerberos, אישורים של חשבונות מקומיים וחשבונות Microsoft, גניבת קלט על ידי keylogger, ותקיפות פיזיות הם מחוץ להיקף.
- היכן אפשר לבדוק אם VBS רץ?
- הסתכלו על השדה "Virtualization-based security" ב-msinfo32, או בצעו שאילתה למחלקה Win32_DeviceGuard במרחב השמות root/Microsoft/Windows/DeviceGuard מ-PowerShell. אם SecurityServicesRunning מכיל 1, Credential Guard רץ; אם הוא מכיל 2, Memory integrity (HVCI) רץ.