מציאת offset עם cyclic, ולמה לא צריך לנחש יותר¶
אחת השאלות הראשונות שמתעוררות כשמתרגלים גלישת חוצץ היא - כמה בייטים בדיוק צריך לשלוח כדי להגיע לכתובת ההחזרה? התשובה הנאיבית היא לנחש - לשלוח 40 בייטים, לבדוק אם התוכנית קרסה, לנסות 44, וכן הלאה. זו דרך עובדת, אבל היא איטית ומייגעת. כלי cyclic פותר את הבעיה הזאת באלגנטיות.
הבעיה עם ניחוש ידני¶
כשיש לכם חולשת גלישת חוצץ, אתם צריכים לדעת בדיוק כמה בייטים לשלוח לפני שאתם מגיעים למקום שבו כתובת ההחזרה נמצאת, כדי לדעת מאיפה להתחיל לכתוב את הכתובת החדשה שאתם רוצים. אם תשלחו יותר מדי או פחות מדי בייטים "מילוי", תדרסו את המקום הלא נכון, וזה יגרום לקריסה שלא תבינו למה בדיוק קרתה.
הדרך הידנית - לשלוח כמות בייטים הולכת וגדלה עד שרואים קריסה - עובדת, אבל דורשת הרבה ניסיונות, במיוחד כשהחוצץ גדול.
הרעיון מאחורי cyclic¶
cyclic, כלי שמגיע כחלק מ-pwntools (ומקורו בפרויקט Metasploit), פותר את הבעיה בצורה חכמה. במקום לשלוח "AAAA...AAAA" חוזר ונשנה, הוא מייצר מחרוזת ייחודית - רצף של תווים כך שכל ארבעה (או שמונה, בהתאם לגודל הכתובת) בייטים רצופים במחרוזת הזאת הם ייחודיים ולא חוזרים על עצמם בשום מקום אחר במחרוזת. משהו כמו aaaabaaacaaadaaa... וכן הלאה בדפוס שיטתי.
כשמזינים את המחרוזת הזאת לתוכנית הפגיעה, וגורמים לה לקרוס, ערך כתובת ההחזרה (או כל רגיסטר אחר שנדרס) יכיל בדיוק את ארבעת (או שמונת) התווים הייחודיים האלה מהמחרוזת. מכיוון שכל רצף כזה מופיע פעם אחת בלבד לאורך כל המחרוזת, יש דרך חד-משמעית לדעת בדיוק באיזה מיקום במחרוזת המקורית הוא הופיע - וממילא, בדיוק כמה בייטים עברו מתחילת הקלט ועד לכתובת ההחזרה.
איך זה נראה בפועל¶
התהליך המעשי פשוט מאוד. קודם מייצרים מחרוזת cyclic (למשל cyclic(200) ב-pwntools, שמייצרת מחרוזת באורך 200 תווים). שולחים אותה כקלט לתוכנית הפגיעה, וגורמים לקריסה. אז בודקים תחת debugger מה הערך שנמצא כרגע ברגיסטר rip (או eip, בהתאם לארכיטקטורה) - זהו הערך שדרס את כתובת ההחזרה. לוקחים את הערך הזה, ומזינים אותו לפונקציית cyclic_find, שמחזירה מיד את ה-offset המדויק - כמות הבייטים המדויקת שצריך לכתוב לפני שמתחילים לכתוב את הכתובת הרצויה.
כל התהליך הזה, שיכול לקחת עשרות ניסיונות בשיטת הניחוש הידנית, מצטמצם לשתי פקודות ובדיקה אחת בdebugger.
למה זה חשוב יותר ממה שנראה במבט ראשון¶
מציאת offset מדויק היא לא רק שלב טכני משעמם בדרך לניצול - היא הבסיס שעליו נשען כל שלב הבא. אם ה-offset שגוי, שום דבר אחרי זה לא יעבוד, לא משנה כמה שרשרת ROP מתוחכמת הרכבתם. הבנה של איך cyclic עובד, ולא רק שימוש עיוור בפקודה, גם עוזרת לדבג מצבים שבהם התוצאה לא ברורה מיד - למשל כשיש כמה כתובות שנדרסות בו זמנית.
מתי הטכניקה הזאת פחות מספיקה¶
יש מצבים שבהם offset פשוט לא מספיק - למשל כשיש בדיקות נוספות על הקלט (כמו סינון תווים מסוימים), או כשגלישת החוצץ לא ליניארית פשוטה. במקרים כאלה, cyclic עדיין נקודת התחלה טובה, אבל צריך שילוב עם ניתוח ידני נוסף של הקוד.
איך לומדים את זה נכון¶
בקורס מחקר חולשות אנחנו מלמדים את cyclic כחלק מהתשתית הבסיסית של תרגול גלישת חוצץ, כדי שתוכלו להתמקד בהבנת הניצול עצמו, ולא לבזבז זמן על ניחושים.
נתקעתם על offset שפשוט לא מסתדר, גם אחרי שהשתמשתם ב-cyclic? יש כמה מוקשים נפוצים שכדאי להכיר, ובדיסקורד שלנו אפשר לבדוק את זה יחד.
לסיכום¶
cyclic הופך שלב שהיה פעם ניחוש מייגע לתהליך מדויק ומהיר - מייצרים מחרוזת ייחודית, גורמים לקריסה, ומחשבים את ה-offset המדויק מהערך שנדרס. זה כלי קטן שחוסך שעות של תסכול, ושכל חוקר גלישת חוצץ צריך להכיר מההתחלה.