منوی سایت
جستجو

بررسی آسیب‌پذیری Buffer Overflow در زبان C

بررسی آسیب‌پذیری Buffer Overflow در زبان C

مقدمه

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

مفاهیم اولیه

  • بافر اوورفلو چیست؟ بافر اوورفلو یک آسیب‌پذیری امنیتی رایج در نرم‌افزارها است که زمانی رخ می‌دهد که داده‌های ورودی بیش از ظرفیت تعیین‌شده برای یک بافر (ناحیه ذخیره‌سازی موقت در حافظه) نوشته شود. این مسئله معمولاً به دلیل عدم بررسی صحیح اندازه داده‌های ورودی توسط برنامه اتفاق می‌افتد و می‌تواند منجر به خرابی برنامه، اجرای کدهای مخرب یا دسترسی غیرمجاز شود.
  • دستکاری آدرس بازگشت چیست؟ این تکنیک یکی از روش‌های رایج در حملات Buffer Overflow است که در آن، هکر با استفاده از آسیب‌پذیری موجود در مدیریت حافظه، آدرس بازگشت ذخیره‌شده در استک (Stack) را تغییر می‌دهد. در این روش، مهاجم داده‌های بیش از حد مجاز را درون بافر می‌ریزد و بخشی از حافظه مجاور (که شامل آدرس بازگشت است) را بازنویسی می‌کند. اگر این داده‌ها به‌گونه‌ای تنظیم شوند که آدرس بازگشت به یک بخش از حافظه که شامل کد مخرب است اشاره کند، برنامه پس از اتمام تابع، به‌جای ادامه مسیر عادی، کد مخرب را اجرا خواهد کرد.

کد برنامه آسیب‌پذیر

کد برنامه آسیب‌پذیر

بررسی کد

  • تابع win() به‌عنوان یک هدف در نظر گرفته شده است که اگر بتوانیم برنامه را فریب دهیم تا این تابع را اجرا کند، یعنی حمله موفق بوده است.
  • تابع login() شامل یک بافر ۶۴ بایتی است که از gets() برای دریافت ورودی استفاده می‌کند. این تابع به دلیل عدم بررسی اندازه ورودی، آسیب‌پذیر به سرریز بافر است و به مهاجم اجازه می‌دهد آدرس بازگشت را تغییر دهد.

تنظیمات کامپایل برای آزمایش

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

gcc -fno-stack-protector -z execstack -o vuln_login vuln_login.c

توضیحات:

  • -fno-stack-protector حفاظت‌های امنیتی استک را غیرفعال می‌کند.
  • -z execstack اجازه اجرای کد روی استک را می‌دهد.
  • این تنظیمات فقط در محیط‌های آموزشی استفاده شوند و در شرایط واقعی غیرفعال باشند.

پیدا کردن آدرس تابع win()

برای بهره‌برداری، باید آدرس تابع win() را در حافظه پیدا کنیم. این کار را می‌توان با استفاده از GDB انجام داد:

gdb vuln_login
(gdb) disassemble win

مثلاً خروجی می‌تواند این مقدار را نشان دهد:

0x080484cb <win>

این مقدار در هر اجرا ممکن است متفاوت باشد، بنابراین حتماً باید بررسی شود.

ساختن پیلود حمله

با داشتن آدرس تابع win()، می‌توان پیلودی ایجاد کرد که به‌جای مقدار اصلی آدرس بازگشت، این مقدار را جایگزین کند:

ساختن پیلود حمله

توضیح Little-Endian

آدرس 0x080484cb باید به‌صورت Little-Endian ذخیره شود، بنابراین بایت‌ها به این ترتیب جایگذاری می‌شوند:

cb 84 04 08

و در قالب رشته هگزا چنین نمایش داده می‌شود:

\xcb\x84\x04\x08

اجرای حمله

برنامه را اجرا کرده و پیلود را به‌عنوان ورودی ارسال می‌کنیم:

./vuln_login

پس از وارد کردن پیلود، اگر حمله موفقیت‌آمیز باشد، به‌جای پیام «پسورد اشتباهه»، تابع win() اجرا شده و پیام موفقیت نمایش داده می‌شود.

روش‌های جلوگیری از حمله Buffer Overflow

برای جلوگیری از این نوع حملات، روش‌های زیر پیشنهاد می‌شود:

  • استفاده از fgets() به‌جای gets()
  • فعال نگه‌داشتن حفاظت استک
  • محدود کردن اندازه ورودی کاربر
  • استفاده از تکنیک‌های مدرن مدیریت حافظه مانند ASLR (Address Space Layout Randomization)

هشدارهای اخلاقی

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

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

دیدگاه‌ها

برای ارسال نظر باید وارد حساب کاربری خود شوید.