הנדסה אזרחית & הנדסה מבנית
כיצד לכתוב קוד C מאובטח כדי למנוע את ה-Buff Overflows
Table of Contents
זרימות יתר של Buffer נשאר אחד הפגיעות הביטחוניות הרציניות והמסוכנות ביותר בתכנות C.למרות שהן מכוונות היטב במשך עשרות שנים, הן ממשיכות לגרום לבעיות חמורות כגון שחיתות נתונים, מערכות התרסקות והוצאה מרחוק של קוד מאובטח C דורש הבנה עמוקה של איך buffer overflows להתרחש וגישה ממושמעת למנוע אותם.
הבנת התעלות
buffer overflow קורה כאשר תוכנית כותבת יותר נתונים לבלוק בולט של זיכרון (buffer) מאשר החיץ הוקצו להחזיק.מכיוון ש-buffers מתגוררים בערימה או זיכרון heap, מעל הגבולות שלהם מעלים את המקומות זיכרון סמוכים.שחיתות זו יכולה לשנות את המדינה, להציג התנהגות בלתי צפויה, או מנוצל על ידי תוקף להזרקת ולבצע קוד שרירותי.
ההשלכות תלויות במה שנכתב יתר על המידה.על כתיבת כתובת החזרה על הערימה יכול להפנות את ביצוע הקוד הנשלט על ידי התוקף.על נושאי כתב יכול להוביל לזיכרון שרירותי כותב.אפילו תאונות פשוטות ניתן למנף להתקפות של הכחשת השירות.
התעלות מבוססת- Stack
משתנים מקומיים, כולל buffers הכריזו בתוך פונקציות, מאוחסנים על הערימה.הערימה גם מחזיקה כתובת החזרה, נקודות מסגרת נשמר, ונתונים אחרים שליטה.כאשר חיץ ליניארי כמו FLT:0 הוא overrun, נתונים לשפוך לכתובת החזרה ומעבר. קלאסיקות ניצול כמו תולעת מוריס (1988) השתמשו מעל גדות כדי להשיג גישה בלתי מורשית.
המונחים: heap-based Overflows
יונקים מוקצה דינמי (באמצעות FLT:1), ;2 וכו ') מתגוררים על גדות הערימה. התעלות כאן יכול להשחית metadata המשמש את המפיץ, המוביל לתאונות או ניצול באמצעות ריסוס או שימוש בהתקפות ללא שימוש. heap overflows קשה יותר לנצל אך מסוכנים באותה מידה.
פונקציות Vulnerable ואלטרנטיבה בטוחה
ספריית C סטנדרטית מספקת מספר פונקציות שאינן מבצעות בדיקת גבולות.שימוש בהן הוא הגורם הנפוץ ביותר לזרימות יתר של buffer. Reמקם אותם עם עמיתים בטוחים יותר הוא תרגול בסיסי הטוב ביותר.
העתקה וקונקטנס
- (ב) ויקרא י"א): "לא בטוח: עותקים עד ל"מקדש אפס" (=ה) אין גבול אורך.פי"ד:2FLT 3:3Safe Alternative:03:03:03:4 ⁇ :4; עותקים של רוב הדמויות n; שימו לב כי אין זה אפס-טרשמיד אם מקור הוא יותר מ-n, אז תמיד ללא כל-טריום.
- טוב יותר: 5) זמין ב BSD ומערכות לינוקס רבות; תמיד אפס-טרמונים וחוזר את אורך מחרוזת המקור לאיתור.
- (ב) ויקרא י"ד): "[ה]: ⁇ [ה]: ⁇ [ה]: ⁇ [ה]: ⁇ [ה]: ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇
עיצוב בחוץ ו Input
- (ב) ויקרא י"א): "[ה]" (ב':א): "לא בטוח: כתוב תפוקה מובנת למצווה ללא בדיקת גודל.
- (ב) ויקרא י"א: "ה' (ב) ויקרא י' (בראשית כ"ד)
- (ב) ויקרא י"א: ויקרא י"ד: "ה', כ"כ ,"ה', כ"כ, כ"כ, כ"כ," (בראשית כ"ד).
- (ב) ויקרא י"ד: "לא י"ד, לא י"א, לא י"א, לא י"ד, לא י"ד, לא י"ד, לא י"ד, ו"ד).
העתק והזיז
- (ב) ויקרא י"ד): "ה' (ב') ויקרא י': "וַיְהִיר אִם נָאוּ נָאוּ נָאוּ נָא אִם עַל הָאָרֶץ אֲשֶׁר נָעָשָׂה הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא הוּא
- כמה פלטפורמות מספקות נספח K (אופציונלי ב- C11), אך אימוץ מוגבל.
ניהול וגודל
גם עם פונקציות בטוחות, עליך לאמת את אורך קלט, להבטיח גדלים חיץ מתאימים, ולטפל פוטנציאל truncation בחסד.
עקבו אחרי Inputs long
לפני העתקה או עיבוד של קלט חיצוני (מידע משתמש, נתונים ברשת, תוכן קובץ), לקבוע את אורך ההסכמה המקסימלי שלו ודחייה או נתונים ממריצים העולה על זה.
#define MAX_INPUT 255
char buffer[MAX_INPUT + 1]; // +1 for null
if (strlen(user_input) > MAX_INPUT) {
// Handle error: reject or truncate
fputs("Input too long", stderr);
return -1;
}
strncpy(buffer, user_input, sizeof(buffer) - 1);
buffer[sizeof(buffer) - 1] = '\0';
השתמש ב- Buffers עם גבולות ידועים
בכל פעם שניתן, להגדיר Buffers עם גודל קבוע ואכיפתו לאורך הקוד. להימנע מערכים באורך משתנה (VLAs) שיכולים לגרום לערימה של מעל גדות אם גדלים גדולים מסופקים.
יד שמאלית - explicitly
פונקציות כמו FLT:21 ו-FLT:22 יכול ליזום נתונים. להיות מודע לערך החזרה כדי לזהות יזום ולהחליט אם הנתונים הטרוקים מקובלים או אם יש להעלות שגיאה.
דגלי אבטחה והגנת ריצה
מעצבים מודרניים מציעים דגלים שמוסיפים גילוי יתר על פני זרימת דגנים והפחתה ללא שינויים בקוד.אפשר להם במערכת הבנייה שלך.
- (ב) ויקרא י"ד: ויקרא י"ד): "וַיְּהְיִדָּבְתָּבְתָּבְתָּבְתָּעָה אִם עַלְתָּעָם" (בראשית כ"ד, כ"ד).
- (ב) ויקרא (ב) ל"ב' (ב"ד)" (ב"ב) "[[1924]]" (ב[[1924]]) ו[[1924]], [[1924]], [[1924]]]]]], [[1924]]]]]], [[1924]]]]]]]], [[1924]]]]]]]]]], [[1924]]]]]]]]]]
- (ב) [15] , ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇
- (ב) ויקרא:30 ,9) , ויקרא (ב) ויקרא: ויקרא י"ד): "הקוד ל"התב" (ב-ב') הוא "הכתובים" (ב) ו"עדי זיכרון אחרים" בזמן ריצה.
- (ב) ,0) ,(ב) ,"התעלם" (ב) מבדיקות התעלות (שימוש בזהירות).
מערכת הפעלה הגנה
קפסולות הן רק שכבה אחת. טכנולוגיות הפחתת Exploit ב-OS המודרניים כוללות:
- (FLT:0Data Execution Prevention (DEP) / NX bitFLT 1:1 - מארקס ערימה ו- heap כ- non-executable, מניעת ביצוע קוד זדוני.
- (FLT:0)Address Space Layout Randomization (ASLR)אנדרל 1:1 - כתובות זיכרון אקראיות (סטאק, heap, ספריות משותפות) כדי להקשות על חיזוי מטרות.
- (ב) ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇
עידוד הגנות הללו (בדרך כלל ברירת מחדל) מעלה את הבר לניצול, אך אינו מחליף קידוד מאובטח.
קוד ביקורת וניתוח סטטי
בדיקה אנושית בשילוב עם ניתוח סטטי אוטומטי יכול לתפוס בעיות זרימה מוקדם.לשלב את אלה לתוך זרימת העבודה שלך.
- (FLT:0) סקירת קוד מנדלה 1:1 - חפש שימושים של פונקציות לא בטוחות, בדיקות בגודל חסר, ו הלולאות לכתוב מעבר לגבולות חיץ.
- (ב) ,0) כלי ניתוח סטטיים (הראשונה ל-[[1924]], [[1924]], [[1924]]]], [[1924]], [[1924]]]]]], [[1924]]]]]], [[1924]]]]]]]], [[1924]]]]]]]], [[1924]]]]]]]]]], [[1924]]]]]]]]]], [[1924]]]]
- (FLT:0)FuzzingofLT:1 - השתמש libFuzzer, AFL, או מטושטשים אחרים כדי לבדוק באופן אוטומטי טיפול קלט עם נתונים בלתי צפויים שעלולים לגרום לזרימות יתר.
דוגמאות מעשיות של קוד מאובטח
עותק בטוח עם Bounds
#include <stdio.h>
#include <string.h>
int safe_string_copy(char *dest, size_t dest_size, const char *src) {
if (!dest || !src || dest_size == 0) {
return -1; // Invalid parameters
}
size_t src_len = strlen(src);
if (src_len >= dest_size) {
// Source too large; truncation or error
// Option: copy what fits and null-terminate
strncpy(dest, src, dest_size - 1);
dest[dest_size - 1] = '\0';
return 1; // Truncation occurred
}
strncpy(dest, src, dest_size);
// strncpy fills remaining with null, so dest_size fits; no need to null-terminate if src shorter
return 0; // Success, no truncation
}
« « « « « טרנדים בטוחים
יתר על כן, זרימת יתר של Buffer יכולה גם לגרום התעלות integer כאשר גדלים מחשוב תמיד לבדוק סיבולת לפני הקצאה.
#include <stdlib.h>
#include <limits.h>
#include <errno.h>
void *safe_malloc_array(size_t nmemb, size_t size) {
if (nmemb == 0 || size == 0) {
return NULL; // Or handle zero-size allocation
}
if (nmemb > SIZE_MAX / size) {
// Integer overflow would occur
errno = ENOMEM;
return NULL;
}
return malloc(nmemb * size);
}
שימוש ב-Sleprintf for Formatted Strings
char log_message[256];
int ret = snprintf(log_message, sizeof(log_message),
"User %s logged in from %s", username, ip_address);
if (ret < 0) {
// Output error
} else if ((size_t)ret >= sizeof(log_message)) {
// Truncation occurred; handle if needed
}
שיטות נוספות
- (ב) ויקרא י"ד: "וַיְּהִנְתָּבְתָּבְתֶּם לְךָ מְאֶת עַמֶרְתִּים" (בראשית כ"ד, כ"ד).
- (ב) ,0) , ללא חתימה על עומק: (ב) ,(ההתדרות ⁇ יכולות להתרחש מטיול עמוק; להשתמש בהסרה או להגביל את עומק.
- (ב) ,0) ,Use (FLT:39 ), חליל 1: , עוזר את הלפיד אופטימיזציה והוא עשוי לתפוס בעיות, אם כי לא ישירות למנוע זרימות.
- (ב) ,0) ,[עריכת קוד מקור]
- (ב) לא להתעלם מערכי החזרה (ב"ג) מתפקידם של ה-[[1924]], ולא להתעלם מערכי החזרה (ב[[1924]], וכן הלאה.
משאבים ללמידה נוספת
- (ב) ,0) ,SEI CERT C Coding StandardFIRLT:1 , כללי מקיף עבור C coding מאובטח.
- (ב) 0CWE-120: עותק Buffer מבלי לבדוק את גודל האינקוויסטפל 1:1 - סיווג של MITRE של חולשות על גדות.
- (ב) ⁇ :0[דרוש מקור]: [ה], [ה], [ה], [ה], [הנחיה המעשית של פרויקט אבטחת יישומים ברשת הפתוחה.
- (ב) GNU C Library Manual: String and Array Utilities FLT:1 - מסמך לפונקציות מחרוזת בטוחות.
- (ב) ויקרא יא"ד: "בְּהָעֹל עַמֶר אֱלֹהִים" (בראשית כ"ד, כ"ד).
מסקנה
מניעת זרימות של buffer ב C אינה אופציונלית; זוהי אחריות בסיסית של כל מפתח עובד עם השפה. על ידי הבנה של מנגנונים של זרימות יתר, החלפת פונקציות מסוכנות עם חלופות בטוחות יותר, אימות קפדני קלטות וגדלים, המאפשר הגנה מדרדר, והפעלה של ניתוח סטטי ובדיקה, אתה יכול להפחית באופן דרמטי את הסיכון של פרצות אלה.