מה זה tcache poisoning, הדרך המודרנית לנצל heap¶
מאז שגרסת glibc 2.26 הציגה מנגנון בשם tcache, כמעט כל טכניקת ניצול heap מודרנית עוברת דרכו. tcache poisoning היא הטכניקה המרכזית שממחישה למה, וגם למה מבנה הנתונים הזה, שנועד לייעל ביצועים, הפך למגרש המשחקים האהוב על חוקרי חולשות.
מה זה tcache בקצרה¶
tcache (thread-local cache) הוא מבנה שנועד לייעל הקצאה ושחרור חוזרים של chunks בגדלים דומים. כש-chunk משתחרר בגודל מסוים, הוא נכנס לרשימה מקושרת קטנה שמוקדשת לגודל הזה - עד עשרה chunks לכל גודל, כברירת מחדל. בפעם הבאה שמבקשים chunk באותו גודל, האלוקטור פשוט מוציא אותו מראש הרשימה, בלי לעבור דרך כל הלוגיקה המורכבת של הבינים הרגילים. זה מהיר משמעותית, אבל המהירות הזאת מגיעה עם בדיקות אבטחה מינימליות בהרבה מהמנגנון הישן.
איך הרשימה בנויה בפועל¶
כל chunk פנוי ב-tcache מכיל, בתחילת אזור הנתונים שלו, מצביע לחתיכה הבאה ברשימה - זהו בעצם רשימה מקושרת יחידה (singly linked list) פשוטה. כשמבקשים chunk חדש, האלוקטור פשוט לוקח את זה שבראש הרשימה, ומעדכן את "ראש הרשימה" להיות מה שהמצביע הזה מצביע עליו.
הנקודה הקריטית - המצביע הזה יושב בתוך אזור הנתונים של ה-chunk עצמו, באותו מקום שבו הייתם שמים נתונים רגילים אם ה-chunk היה בשימוש. אם יש לכם חולשת כתיבה שמאפשרת לכתוב לתוך chunk אחרי ששוחרר (למשל דרך Use After Free או Double Free), אתם יכולים לשנות את המצביע הזה בעצמכם.
איך הניצול עובד בפועל¶
הרעיון המרכזי הוא לשנות את המצביע "הבא" בתוך chunk שנמצא ב-tcache, כך שבמקום להצביע ל-chunk פנוי אמיתי אחר, הוא יצביע לכל כתובת שאתם בוחרים - כתובת בתוך ה-GOT, כתובת על הסטאק, או כל מקום אחר שתרצו לכתוב אליו. ברגע שזה קורה, שתי קריאות malloc עוקבות עושות את הקסם - הראשונה מוציאה מה-tcache את ה-chunk המקורי (שהמצביע שבתוכו כבר תופעל), והשנייה מקבלת בחזרה בדיוק את הכתובת שאתם קבעתם, כאילו זה chunk זיכרון תקין וזמין.
מהרגע הזה, כל כתיבה לתוך ה-chunk ה"מזויף" שקיבלתם היא בפועל כתיבה חופשית לכתובת שבחרתם. זו בדיוק ההגדרה של כתיבה שרירותית בזיכרון - ומכאן קצרה הדרך לניצול מלא, כמו דריסת ערך ב-GOT או שינוי משתנה קריטי בתוכנית.
למה זו טכניקה כל כך "נקייה"¶
בהשוואה לטכניקות ניצול heap ישנות יותר כמו Unlink Attack, שדרשו הבנה של מבנים מורכבים ובדיקות רבות, tcache poisoning פשוט להפליא ברעיון שלה - אתם רק צריכים לכתוב ערך אחד למקום הנכון. זו הסיבה שהיא הפכה לטכניקת ברירת מחדל בהרבה מאתגרי CTF מודרניים בקטגוריית Pwn.
איך glibc התמודד עם זה¶
בגרסאות מאוחרות יותר נוספה הגנה שנקראת Safe Linking. במקום לשמור את המצביע "הבא" ישירות, glibc מצפין אותו עם XOR מול כתובת הזיכרון של ה-chunk עצמו (מוסטת ימינה). כדי לזייף מצביע תקין תחת ההגנה הזאת, תוקף חייב לדעת גם את הכתובת שבה ה-chunk יושב בזיכרון - מה שמצריך דליפת כתובת heap כתנאי מקדים, ומקשה משמעותית על ניצול ללא מידע נוסף.
איך לומדים את זה נכון¶
tcache poisoning דורש הבנה מוצקה של מבנה chunk, של סדר הקצאות ושחרורים, ותרגול בפועל תחת debugger כדי לראות את המצביעים משתנים בזמן אמת. זו טכניקה שממש "נכנסת ליד" רק אחרי שרואים אותה עובדת פעם אחת בעצמכם.
בקורס מחקר חולשות אנחנו בונים ניצול tcache poisoning שלב אחר שלב, כולל התמודדות עם Safe Linking בגרסאות מודרניות יותר.
מבולבלים לגבי איזו גרסת glibc רלוונטית לאתגר שלכם ואיך זה משפיע על הניצול? בדיסקורד שלנו יש אנשים שמתמצאים בדיוק בהבדלים האלה.
לסיכום¶
tcache poisoning ממחישה איך מנגנון שנועד לייעל ביצועים יכול להפוך ליעד תקיפה מרכזי, כשמבנה נתונים פשוט מדי נמצא בדיוק במקום שבו תוקף יכול לכתוב אליו. הבנה שלה היא כיום בסיס כמעט הכרחי לכל מי שרוצה להתקדם בעולם ניצול ה-heap המודרני.