سرریز بافر پشته

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

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

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

#include <string.h>

void foo (char *bar)
{
   char  c[12];

   strcpy(c, bar);  // no bounds checking
}

int main (int argc, char **argv)
{
   foo(argv[1]); 
}

کد بالا، آرگومانی را از خط فرمان دریافت کرده و آن را در یک متغیر محلی به نام c که در پشته برنامه قرار دارد، می‌نویسد. اگر آرگومانی که در خط فرمان وارد می‌شود کوچکتر از 12 باشد، این برنامه به‌درستی کار خواهد کرد. با این حال، اگر آرگومان بزرگتز از ۱۱ کاراکتر باشد، باعث می‌شود بافر c سرریز شود (در زبان سی در انتهای رشته‌ها یک کارکتر null قرار می‌گیرد، بنابراین حداکثر اندازه ایمن برای این بافر ۱۱ است تا یک خانه هم برای آن کاراکتر null مهیا شود). اگر آرگومان خط فرمان ۱۲ کاراکتر باشد، برای ذخیره آن به بافری با اندازه ۱۳ نیاز است (هم خود آرگومان و هم کاراکتر null). از آنجا که بافر c تنها ۱۲ کاراکتر ظرفیت دارد، باعث می‌شود تا کاراکتر null در خارج از محدوده بافر نوشته شود و یک خانه آن طرفتر را بازنویسی کند. 

در شکل ج، وقتی که آرگوامنی بزرگتر از ۱۱ کاراکتر در خط فرمان وارد می‌شود، تابع foo() داده‌های موجود در پشته برنامه، از جمله اشاره‌گر قاب ذخیره شده و از همه مهمتر، آدرس برگشت تابع را بازنویسی می‌کند. وقتی که اجرای تابع foo() به اتمام می‌رسد و تابع برمی‌گردد، برنامه آدرس برگشت تابع را از پشته برداشته و سپس به آن آدرس پرش می‌کند و در نهایت سعی می‌کند اطلاعات موجود در آن آدرس را اجرا کند (برنامه شروع به اجرای دستورلعمل‌های موجود در آن آدرس می‌کند). بدین گونه مهاجم آدرس برگشت تابع را با اشاره‌گری به بافر char c[12] بازنویسی می‌کند و این بافر هم اطلاعاتی را در خود دارد که توسط مهاجم به برنامه تزریق شده‌اند. در یک حمله واقعی، اطلاعات موجود در بافر، به جای کاراکترهای A، شل‌کدی متناسب با پلتفرم و تابع مربوطه خواهد بود. اگر این برنامه دسترسی‌ها و امتیازات بالایی داشته باشد (مثلاً اگر بیت SUID برای اینکه برنامه به عنوان کاربر root اجرا شود، تنظیم شده باشد)، مهاجم می‌تواند از این آسیب‌پذیری برای بدست آوردن دسترسی ریشه به رایانه قربانی استفاده کند.

منابع 

 

اشکال‌های برنامه‌نویسی
خطاهای رایانه
سوءاستفاده امنیتی از رایانه
ناهنجاری‌های نرم‌افزاری