7.6 מבוא לניצול חולשות תרגול
תרגיל 1 - ניתוח תוכנית פגיעה¶
הנה קוד C עם חולשת אבטחה:
#include <stdio.h>
#include <string.h>
void secret() {
printf("You found the secret function!\n");
}
void greet() {
char name[32];
printf("What is your name? ");
gets(name);
printf("Hello, %s!\n", name);
}
int main() {
greet();
return 0;
}
- מהי החולשה בקוד? הסבירו בדיוק למה היא מסוכנת.
- ציירו את מבנה המחסנית של הפונקציה
greet- איפהname, איפה saved rbp, ואיפה כתובת החזרה? - כמה בתים צריך להקליד כדי להגיע לכתובת החזרה? (הניחו מערכת 64 ביט, כלומר saved rbp הוא 8 בתים)
- אם כתובת הפונקציה
secretהיא0x401156, הסבירו תיאורטית איך תוקף יכול לגרום לביצוע שלsecret.
תרגיל 2 - חישוב offset לכתובת חזרה¶
נתון הקוד הבא:
#include <stdio.h>
void vulnerable() {
int x = 42;
char buffer[128];
int y = 17;
printf("Enter input: ");
gets(buffer);
printf("x = %d, y = %d\n", x, y);
}
int main() {
vulnerable();
printf("Done!\n");
return 0;
}
- ציירו את מבנה המחסנית של
vulnerable(שימו לב: הקומפיילר עשוי לסדר את המשתנים בסדר שונה ממה שכתוב בקוד. הניחו שהסדר הוא: buffer בתחתית, אחריו y, אחריו x, אחריו saved rbp, אחריו כתובת חזרה). - מה ה-offset מתחילת buffer עד כתובת החזרה? (הניחו: buffer=128, y=4, x=4, padding=8 לiuשור, saved rbp=8)
- אם נקליד 130 תווים 'A' - אילו ערכים יידרסו?
- מה הערך של
yו-xיהיה אחרי שנקליד 140 תווים 'A'?
הערה: בפועל, הקומפיילר יכול לסדר את המשתנים ולהוסיף padding בצורה שונה. בתרגיל הזה הניחו את הסדר שנתון למעלה.
תרגיל 3 - שימוש ב-checksec¶
קמפלו את התוכנית הבאה בכמה אופנים שונים ובדקו את ההגנות עם checksec:
#include <stdio.h>
#include <string.h>
int main() {
char buf[64];
printf("Input: ");
fgets(buf, sizeof(buf), stdin);
printf("You said: %s\n", buf);
return 0;
}
התקינו checksec:
קמפלו בארבע דרכים שונות:
# גרסה 1: בלי שום הגנה
gcc -fno-stack-protector -z execstack -no-pie -o version1 program.c
# גרסה 2: רק canary
gcc -fstack-protector-strong -z execstack -no-pie -o version2 program.c
# גרסה 3: canary + NX
gcc -fstack-protector-strong -z noexecstack -no-pie -o version3 program.c
# גרסה 4: כל ההגנות
gcc -fstack-protector-strong -z noexecstack -pie -o version4 program.c
הריצו checksec על כל גרסה:
- מה ההבדלים בפלט של checksec בין הגרסאות?
- איזו גרסה הכי פגיעה? למה?
- איזו גרסה הכי מוגנת? למה?
- האם יש הגנות שלא שלטנו בהן דרך דגלי הקומפיילר אבל checksec עדיין מראה?
תרגיל 4 - מדוע gets() מסוכנת¶
הסבירו בפירוט למה הפונקציה gets() מסוכנת. בתשובה שלכם:
- ציירו דיאגרמה של המחסנית שמראה מה קורה כשקוראים ל-gets עם קלט ארוך מדי
- הסבירו למה fgets היא חלופה בטוחה:
- הראו עוד 3 פונקציות "מסוכנות" שלא בודקות גבולות, ואת החלופה הבטוחה שלהן
- הסבירו מה ההבדל בין:
תרגיל 5 - קנרי על המחסנית¶
נתון הקוד הבא:
#include <stdio.h>
#include <string.h>
void copy_input() {
char buffer[16];
printf("Enter text: ");
gets(buffer);
printf("You entered: %s\n", buffer);
}
int main() {
copy_input();
return 0;
}
-
קמפלו עם stack protector:
-
הריצו עם קלט קצר (למשל "hello") - מה קורה?
-
הריצו עם קלט ארוך שיגלוש (למשל 50 תווים 'A'):
-
מה הודעת השגיאה שמופיעה? הסבירו מה קרה.
-
ציירו דיאגרמה של המחסנית שמראה את מיקום הקנרי ביחס ל-buffer ולכתובת החזרה.
-
הסבירו: למה הקנרי מתחיל בבית null (
\x00)? באיזה מצב ספציפי זה עוזר?