לדלג לתוכן

מה זה SROP, כשמנגנון הסיגנלים של לינוקס הופך לכלי ניצול

יש בעולם ניצול החולשות טכניקות שמזכירות פריצה קלאסית, ויש כאלה שמרגישות כמו לגלות דלת סודית שאף אחד לא התכוון להשאיר פתוחה. SROP, קיצור של Sigreturn Oriented Programming, שייכת בבירור לקטגוריה השנייה.

רקע קצר - מה זה בכלל sigreturn

מערכת ההפעלה לינוקס תומכת ב"סיגנלים" - הודעות שהמערכת שולחת לתוכנית כדי להודיע לה על אירוע, כמו לחיצת Ctrl+C או ניסיון גישה לזיכרון לא חוקי. כשתוכנית מקבלת סיגנל, המערכת עוצרת את מה שהיא עשתה, שומרת את כל מצב הרגיסטרים שלה במבנה מיוחד על הסטאק, ומריצה פונקציית טיפול בסיגנל (signal handler). כשהטיפול מסתיים, יש להחזיר את התוכנית בדיוק למצב שבו הייתה קודם - וזה בדיוק תפקידה של קריאת המערכת sigreturn. היא לוקחת את המבנה שנשמר על הסטאק, וממנו משחזרת את כל הרגיסטרים בבת אחת, כולל מצביע ההוראות עצמו.

איך זה הופך לכלי ניצול

כאן ההברקה - קריאת המערכת sigreturn לא בודקת שבאמת קרה סיגנל אמיתי. היא פשוט לוקחת כל מה שנמצא במבנה שהיא מקבלת, ומשחזרת ממנו רגיסטרים. אם תוקף מצליח לגרום לתוכנית לבצע קריאת sigreturn בעצמו, ולשלוט על התוכן של אותו מבנה, הוא בעצם קיבל שליטה מלאה על כל רגיסטר במעבד בבת אחת - כולל rip (מצביע ההוראות), rsp (מצביע המחסנית), וכל הרגיסטרים האחרים - בפעולה אחת בלבד.

זה שונה לגמרי מ-ROP רגיל, שבו כל gadget שולט לרוב ברגיסטר אחד או שניים, ומצריך שרשרת ארוכה של gadgets כדי להגיע לשליטה מלאה. עם SROP, "gadget" אחד - קריאת sigreturn עם מבנה מוכן - מספיק כדי לקבל שליטה מוחלטת.

למה זה כל כך שימושי בניצול

היכולת לשלוט בכל הרגיסטרים בבת אחת פותחת דלת נוחה במיוחד לביצוע קריאת מערכת שרירותית - למשל execve("/bin/sh", NULL, NULL) - כי אתם יכולים לקבוע בדיוק את הערכים של כל הרגיסטרים הרלוונטיים לקריאת המערכת (בארכיטקטורת x86-64, למשל rax, rdi, rsi, rdx) בפעולה אחת, בלי לחפש gadgets נפרדים לכל אחד מהם.

זה הופך את SROP לשימושי במיוחד במצבים שבהם קשה למצוא gadgets מספיקים בבינארי - למשל בינארי קטן מאוד עם מעט מאוד קוד, שבו פשוט אין מספיק gadgets שונים כדי להרכיב שרשרת ROP רגילה.

מה נדרש כדי לבצע SROP

צריך שני דברים - קודם, יכולת לגרום לתוכנית לבצע את קריאת המערכת sigreturn (למשל דרך gadget שמבצע syscall כשהרגיסטר המתאים מכיל את המספר הנכון). שנית, שליטה על תוכן הסטאק כדי לבנות עליו את מבנה ה-sigcontext המלא, עם כל הרגיסטרים שאתם רוצים לקבוע. זה דורש הבנה מדויקת של המבנה הפנימי הזה - כל שדה חייב להיות בסדר הנכון ובגודל הנכון.

כלים כמו pwntools מספקים תמיכה מובנית ביצירת מבני SROP, כי בנייה ידנית שלהם היא עבודה טכנית מייגעת שקל לטעות בה.

מתי בפועל נתקלים בזה

SROP מופיע בעיקר באתגרי CTF ברמה מתקדמת, כשהמעצבים במכוון מגבילים את הבינארי כך שאין מספיק gadgets לשרשרת ROP רגילה, ובכך "מכריחים" את הפותרים למצוא את דרך ה-syscall. זו טכניקה מתקדמת יחסית, אבל היא מלמדת שיעור חשוב - לפעמים החולשה האמיתית לא נמצאת בקוד של התוכנית עצמה, אלא במנגנון מערכת הפעלה שהתוכנית סומכת עליו בעיוורון.

איך זה מתחבר לשאר הידע

SROP דורש בסיס מוצק ב-ROP רגיל, בהבנת syscalls, ובהבנה של מבנה הזיכרון בזמן קריאת מערכת. זו לא נקודת התחלה, אלא תחנה מתקדמת שמראה עד כמה יצירתי אפשר להיות כשמבינים לעומק את המנגנונים הפנימיים של מערכת ההפעלה.

בקורס מחקר חולשות אנחנו מגיעים ל-SROP אחרי שמיצינו ROP רגיל ו-syscalls, כדי שהמעבר יהיה טבעי ולא מבלבל.

מתמודדים עם אתגר שבו נגמרו לכם ה-gadgets? יכול להיות שזה בדיוק המקום ש-SROP נועד בשבילו, ובדיסקורד שלנו אפשר להתייעץ על זה.

הצטרפו לקהילה בדיסקורד

לסיכום

SROP מנצל את מנגנון הסיגנלים של לינוקס כדי לקבל שליטה מלאה על כל הרגיסטרים בפעולה אחת, בלי להזדקק לשרשרת ROP ארוכה. זו טכניקה מתקדמת שמראה איך הבנה עמוקה של מערכת ההפעלה עצמה יכולה לפתוח דרכי ניצול שלא היו קיימות אם מסתכלים רק על קוד התוכנית.