SEED Lab – Buffer Overflow writeup

By | פברואר 29, 2020

במאמר זה נראה איך עוברים את האתגר של BOF במכונה seedbuntu הסבר על האתגר אפשר למצוא כאן

במעבדה זו נדרשנו לבצע מתקפת Buffer Overflow על קטע קוד פגיע בשם stack.
בשלב הראשון היה עלינו לבטל את מנגנון ה- Address Space Randomization וזאת ע"י הפקודה:

ובנוסף בעת הקימפול של ההתקפה היה עלינו להשתמש בשני פרמטרים:

כעת נבחן את הקוד וננסה להבין איפה הבאג

כפי שניתן לראות, בקוד ישנה פונקציית main אשר עושה את הפעולות הבאות:

  1. יוצרת מחרוזת באורך 517 בייטים.
  2. פותחת לקריאה קובץ בשם badfile.
  3. קוראת 517 בייטים מbadfile לתוך המחרוזת שנוצרה בסעיף 1.
  4. מריצה את פונקציית bof (עליה נרחיב בהמשך).
  5. מדפיסה הודעה למשתמש שהכל בוצע כהלכה.
  6. מסיימת ומחזירה 1.

פונקציית bof שמופעלת במהלך ריצת ה-main עושה את הדברים הבאים:

  1. מקבל מחרוזת כפרמטר.
  2. יוצרת באפר בגודל 24 בייטים.
  3. מעתיקה את המחרוזת שהיא קיבלה לתוך הבאפר.
  4. מסיימת ומחזירה 1.

כאשר אנחנו נשתמש בפקודה strcpy כדי להעתיק מחרוזת ארוכה אל תוך מקום קטן בזיכרון, הפקודה לא תגביל אותנו, ותתן לנו להעתיק את כל המחרוזת הגדולה, גם אם נדרוס חלקים שלא קשורים לבאפר ונגרם ל-Segmentation Fault.

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

 

ראשית, נבין רגע איך נראה הזיכרון בעת ריצה תקינה של התוכנית stack:

נתחיל מלמטה כלפי מעלה לפי סדר הכנסת הנתונים ל-Stack.

ראשית, פונקציית main יוצרת מקום פנוי ל-517 התווים שצריכים להתמלא בתוכן של הקובץ badfile.

לאחר מכן הפונקצייה תקצה 4 בייטים (גודל משתנה), תקרא את הקובץ ואז תקרא לפונקציית bof.

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

ראשית הפונקציה תכתוב את ההצבעה לפרמטר, לאחר מכן תכתוב ה-Address Code, שזהו המקום של הפוינטר של פונקציית main, ככה שבסיום פונקציית bof הקוד ידע לאן לחזור. ולאחר מכן תעתיק את ה-EBP שישמש בתור frame pointer כדי שלפונקציה bof תהיה איזשהו בסיס שלפיו היא תדע להתמצא בזיכרון של עצמה.

כעת תקצה הפונקציה את הבאפר בגודל 24 בייטים. וכל השאר הם בגדול אותם תהליכים בעת הקריאה לפונקצייה strcpy.

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

לשם כך, נשתמש בקובץ exploit אשר מטרתו למלא את ה-badfile בקוד הזדוני שיגרום להרצת ה-Shellcode שלנו, ופתיחת root shell אשר נחדיר לתוך הבאפר ונביא לריצתו.

כיצד נעשה זאת?

קודם כל קוד, ואז הסברים.

 

 

Shellcode  – יכיל את הקוד שאנחנו רוצים שירוץ 

כעת ניצור באפר בגודל 517 בייטים ונרוקן אותו. בבאפר הזה נכניס את הערכים שיכנסו בסופו של דבר לקובץ badfile.

כעת נמלא בסתם תווים את כל החלקים שלפני ה-Return Address.

איך אנחנו יודעים איפה בדיוק ה-Return Address? בגדול, ניסוי וטעיה.

כאשר נדרוס את ה-Return Address ונפעיל GDB נוכל לראות מה הערך במקום שבו הוא היה אמור להיות, ולפי זה, ומשחק עם תווים שונים נוכל לגלות בסופו של דבר את המיקום המדויק.

עכשיו, כאשר הגענו ל-Return Address, איזה מקום בזיכרון נשים? נגיע לזה בהמשך.

כעת, לאחר שעברו את ה-Return Address, נשתמש בכל שאר המקומות שניתנו לנו כדי לשים תו שנקרא NOP, או No Operation.

תו זה לא יעשה כלום ופשוט יריץ קדימה בסדר הפקודות, ככה שלא משנה איפה ה-Return Address "ינחת", כל עוד הוא יהיה בתוך ה-NOP’s, הקוד ירוץ ויגיע ל-Shellcode שלנו, אותו נכניס מיד אחריו, בצורה כזאת שבה ננצל את מלוא התווים שניתנו לנו (517). אם נמלא יותר מכך, נקבל Segmentation Fault בעצמנו.

לכן, ב-Return Address, נכניס כתובת בזיכרון שהיא היכנשהו בהתחלה של ה-NOP’s, אבל לא ממש בהתחלה, כי שינויים של מערכות הפעלה יגרמו למצב שאולי ננחת במקום אחר.

ככה יראה הזיכרון לאחר הרצת stack, שרץ לאחר שהרצנו את הקוד exploit:

בהרצה ללא Address Space Randomization נצליח מיד על הפעם הראשונה:

בהרצה עם Address Space Randomization כמובן שיש סיכוי נמוך שנצליח "לנחש" את המיקום בזיכרון של ה-Shellcode, אך זכרו שיש לנו כמות גדולה של כמה מאות NOP’s שבהחלט הופכים את המשימה ליותר קלה. לכן ביטלנו את ה-Randomization והרצנו את stack בלופ.

ולבסוף

כעת, נסיר שוב את הגנת ה-Address Randomization, כדי שנוכל הפעיל הגנות אחרות.

נקמפל מחדש את הקוד הפגיע עם Stack Guard:

gcc -o stack -z execstack stack.c

הרצנו וראינו שההגנה לא משפיעה ועדין קיבלנו Shell.

במידה ונריץ עם noexecstack לא נקבל Shell, אלא הודעה גנרית של Segmentation Fault.

הגנה זו לא מאפשרת את הרצת הShellcode, אך אינה מונעת את ה-Buffer Overflow.

 

דירוג

Comments

comments

כתיבת תגובה

האימייל לא יוצג באתר. שדות החובה מסומנים *