בפוסט האחרון בבלוג Project Zero, הצוות גילה דרך לעקוף את הגנת הליבה בזמן אמת של סמסונג, הנקראת Knox Hypervisor.
צוות Project Zero של גוגל אימת מספר ניצולים המאפשרים לתקוף את הטלפונים של סמסונג המריצים את חבילת האבטחה המאובטחת לכאורה של Samsung Knox. הבלוג מציין שכל נקודות התורפה הועברו לסמסונג שלמעשה פרסמה תיקונים עבורן בעדכון תוכנה בינואר.
רקע כללי
כחלק מחבילת תוכנות האבטחה של סמסונג נוקס שהציגה סמסונג, ישנה תוכנה שיושבת בין אפליקציות אנדרואיד לקרנל הנקראת היפרוויזר. זה יכול לשמש כשכבה נוספת לאבטחת מכשירי אנדרואיד. ה-Samsung Knox Hypervisor נקרא "הגנת ליבה בזמן אמת" או בקיצור RKP, כפי שאתייחס אליו בהמשך המאמר הזה.
ה-Kernel יושב מתחת ל-RKP בערימת תוכנות האנדרואיד, והאפליקציות שפועלות במכשיר יושבות בחלק העליון. הרעיון מאחורי RKP הוא לספק שכבת אבטחה נוספת למכשיר, כאשר כל הבקשות (זיכרון ומשאבים אחרים) מבוצעות על ידי יישומים ל-Kernel צריכים לעבור תחילה דרך Knox, שמנסה לזהות אם אפליקציה עושה משהו לא צריך. RKP מספקת גם אבטחה באמצעות ערפול עם שכבה נוספת להסתרת מידע רגיש שיישום יכול להשתמש בו כדי לסכן את המכשיר.
הפוסט בבלוג עוסק די עמוק באיך זיכרון אנדרואיד, ה-RKP ומערכות ההפעלה בכלל פועלות, אז ריכזתי ופישטתי אותו כדי לתת סקירה מהירה של מה שהתגלה. אני ממליץ לך לקרוא את המאמר המלא אם יש לך זמן, עם זאת, מכיוון שהוא מאוד מאיר עיניים.
ניצול מס' 1:
KASLR או פריסת מרחב כתובת ליבה אקראית היא תהליך של שינוי המיקום של קוד הליבה בזיכרון בכמות אקראית בעת האתחול. בכל פעם שהמכשיר מופעל, הקרנל נטען למרחב כתובות אחר (אזור בזיכרון). הרעיון הוא להקשות על מציאת קוד הליבה כדי לתקוף אותו כי לאחר כל אתחול קוד הליבה "מזז" בכמות אקראית בזיכרון. זה נשמע כמו צעד מצוין למניעת תוקפים פוטנציאליים אבל לאחרונה מחקר הראה שאתה באמת יכול להביס את זה מבלי לדרוש באג תוכנה או פגיעות, מכיוון שלמעשה קשה מאוד ליישם את KASLR בצורה חזקה נגד תוקפים מקומיים.
במקרה של תוכנת RKP, היכולת לעקוף את KASLR היא למעשה פשוטה יותר מהמחקר שהוזכר לעיל. כל זיכרון מכשירי האנדרואיד מופנה באמצעות מצביעים וכדי להגן על המכשירים מפני התקפה, בכל פעם שמכשירי אנדרואיד מדפיסים או יוצאים (אם למסך או לתייק עבור יומנים או ניפוי באגים), הפניות המצביעים הן אנונימיות, - מה שהופך את זה לבלתי אפשרי לגלות לאן המצביע מצביע בפועל בעת קריאת תְפוּקָה.
חשבו על מצביעי זיכרון כמו שלט רחוב המצביע על מיקום וחשבו על אנונימיות כעל טשטוש. בדומה לטלוויזיה, אנונימיזציה מתבצעת לאחר הצילומים, אנדרואיד מחיל גם אנונימיזציה זו בזמן הפלט ורק אם אנונימיזציה מוגדרת כהלכה, והמחבר מציין שלכל מכשיר [שהוא] נתקל בו הוגדרה כהלכה את האנונימיזציה של המצביע. זה אולי נשמע כאילו קשה מאוד לשבור אותו, אבל כל מה שאתה צריך לעשות הוא למצוא מצביע בודד (תחשוב על שלט רחוב) שלא היה אנונימי (מטושטש) על ידי מפתח הליבה (היזהר שזה לא מפתח אפליקציית אנדרואיד הממוצע שלך) כאשר המצביע נכתב ללוגים או למיקום אחר, למשל. מסך או א קוֹבֶץ.
אז אם אתה יכול למצוא מצביע שלא היה אנונימי, אז אתה יכול לחשב את שינוי הכתובת האקראי של הקרנל כהבדל בין השניים. מעניין שהכותב לא מצא מצביע בר ניצול בליבה אבל כן מצא אותו בתוך ה-RPK שבו מפתחים שכחו להפוך מצביע לאנונימי בפלט באגים (רישום), שנוצר בדרך של טעות דפוס. כדי להפוך את המצביעים לאנונימיים באנדרואיד צריך להשתמש בקוד מיוחד ומסתבר שמפתחי RPK השתמשו בטעות ב- אותיות קטנות 'K' במקום an אותיות גדולות 'K'. לכן היה פשוט יחסית להבין את כמות ההזזה האקראית של קוד הליבה ולתקוף אותו.
ניצול מס' 2:
הניצול הבא הוא קצת יותר מורכב: סמסונג נוקס מגינה על המכשיר שלך על ידי החלת מערכת כללים על זיכרון המכשיר כדי לעצור קוד זדוני. הכללים הם כדלקמן:
- כל הדפים (קוד בזיכרון), למעט הקוד של הליבה, מסומנים כ-"Privileged Execute Never" (כלומר, קוד כאן לא יכול לפעול לעולם)
- דפי נתוני ליבה (נתונים המשמשים את התוכנית בזיכרון) לעולם אינם מסומנים כניתנים להפעלה (לכן הקוד כאן לעולם לא יוכל לפעול)
- דפי קוד ליבה (קוד בזיכרון) לעולם אינם מסומנים כניתנים לכתיבה (לכן שום קוד זדוני לא יכול לשנות אותו)
- כל דפי הליבה מסומנים כקריאה בלבד בטבלת תרגום שלב 2 (הטבלה שנמצאת בין האפליקציה לקרנל כדי למנוע עוד יותר מיישומים שידעו על מיקומי זיכרון אמיתיים)
- כל ערכי תרגום הזיכרון מסומנים כקריאה בלבד עבור יישומים.
נתמקד בכלל 3 מכיוון שכאן מצא המחבר בעיה ביישום הכללים לעיל. RPK אכן מסמן את הזיכרון של הליבה כקריאה בלבד, אולם כפיקוח על ה-KASL התגלה חור, שהוביל ל כתיבת קוד לקטע כביכול "לקריאה בלבד".. על מנת לטשטש את מיקום הליבה בזמן האתחול מוקצה זיכרון לקרנל, אך כמות הזיכרון הזו גדולה בהרבה מקטע הטקסט של הליבה. על ידי הקצאת כמות גדולה יותר של זיכרון זה מקשה הרבה יותר למצוא את קוד הליבה בפועל שיכול להיות בכל מקום, וכפי שראינו למעלה הוא מועבר באופן אקראי בכל אתחול של המכשיר.
המחבר הצליח לאשר שהזיכרון ששימש את הליבה אכן סומן כ"קריאה בלבד", אולם שאר כמות הזיכרון הגדולה הזו ששימשה להסתרת הליבה הייתה לֹא מסומן כ"קריאה בלבד". הסיבה לכך היא ש-RKP מגן רק על האזור המכיל את הטקסט של הליבה לאחר החלת השקופית KASLR.
ניצול מס' 3
בניצול השלישי המחבר הצליח לגשת לאזור אחר של זיכרון שאמור להיות מוגבל גם לקריאה בלבד. ה-RKP מגן על הזיכרון ומשתמש ב-a רישום תצורת Hypervisor (HCR) כדי לשלוט בפעולות הליבה המרכזיות. המטרה של ה-HCR היא לאפשר לפעולות ליבה תקפות ואמיתיות לגשת לרגיסטרים ולחסום התקפות זדוניות. זה עושה זאת על ידי בדיקת השיחות שבוצעו לרגיסטרים השולטים בתכונות הוירטואליזציה. ה-HCR מוגדר לחסום פעולות ספציפיות שיטופלו בדרך כלל, מה שמאפשר ל-RKP לבחור אם לאפשר או לא לאפשר בקשה.
בניצול זה שליטת HCR הייתה לא מכסה שני אוגרים זה התברר כחשוב מאוד. המחבר חפר עמוק במדריך ARM Reference וגילה שהרישום הראשון אפשר לו בעצם לכבות את RKP עבור יישומים. ה "System Control Register עבור EL1 (SCTLR_EL1) מספק שליטה ברמה העליונה על המערכת, כולל מערכת הזיכרון." בעולם מושלם האפליקציה תשתמש בזיכרון שמופה דרך ה-RKP כך שה-RKP יוכל לשלוט למה האפליקציה יכולה לגשת. עם זאת, כיבוי הרשום הזה אפשר את RKP להיות מושבת על ידי החזרת המכשיר למעשה לאופן שבו הוא פעל לפני התקנת RKP - כלומר, המכשיר ממופה לזיכרון פיזי ללא האבטחה הנוספת שסיפקה RKP. זה בתורו אומר שהמחבר יכול לקרוא ולכתוב לזיכרון שנחסם במקור ונכון על ידי תוכנת RKP.
למאגר השני שהוחמצה הייתה השפעה עדינה יותר, אך בסופו של דבר הרסנית לא פחות לביטחון. ה רשם בקרת תרגום עבור EL1 רישום (TCR_EL1) מתייחס ישירות לכמות הזיכרון שאיתו יישום עובד הנקרא עמוד. RKP מקודד לגודל עמוד של 4KB מכיוון שגרעיני לינוקס של AARCH64 (כגון אנדרואיד) משתמשים בגודל תרגום של 4KB. האוגר המדובר (TCR_EL1) מגדיר את ערכות השבבים של ARM לגודל הזיכרון שיש להחזיר. מסתבר ש פנקס זה אינו מוגן על ידי ה-HCR ולכן תוקף יכול לשנות אותו כפי שהמחבר שינה אותו לגודל עמוד של 64kb.
המשמעות היא שכאשר הבקשה מתמלאת על ידי RKP, כמות הזיכרון האמיתית הנגישה כעת היא 64kb במקום 4kb. הסיבה היא שערכת השבבים ARM עדיין שולטת בגודל העמוד והיא הוגדרה ל-64kb על ידי הניצול. מכיוון שה-RKP מגן על הזיכרון מפני כתיבה, כחלק מהכללים המפורטים ב-exploit #2, הזיכרון עדיין מוגן בפועל. אבל הנה הקאץ' - מכיוון ש-RKP מקודד קשה ל-4kb הוא לא משתנה לגודל עמוד של 64kb כאשר הרגיסטר עודכן, אז רק 4KB הראשונים של הזיכרון מוגנים המאפשר לתוקף לעשות מה שהוא רוצה עם ה-60Kb הנותרים.
ניצול מס' 4
הניצול האחרון שהמחבר מראה הוא הפניה לזיכרון היכן שנמצאת תוכנת RKP, כך שהתוקף יוכל לתקוף את תוכנת RKP עצמה. טריק אחד לעצור את סוג ההתקפה הזה שגם ליבות לינוקס משתמשות בו הוא לבטל את מיפוי התוכנית שלך ממרחב הכתובות של הזיכרון הווירטואלי כך שאף יישומים לא יוכלו לתקוף אותה כי הם לא יכולים להתייחס אליה.
זכור שזיכרון עוסק כולו במצביעים וטבלאות הממפות זיכרון פיזי לזיכרון וירטואלי. בהתאם להגנה הרגילה בסוג זה של התקפה, RKP מבטל את מיפוי עצמו כך שלא ניתן לתקוף אותו. עם זאת, כאשר הליבה אינה מספקת יכולות כאלה, RKP כן מאפשר למפות פיסת זיכרון ולסמן כקריאה/כתיבה. הבדיקה היחידה היא שזה לא הקרנל הבסיסי עצמו שכן RKP לא מבצע בדיקות כדי לראות אם הכתובות שמתבקשות למפות הן האזור שבו RKP עצמו שוכן בזיכרון. בעיקרון, RKP מרשה לעצמה למפות מחדש חזרה למרחב הכתובות שאליו יישומים יכולים לגשת וכצד להשפיע על הזיכרון מסומן אוטומטית כקריאה/כתיבה כך שתוקף יכול כעת להשתמש בזיכרון איך שהוא רוצה.
סיכום
אחת הבעיות הגדולות ביותר עם ארבעת המנצלים המפורטים לעיל היא שהמחבר מזכיר כמה קשה יהיה לבצע אותם בגלל היעדר פונקציות בליבת האנדרואיד הבסיסית. למרבה האירוניה, ה-RKP Hypervisor המאובטח סיפק את כל הכלים הנדרשים לביצוע ההתקפות. זה מראה שלפעמים תוכנה עם כוונות טובות גורמת ליותר בעיות ממה שהיא פותרת ויש לנו מזל שיש לנו אנשים כמו גל בנימיני שמוכן ללכלך את הידיים ולבדוק שהתיעוד תואם את התוכנה בפועל עושה.
למרות שהמעללים האלה נראים מפחידים וגורמים לנוקס להישמע פגיע מאוד, אני רוצה להרגיע את כולם שהבעיות האלה היו כולן תוקן בעדכון ינואר מבית סמסונג. יתר על כן, ניצולים אלו דורשים הבנה עמוקה מאוד של מעבדי ARM ותכנות, כך שחסם הכניסה בשימוש בניצולים אלו הוא גבוה מבחינה אסטרונומית.
מקור: Project Zero