גלישת חוצץ

מתוך ויקיפדיה, האנציקלופדיה החופשית
קפיצה אל: ניווט, חיפוש

במחשבים, גלישת חוצץאנגלית: Buffer overflow) היא שגיאת תכנות, שמתבטאת בכך שתוכנית מחשב כותבת לאזור בזיכרון המחשבחוצץ) יותר מידע מאשר אותו אזור מסוגל להכיל. כתוצאה מכך "גולש" חלק מהמידע אל מחוץ לגבולות החוצץ, ומשנה נתונים שלא היו אמורים להשתנות. המידע שנמחק הוא לעתים קרובות הכרחי להמשך ריצתה התקינה של התוכנית, ובשל כך גלישת חוצץ עלולה לגרום לתוכנית להחזיר תוצאות לא נכונות, לקרוס לחלוטין, או אף לאפשר הרצה של "קוד זדוני" הגורם לתוכנית לפעול באופן שלא תוכנן מראש. בשל כך, גלישות חוצץ מהוות בסיס לפרצות אבטחה רבות. ברוב המקרים, גלישת חוצץ תגרום לפחות לקריסה של התוכנית המשתמשת בחוצץ.

תוכן עניינים

[עריכה] תיאור

חוצצים משמשים לאחסון מידע - בפרט, את המשתנים בהם משתמשת התוכנית. מכיוון שגודלו של החוצץ חסום ומוגדר מראש, כתיבה של מידע רב יותר מאשר הוא מסוגל להכיל תגרום לגלישה.

הדוגמה הנפוצה ביותר לגלישת חוצצים מתרחשת כאשר תוכנית מבצעת כתיבה של קלט לתוך חוצץ בלי לוודא שגודל הקלט קטן מגודל החוצץ. לדוגמה, אחת מפונקציות הספרייה הסטנדרטית של C (הפונקציה gets) מבצעת כתיבה לתוך חוצץ של קלט שגודלו אינו מוגבל - כלומר, כל שימוש בה עשוי לגרום לגלישת חוצץ, בהתאם לקלט שמועבר אליה.

[עריכה] הסכנות שבגלישת חוצץ

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

לעתים קרובות מאוחסן המידע הדרוש להבטחת ריצתה התקינה של תוכנית בסמוך לחוצצים בה היא משתמשת. גלישת חוצץ עשויה לגרום למחיקת מידע זה והחלפתו במידע אחר. פרט לפגיעה בריצתה התקינה של התוכנית, הדבר עלול לסייע לוירוס מחשב "להשתלט" על ריצת התוכנית ולהריץ קטעי קוד זדוניים וזאת על ידי כתיבה על אזור בזיכרון שמכיל קוד תוכנה שמתבצע. גלישת חוצץ הגורמת לקריסה של התוכנית, ללא הרצת קוד זדוני, מכונה "מניעת שירות" (Denial of Service).

במידה והחוצץ נמצא במחסנית קריאות, הזיכרון שמוקצה לחוצץ נמצא בסמיכות לתא הזיכרון שמכיל את כתובת הזיכרון שאליה יש לחזור לאחר סיום הפונקציה, לצורך המשכה התקין של התוכנית. אם ידוע כי בתוכנית קיים כשל של גלישת חוצץ, ניתן לעתים לגרום לכך שתוכנו של תא זיכרון זה ישתנה, והוא יצביע על כתובתו של קטע קוד זדוני. סוג זה של גלישת חוצץ נקרא גם גלישת מחסנית (Stack overflow).

כאשר החוצץ נמצא בערימה, הוא לרוב אינו נמצא בסמיכות לכתובות חזרה כל שהן, ולכן באופן כללי ניתן לומר כי קשה יותר לנצל גלישת חוצץ בערימה לטובת הרצת קוד זדוני מאשר במחסנית. סוג זה של גלישת חוצץ נקרא גלישת ערימה (Heap overflow).

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

[עריכה] מניעת גלישות חוצץ

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

במהדרים מתקדמים ובמערכות הפעלה מתקדמות קיימת הגנה מובנית מפני ניצול של גלישת חוצץ להרצת קוד זדוני (אם כי לרוב לא ממניעת שירות). דוגמה אחת להגנה כזו היא שתילה של מספר אקראי בין המשתנים של פונקציה מסוימת לערך החזרה שלה. מערכת ההפעלה יכולה לבדוק את הערך לפני תחילת ריצת הפונקציה ולפני החזרה שלה. מכיוון שערך זה משתנה בכל ריצה של התוכנית, אין דרך לחזות אותו מראש, אם כתובת החזרה של הפונקציה תידרס, הערך האקראי יידרס גם כן, ומערכת ההפעלה תוכל להתריע על גלישת חוצץ. שיטה זו נקראת קנרית המחסנית (Stack Canary).

למרות שקיימות שיטות רבות למניעה של ניצול גלישת חוצצים להרצת קוד זדוני, לא קיימת כיום הגנה מוחלטת מניצול כזה.

[עריכה] דוגמה בשפת C לתוכנית המבצעת גלישת חוצץ

#include <string.h>
 
int main() {
        struct {
                char str[12];
                int num;
        } data;
 
        strcpy(data.str, "Short str"); // Copying 9 Characters + Null byte = 10 bytes; OK
        data.num = 0;
 
        strcpy(data.str,"Buffer overflow"); // Copying 15 Characters + Null byte = 16 bytes; Not OK
        // Will overrun data.num, and possibly more, depending on the OS
 
        return 0;
}

בקוד זה, מוגדר מבנה נתונים המכיל מחרוזת תווים באורך 12 בתים (כולל תו אפס) ואחריה מספר שלם[1]. הקוד ראשית מעתיק מחרוזת בת 9 תווים (10 בתים, כולל תו NULL) למחרוזת של המבנה, ולאחר מכן מחרוזת ארוכה יותר, בת 15 תווים (16 בתים). ההעתקה הראשונה אינה גורמת לבעיה, שכן גודל המערך מספיק להכלת המחרוזת, אולם המחרוזת השנייה גדולה מאורך המערך (החוצץ) ולכן תגלוש ותדרוס את המספר, שנמצא מיד אחרי המחרוזת בזיכרון.

במקרה זה, הגלישה מזיקה לתוכנית באופן פנימי (כלומר הערך של data.num נפגע, וייתכן שיגרור שגיאות בהמשך, אך שאר המחסנית נשארת תקינה) רק כאשר המערכת מגדירה int בגודל 32 סיביות או יותר; אם גודלו קטן יותר התוכנה דורסת מידע נוסף בזיכרון.

[עריכה] ראו גם

[עריכה] הערות שוליים

  1. ^ גודל המספר ויישורו תלוי במימוש המהדר ובמערכת ההפעלה. ייתכן שהקוד לא תקף בסביבות מסוימות.