سرریز بافر

از ویکی‌پدیا، دانشنامهٔ آزاد

در امنیت کامپیوتر و برنامه نویسی، سرریز بافر، یا تاخت و تاز کردن بافر، یک استثنا است که در آن برنامه، هنگامی که در حال نوشتن داده‌ها به بافر است، از مرز بافر تخطی می‌کند و باعث رونویسی حافظه مجاور می‌شود. این یک مورد خاص از نقض ایمنی حافظه‌است.

سرریزهای بافر توسط ورودی طراحی شده‌اند که برای اجرای کد، یا راه عمل برنامه را تغییر می‌دهند، باعث شده‌است. این امر ممکن است در رفتار نامنظم، از جمله خطاهای دسترسی به حافظه، نتایج نادرست، تصادف، یا نقض امنیت سیستم منجر شود. بنابراین، آن‌ها اساس بسیاری از آسیب‌پذیری‌های نرم‌افزار است و می‌تواند مخرب مورد سوء استفاده قرار بگیرند.

زبان‌های برنامه نویسی که معمولاً با سرریزهای بافر همراه هستند، عبارتند از C و C + +‎، ساخته شده‌است، در حفاظت در برابر دسترسی یا جای نوشتن داده‌ها در هر بخشی از حافظه و انجام به‌طور خودکار نیست بررسی کنید که داده‌ها به آرایه (ساخته شده در نوع بافر) داخل مرزهای آن آرایه نوشته شده‌است.

سرریز بافر هنگامی رخ می‌دهد که داده‌ها نوشته شده به یک بافر، با توجه به مرزهای کافی بررسی، فساد مقادیر داده در حافظه آدرس مجاور به بافر اختصاص داده‌است. شایع‌ترین این زمانی اتفاق می‌افتد که کپی کردن رشته از کاراکترها از یک بافر به دیگری است.

تشریح[ویرایش]

امروزه بیشتر سیستم‌عامل‌های مدرن از یک پشته برای ارسال آرگومان‌ها به توابع و همچنین ذخیره کردن متغیرهای محلی استفاده می‌کنند. یک پشته، حافظه‌ای به صورت LIFO است که ورود و خروج اطلاعات از یک طرف انجام می‌گیرد. بنابراین آخرین شیئی که وارد پشته شده، اولین شیئی است که از آن خارج می‌شود. هر فرایند برای خود پشته‌ای دارد که آرگومان‌های توابع و متغیرهای محلی در آن ذخیره می‌شوند و این پشته در بالاترین آدرس تصویر فرایند در حافظه قرار دارد. وقتی که یک برنامه تابعی را فراخوانی می‌کند، یک «قاب پشته» جدید ایجاد می‌شود. این قاب پشته علاوه بر اینکه دربرگیرنده آرگومان‌هایی است که به تابع ارسال شده‌اند، دربرگیرنده فضایی پویا برای متغیرهای محلی تابع است. «اشاره‌گر پشته» ثباتی است که آدرس بالای پشته را نگهداری می‌کند. از آنجا که هر وقت مقدار جدیدی وارد پشته می‌شود محتوای این ثبات هم تغییر می‌کند، در خیلی از موارد یک «اشاره‌گر قاب» هم وجود دارد که در آغازی پشته قرار دارد تا بر اساس این اشاره‌گر بتوان به متغیرهای محلی راحت‌تر دسترسی پیدا کرد. اما مسئله‌ای که باعث ایجاد سرریز بافر می‌شود این است که آدرس برگشت فراخوانی تابع هم در پشته ذخیره می‌شود و از آنجا که سرریز شدن یک متغیر محلی می‌تواند باعث شود آدرس برگشت تابع در پشته بازنویسی شود، یک کاربر خرابکار قادر خواهد بود هر کدی که می‌خواهد را اجرا کند.[۱]

جلوگیری[ویرایش]

در هنگام برنامه‌نویسی باید از این توابع استفاده نشود. این توابع بدون بررسی کردن حجم بافر آن‌ها را بازنویسی می‌کنند که این مسئله می‌تواند دیگر مقادیر موجود در پشته مانند همان آدرس برگشت تابع را بازنویسی کند.

نام تابع دلیل
strcpy(char *dest, const char *src)
ممکن است بافر dest سرریز شود
strcat(char *dest, const char *src)
ممکن است بافر dest سرریز شود.
getwd(char *buf)
ممکن است بافر buf سرریز شود.
gets(char *s)
ممکن است بافر s سرریز شود
[vf]scanf(const char *format, ...)
تمام آرگومان‌ها در معرض سرریز شدن قرار دارند
realpath(char *path, char resolved_path[])
ممکن است بافر path سرریز شود.
[v]sprintf(char *str, const char *format, ...)
ممکن است بافر str سرریز شود.

جای تابع strcpy می‌توان از strncpy و به جای تابع strcat می‌توان از strncat استفاده کرد که این توابع با بررسی حدود بافر مقصد باعث جلوگیری از وقوع سرریز بافر می‌شوند. همینطور تابع fgets هم برای ورودی و خروجی استاندارد مناسب است.

نمونه[ویرایش]

کد زیر دارای یک اشکال است که باعث می‌شود سرریز بافر صورت پذیرد:

#include <stdio.h>

void manipulate(char *buffer) {
  char newbuffer[80];
  strcpy(newbuffer,buffer);
}

int main() {
  char ch,buffer[4096];
  int i=0;

  while ((buffer[i++] = getchar()) != '\n') {};

  i=1;
  manipulate(buffer);
  i=2;
  printf("The value of i is : %d\n",i);
  return 0;
}

آرایه newbuffer تنها ۸۰ بایت ظرفیت دارد و نمی‌تواند بیشتر از آن را در خود جای دهد. حالا اگر ما برنامه بالا را اجرا کنیم و ۱۶۰ کاراکتر تایپ کنیم، آرایه سرریز شده و اطلاعات بعد از آرایه هم بازنویسی می‌شوند.

نمونه پایه‌ای[ویرایش]

در نمونه زیر، یک برنامه تعریف شده دو داده که مجاور در حافظه: ۸-بایت بافر رشته‌ای، A، و یک عدد صحیح دو بایتی، B. در آغاز، A دارای هیچ چیزی صفر بایت و B شامل شماره ۱۹۷۹. طول هر کاراکتر یک بایت است.

variable name A B
value [null string] ۱۹۷۹
hex value ۰۰ ۰۰ ۰۰ ۰۰ ۰۰ ۰۰ ۰۰ ۰۰ ۰۷ BB

در حال حاضر، برنامه اقدام به ذخیره‌سازی رشته تهی پایان "بیش از حد" در بافرA. با شکست چک کردن طول رشته، آن را رونویسی مقدار B:

variable name A B
value 'e' 'x' 'c' 'e' 's' 's' 'i' 'v' ۲۵۸۵۶
hex ۶۵ ۷۸ ۶۳ ۶۵ ۷۳ ۷۳ ۶۹ ۷۶ ۶۵ ۰۰

با وجودی که برنامه نویس قصد ندارد برای تغییر B در مقدار B در حال حاضر تعداد شکل گرفته از بخشی از رشته کاراکتر جایگزین می‌شود. در این نمونه، بر روی یک سیستم big-endian است که با استفاده از ASCII، "E" به دنبال یک بایت صفر تبدیل شدن به تعداد ۲۵۲۵۶ است. اگر B تنها متغیر قلم دوم از اقلام داده‌های تعریف شده توسط برنامه بود، نوشتن یک رشته طولانی که رفت و گذشته از B می‌تواند باعث خطا مانند گسل تقسیم‌بندی شود، فسخ این روند بود.

بهره‌برداری[ویرایش]

تکنیک بهره‌برداری از آسیب‌پذیری سرریز بافر با توجه به نوع معماری، سیستم عامل و منطقه حافظه متفاوت است. به عنوان نمونه، بهره‌برداری بر اساس هیپ (برای حافظه به صورت پویا اختصاص داده شده‌استفاده می‌شود)، بسیار متفاوت از بهره‌برداری در پشته است.

پشته مبتنی بر بهره‌برداری[ویرایش]

کاربر تمایل به لحاظ فنی ممکن است سرریزهای بافر مبتنی بر پشته این برنامه برای دستکاری در یکی از راه‌های مختلفی را به نفع خود بهره‌برداری کند:

با جای نوشتن یک متغیر محلی است که در نزدیکی بافر در حافظه در پشته به تغییر رفتار از برنامه‌ای که ممکن است مهاجم بهره مند شوند

با جای نوشتن آدرس برگشت در قاب پشته. پس از بازده عملکرد، اجرا خواهد شد در آدرس برگشت، به عنوان مهاجم، معمولاً پر از بافر ورودی کاربر را مشخص سر گرفته شود.

با جای نوشتن تابع یک اشاره گر، یا برنامه کنترل استثنا است که پس از آن اجرا شده‌است.

با استفاده از یک روش به نام "trampolining"، در صورتی که آدرس داده‌های کاربر را تأمین ناشناخته‌است، اما محل در ثبت نام ذخیره می‌شود، و سپس آدرس برگشت، می‌تواند با آدرس شناسنده رونویسی است که باعث می‌شود که اجرای حکم اعدام به پرش تأمین شده توسط کاربر داده‌است.

اگر محل در ثبت نام R ذخیره می‌شود، سپس پرش محل حاوی شناسنده برای مراجعه R، تماس R یا دستورالعمل مشابه، اعدام از داده‌های کاربر عرضه می‌شود. محل opcodes مناسب، یا بایت در حافظه، می‌تواند در DLLها یا اجرایی خود را در بر داشت.

با این حال آدرس شناسنده به‌طور معمول هر کاراکتر تهی نیست و محل این opcodesها می‌تواند در میان برنامه‌ها و نسخه‌های سیستم عامل متفاوت باشد. پروژه Metasploit یک پایگاه داده‌های چنین opcodes مناسب است، هر چند تنها افراد موجود در سیستم عامل ویندوز ذکر شده‌است.

هیپ، مبتنی بر بهره‌برداری[ویرایش]

سرریز بافر در منطقه پشته داده به عنوان یک سرریز پشته اشاره می‌شود و بهره‌برداری را به شیوه‌ای متفاوت از سرریزهای مبتنی بر پشته انجام می‌دهد. حافظه پشته به صورت پویا توسط برنامه در زمان اجرا اختصاص داده شده و به‌طور معمول شامل داده‌های برنامه می‌باشد.

استثمار با فساد این داده‌ها در روش‌های خاص باعث می‌شود برنامه را بازنویسی سازه‌های داخلی مانند اشاره گر لیست پیوندی انجام می‌شود. روش سرریز پشته استاندارد، رونویسی پیوندی تخصیص حافظه‌های پویا (مانند داده‌های meta malloc) و با استفاده از ارز اشاره گر منجر به بازنویسی برنامه اشاره گر تابع است.

موانع استثمار[ویرایش]

دستکاری بافر رخ می‌دهد که قبل از آن خوانده می‌شود یا اعدام شده‌است، ممکن است منجر به شکست تلاش بهره‌برداری شود. این دستکاری می‌تواند تهدید از بهره‌برداری، کاهش، اما ممکن است آن را غیرممکن سازد. دستکاری می‌تواند تبدیل به بالا یا پایین‌تر مورد، حذف metacharacters و فیلترینگ از رشته‌های غیر الفبایی باشد.

با این حال، تکنیک‌ها یی برای دور زدن این فیلتر و دستکاری وجود داشته باشد ؛کد عدد و الفبایی، کدهای چند شکلی، خود را تغییر کد و بازگشت به حملات-libc. از روش مشابه می‌تواند مورد استفاده قرار گیرد برای جلوگیری از شناسایی توسط سیستم‌های تشخیص نفوذ است. در برخی موارد، از جمله که در آن کد را به یونیکد تبدیل شده، خطر از آسیب‌پذیری شده‌اند تحریف توسط disclosers به عنوان انکار تنها از خدمات که در واقع اعدام از راه دور کد دلخواه، امکان‌پذیر است.

نکات بهره‌برداری[ویرایش]

در دنیای واقعی سوء استفاده‌های مختلف از چالش‌های است که باید بر طرف شود برای سوء استفاده به عمل قابل اعتماد وجود دارد. این عوامل عبارتند از بایت‌های پوچ در آدرس‌ها، تنوع در محل شل کد، تفاوت میان محیط‌های مختلف مقابله با اقدامات در عمل است.

NOP روش سورتمه[ویرایش]

NOP-سورتمه قدیمی‌ترین و روش به‌طور گسترده‌ای شناخته شده برای موفقیت بهره‌برداری از یک سرریز بافر پشته‌است. راه حل این مشکل، پیدا کردن آدرس دقیق از بافر به‌طور مؤثر افزایش اندازه از منطقه هدف است.

برای انجام این بخش بسیار بزرگتر از پشته‌ها را با دستورالعمل دستگاه بدون عملیات خراب شده‌است. در پایان از داده‌های مهاجم تأمین، پس از دستورالعمل‌های بدون عمل، دستورالعمل به انجام پرش نسبت به بافر که در آن شل کد واقع شده‌است. این مجموعه‌ای از هیچ OPS به عنوان "NOP-سورتمه" می‌گویند چرا که اگر آدرس بازگشت با هر آدرس در منطقه بدون عملیات بافر رونویسی است از آن خواهد شد "اسلاید" پایین بدون-OPS تا آن را به کد مخرب واقعی پرش در پایان هدایت می‌شود. این روش نیاز به مهاجم که در پشته NOP-سورتمه‌است به جای استفاده ازشل کد نسبتاً کوچک، آن را حدس زد.

از آنجا که از محبوبیت از این روش، بسیاری از فروشندگان سیستم‌های پیشگیری از نفوذ این الگوی دستورالعمل دستگاه بدون عملیات در تلاش برای شناسایی شل کد در استفاده از جستجو می‌باشد. این مهم است توجه داشته باشید که NOP-سورتمه لزوماً شامل دستورالعمل دستگاه تنها سنتی بدون عملیات، دستور العمل‌ها که ماشین حالت به یک نقطه که در آن شل کد اجرا نمی‌شوند ومی تواند از سخت افزار مورد استفاده قرار می‌گیرد.

در نتیجه آن سورتمه روش معمول برای بهره‌برداری نویسندگان بدون عملیات با دستورالعمل که هیچ اثر واقعی در مورد اعدام شل کد نوشتن تبدیل شده‌است.

منابع[ویرایش]