ورود/ایجاد حساب کاربری بسم الله الرحمن الرحیم سه شنبه، ۲۰ بهمن ۱۳۸۸
   طرح ملی نرم‌افزارهای آزاد/متن‌باز
· خانه
· معرفی طرح
· گزارشها
· پروژه‌ها
· فعالیتهای فرهنگ‌سازی و ترویجی
· فعالیتهای آموزشی
· خبرنامه افق لینوکس
· کتابها
· مدیران سایت
· سوالات متداول در مورد طرح
· ارتباط با ما

   امکانات وبگاه
· انجمن‌های گفتگو
· لیست بیشترین‌ها
· آرشیو اخبار
· آرشیو مقالات
· دریافت فایل
· جستجو در وبگاه
· آمار مشاهده‌ها
· طبقه‌بندی موضوعی خبر
· پیوند به وبگاه های مرتبط
· سوالات فنی رایج
· معرفی وبگاه به دوستان
   گروه کاربران لینوکس در ایران
· انجمن صنفی کاربران نرم افزارهای آزاد/متن باز
· گروه کاربران ایرانی اوبونتو
· گروه کاربران لینوکس خوزستان
· گروه کاربران لینوکس گیلان
· گروه کاربران لینوکس یزد
· گروه کاربران لینوکس مشهد
· گروه کاربران لینوکس اصفهان
· گروه کاربران لینوکس کیش
   وب گاه های همکار
· AICTC
· انجمن صنفی کاربران نرم افزارهای آزاد/متن باز
· نمایندگی رسمی LPI ایران
· تکنوتاکس
· گنو ایران
· گنو دانلود
· مدیریت محتوای پرسیسم
· فارسی پرس
· فروشگاه لینوکس شاپ
· سی تو: خرید توزیعهای لینوکس
· برنامه نویسان و کاربران متن باز ایرانی
· آموزش GTK
· نشریه الکترونیکی IranTux
   چند برنامه‌ی متن باز ایرانی

ذکر

فرهنگ لغاتxfardic

فرهنگ لغات mdic

انوار

   وضعیت کاربران سایت
مدیر
هیچیک از مدیران حاضر نیست
گروه خبر
هیچ مدیر کمکی حاضر
گروه مقالات
هیچ مدیر کمکی حاضر
اعضا:
جدیدترین: جدید امروز:0
جدیدترین: جدید دیروز:1
جدیدترین: مجموع:6595
جدیدترین: جدیدترین:
gafhab1360
اعضا: حاضر
اعضا: اعضا:0
مهمان‌ها: مهمان‌ها:37
مجموع: مجموع:37
 کاربران حاضر
هیچ کاربر حاضری وجود ندارد
مقابله با حملات سرریز بافر

(3829 کلمه در این مقاله وجود دارد)
(2594 بار مطالعه شده است)   نسخه چاپی

خوب، تا اینجا، و طی مقالات LHI1,2، با اصول و اساس کار اکسپلویت های سرریز بافر آشنا شدیم و یک اکسپلویت برای لینوکس slackware نوشتیم. اما آن اکسپلویتی که نوشته شده است، فقط بر روی نسخه های قدیمی پاسخ می دهد. چرا؟
معلوم است. به این دلیل که هر چه سیستم عامل ها پیشرفته تر می شوند، تدابیر بیشتری هم برای جلوگیری از اتفاق افتادن این ایرادات در نظر گرفته می شود. به همین دلیل، در این مقاله، با یک سری از روش هایی که سیستم های عامل برای مقابله با حملات سرریز بافر استفاده می کنند، آشنا خواهیم شد و در مقالات بعدی، به امید خدا سعی بر این است تا روش های دور زدن این تدابیر را بررسی نماییم. ولی توجه داشته باشید که این مقاله، در بعضی موارد، به شدّت با مفاهیم سیستم عامل و مدیریت حافظه، درگیر است و اصطلاحات و نکاتی در آن گنجانده شده که بدون آشنایی با این قضیه، احتمالاً در استفاده از این مقاله دچار مشکل خواهید شد.
همان طور که می دانید، حملات سرریز بافر، عملاً به این دلیل اتفاق می افتند که مقداری که قرار است در بافر قرار بگیرد، اندازه اش، قبل از ریختن، چک نمی شود و به همین دلیل ممکن است یک مقدار خیلی زیاد، در یک بافر کم قرار بگیرد. یکی از روشهایی که برای پیدا کردن نقاط آسیب پذیر یک برنامه استفاده می شود، پیدا کردن مکانهایی هست که از یک سری توابع برای کپی کردن یا بهتر بگوییم ریختن مقادیر در متغیر ها و ... استفاده می شود مثلاً تابعی مثل strcpy، کاری ندارد که طول رشته ای که می خواهد کپی کند، چقدر هست و طول بافر چقدر. فقط کپی می کند.
با این توضیحات، می توان اینگونه بیان کرد که یکی از راه های پیدا کردن نقاط آسیب پذیر احتمالی، بررسی کد منبع برنامه و گشتن به دنبال توابع آسیب پذیر است. توابعی مثل: strcpy, strcat, sprintf, vsprintf, gets, scanf, fscanf, sscanf, vscanf, vsscanf, vfscanfrealpath, getopt, getpass, streadd, strecpy و ...
ویندوز هم از این گونه توابع دارد. توابع ویندوزی مثل: wcscpy, _tcscpy, _mbscpy, wcscat, _tcscat, _mbscat و ... هم جزو توابع آسیب پذیر محسوب می شوند. یک سری ایرادات نیز وجود دارد که بر می گردد به ایرادات برنامه نویسی، مثل اینکه طول یه آرایه را، اشتباهاً یک واحد کم در نظر بگیریم که خطای رایجی هست و می تواند منجر به سرریز بافر شود.
بنابراین، این ایرادات، همه به خاطر طرز استفاده و ابزار مورد استفاده است که اتفاق می افتد. یکی از کارهایی که برای جلوگیری از اتفاق افتادن این ایرادها می توان انجام داد، این است که به برنامه نویس، آموزش دهیم که بیشتر دقا کند.
یکی دیگر از این روشها ، ایمن کردن سیستمی است که این برنامه ها، بر روی آن اجرا می شوند. برای این منظور هم روشهای مختلفی مورد استفاده قرار می گیرد که تعدادی از پر استفاده ترین روشها را می توان به صورت زیر طبقه بندی کرد:

حفاظ های قناری ای!!: مثل StackGuard (که در Immunix استفاده شده است)، ssp/ProPolice (که در OpenBSDاستفاده شده)، و حفاظی که با استفاده از گزینۀ /GS توسط مایکروسافت فراهم می شود.

حفاظهای غیر قابل اجرا کنندۀ پشته مثل پچ non-exec stack (مورد استفادۀ OpenWall) و Exec-Shield (مورد استفاده Redhat, Fedora).

سایر حفاظ های موجود نظیر libsafe که در Mandrake استفاده می شود، Split-Stack، TIED، LClint و ... .
البته تمام روش های بالا، ایراداتی دارند ولی استفاده از آنها، خیلی به ایمن شدن برنامه کمک می کند.
شاید اسم اولین دسته، یک ذره تخیلی به نظر آید ولی بی حکمت نیست. اگر در یک معدن کار کرده باشید تا حالا حتماً با کاربرد قناری در معدن آشنا هستید حالا چون ممکن است بعضی ها، استثنائاً در معدن کار نکرده باشند، می گوییم چه کاربردی دارد:
قناری، موجود حساسی است. در معدن (البته در زمانهای قدیم) چون زیر زمین بودن و ممکن بود ناخواسته به منابع گاز برسند، همیشه یک قناری با خود به همراه می بردند و به محض اینکه گاز نشت می کرد، این قناری، بال بال می زد یا می مرد و آنها می فهمیدند که گاز داره نشت می کند و سریع فکری می کردند قبل از اینکه خفه شوند. چه کسی فکر می کرد که یک روز، این مسئله، در یک مقاله راجع به سرریز بافر مطرح شود!!

پروتکشن های نوع اول، اساس کارشان، همین است. به عنوان مثال، StackGuard، که توسط Crisper Cowon ابداع شد، کارش همین است و کامپایلر C (gcc) را به گونه ای تغییر می دهد که یک مقدار "قناری"، جلوی آدرس برگشت قرار بگیرد و هر بار که تابعی صدا زده می شود، قبل از هر برگشتن از تابع، این مقدار قناری چک می شود که آیا مقدارش عوض شده یا نه و اگه عوض شده بود، برنامه متوقف شود. ولی حملات سرریز بافر، می توانند با تغییر دادن مقادیر دیگری بجز آدرس برگشت هم اتفاق بیفتند. پس تلاش شده که این قناری، در بقیه مقادیر در معرض خطر هم استفاده شود.
شمای کلّی کار، اینگونه می شود::















حفاظ Stack-Smashing Protector (SSP) که توسط IBM ایجاد شده است نیز وجود دارد که نام اصلی آن، ProPolice می باشد و تغییر یافتۀ همین StackGuard هست فقط یک سری پیچ و تاب جالب توجه، علاوه بر قرار دادن قناری، به ایدۀ اولیه اضافه شده است.
همان طور که می دانید، ساختار حافظه این گونه است که جهت پر شدن پشته، بر خلاف جهت افزایش آدرس های حافظه است و به همین دلیل، سرریز، همیشه از سمت بالای پشته (جایی که بافر ما قرار دارد) به سمت پایین پشته (جایی که آدرس برگشت قرار دارد) اتفاق می افتد. ترفندی که IBM بکار برده، این است که محل قرار گیری بافر را (اگر دقیق تر بگوییم متغیر های محلی تابع را) عوض کرده و آن را به پایین ترین قسمت پشته انتقال داده و آدرس آن را به صورت اشاره گر، در آرگومان های تابع قرار داده تا به این ترتیب، اگر هم سرریزی اتفاق افتاد، داده های مربوط به اشاره گر ها، دست نخورده باقی بمانند و خانه های دیگری از حافظه باز نویسی شوند و به این ترتیب، ماکزیمم خطری که ممکن است به وجود آید، DoS شدن هست.
شمای کلی کار، اینگونه است:





























OpenBSD، از نسخۀ 2003May به بعد، از این تکنیک (ProPolice) استفاده کرده است. مایکروسافت هم یه فلگ به کامپایلر اضافه کرده (/GS) که این قناری را بر پایۀ StackGuard، در کامپایلر C پیاده سازی کرده باشد.

پروتکشن های نوع دوم:
یک روش دیگر محافظت، غیر قابل اجرا کردن کدهای قرار گرفته شده در پشته می باشد. البته متأسفانه (یا خوشبختانه) مکانیسم های محافظت از حافظه که در پردازنده های x86 بکار گرفته شده، به راحتی از این روش پشتیبانی نمی کنند. به طور طبیعی، هر قسمتی از حافظه که قابلیت خوانده شدن داشته باشد، قابلیت اجرا شدن را هم دارد.
یک developer به نام Solar Designer، ترکیب هوشمندانه ای از مکانیسم های کرنل و پردازنده را برای ایجاد یک پچ با نام "non-exec stack" برای کرنل های لینوکس به کار برد. با این وصله (پچ)، دیگر برنامه هایی که در پشته قرار داشتند، نمی توانستند اجرا شوند. این مسئله بعضی جاها (مانند مواردی که احتیاج به کنترل سیگنالها باشد)، دردسر ساز می شود چون در این گونه موارد، برنامه احتیاج دارد که در پشته اجرا شود. Solar Designer، برای این موارد نیز راه حلی پیدا کرد که چگونه این موارد خاص هم اجرا شوند در حالی که از حملات یکدیگر جلوگیری می شود.
وصلۀ اصلی برای انجام این کار در کرنل لینوکس، در سال 1998 توسط لینوس توروالدز رد شد. علت رد شدن آن این بود که حتی اگر کد در پشته نتواند اجرا شود، با استفاده از تکنیک بازگشت به درون libc، می شود از روتین های موجود (مثلاً یک روتین در کتابخانۀ C) برای حمله استفاده کرد؛ به زبان ساده تر، فقط داشتن یک پشتۀ غیر قابل اجرا کافی نیست.
بعد از مدتی، ایدۀ جدیدی که برای این مشکل ارائه شد، ایده ای بود که تمام کد اجرایی را به قسمتی از حافظه به نام "منطقۀ زرهی اسکی" (ASCII) انتقال می دهد.
حالا این منطقه، چه ویژگی ای دارد؟
خوب همان طور که می دانید، زمانی که سرریز به وجود می آید نباید از Null byte استفاده کنیم. ویژگی این منطقه این است که در همۀ آدرس های مربوط به این ناحیه، حداقل یک بایت null (0) وجود دارد و به این ترتیب، حمله کردن، بسیار سخت تر خواهد شد.
بزرگترین محدودۀ پیوستۀ حافظه که این ویژگی را داشته باشد، از آدرس 0 تا 0x01010100 وجود دارد. البته آدرسهای دیگری نیز با این ویژگی وجود دارند ولی پراکنده هستند. این حفاظ، در ترکیب با پشته های غیر قابل اجرا، قدرت زیادی به ارمغان می آورند هرچند که این حفاظ زرهی، برای یه سری برنامه های خاص و برنامه های بزرگ جواب نمی دهد چون این برنامه ها، به فضایی بیشتر از 0 تا 0x01010100 برای اجرا شدن نیاز دارند.
Ingo Molnar از Redhat، این ایده را در وصلۀ exec-shield پیاده سازی کرد و در Fedora استفاده می شود. OpenWall GNU/Linux هم یک پیاده سازی این ایده که توسط Solar Designer انجام شده را مورد استفاده قرار می دهد.



سایر پروتکشن ها:
روش های دیگری نیز برای مقابله با سرریز بافر وجود دارد. به عنوان مثال یک روش، این است که روتین های استاندارد کتابخانه ای را در مقابل این حملات مقاوم کنیم. Lucent Technologies، یک مکمل با نام Libsafe را ارائه کرد که چندین توابع کتابخانه ای C مثل strcpy() که در مقابل حملات پشته، آسیب پذیر بودن را، ارائه داده بود. Libsafe، یک نرم افزار متن باز می باشد و تحت لیسانس LGPL ارائه شده است. توابع کتابخانه ای که به صورت Libsafe هستند، چک می کنند که بازنویسی شدنِ خانه های حافظه، به Stack Frame نرسد. هرچند این کار، فقط همین توابع خاص را مقاوم می کند و نه آسیب پذیری های سرریز پشته را و همچنین، این کار، فقط از پشته محافظت می کند و نه از مقادیر محلّی که در پشته وجود دارند، ولی باز هم خوب به نظر می رسد. در ضمن، پیاده سازی اصلی این توابع، از LD_PRELOAD استفاده می کند که ممکن است با برنامه های دیگر، تداخل داشته باشد. محض اطلاع، توزیع Mandrake، از libsafe استفاده می کند.
ایدۀ دیگر، "split control and data stack" می باشد که پشته را به دو پشته دیگر تقسیم می کند. یکی برای ذخیرۀ اطلاعات کنترلی (مثل آدرس برگشت) و دیگری برای ذخیرۀ بقیه اطلاعات. Xu et al، این قضیه را در gcc پیاده سازی کرد (این اسامی ژاپنی، کره ای و چینی، واقعاً تخیلی هستند!!!) و StackShield، آن را در اسمبلر پیاده سازی کرده. این مسئله، دستکاری کردن آدرس برگشت را خیلی سخت تر می کند ولی هنوز هم در مقابل حملات سرریزی که اطلاعات توابع فراخوانده شده را تغییر می دهند (یعنی کاری با آدرس برگشت ندارند)، آسیب پذیر است.
در حقیقت، راهکارهای دیگری نیز وجود دارد از جمله تصادفی کردن مکان های اجرایی. ایدۀ "PointGuard" که توسط Crispen ارائه شد هم، ایدۀ قناری را برای heap بسط داد و از این گونه ایده ها. ولی به طور کلی، می شود کلیه ایده ها را به دو قسمت خلاصه کرد:
بافری که به صورت استاتیک تخصیص داده شده است: وقتی بافر پر می شود، یک پیغام خطا یا هر چیز دیگر نشان داده شده و از اضافه کردن مقادیر بیشتر به بافر، جلوگیری می کنیم.
بافری که به صورت داینامیک تخصیص داده شده: وقتی بافر پر می شود، اندازه آن را تا گرفتن کل فضای حافظه، افزایش می دهیم.
هر کدام از این دو روش، مزایا و معایب خود را دارند. به عنوان مثال، اگر از بافر استاتیک استفاده کنیم، با توجه به اینکه اطلاعات "اضافه" دور ریخته می شود، یک هکر می تواند اطلاعات خود را در بافر بریزد و بقیه اطلاعات که قرار است اضافه شود (اطلاعات اصلی)، به عنوان اطلاعات اضافه در نظر گرفته می شوند. یا اگر از بافر داینامیک استفاده کنیم، با توجه به افزایش سایز، احتمال اینکه کل فضای حافظه (یا مقدار خیلی زیادی از آن) را از دست بدهیم، وجود دارد و این امر، باعث پایین آمدن کارایی و کند شدن سیستم می شود. بیشتر حملاتی که بر علیه این نوع بافرها شکل می گیرد، حملات DoS است.

اندکی دربارۀ exec-shield:
همان طور که می دانید، اولین قدم در راه مبارزه با حملات سرریز بافر، این است که به گونه ای مطمئن شویم که IP، دارد دقیقاً به همان چیزی اشاره می کند که باید اشاره کند. این همان ایده ای است که در حفاظ هایی نظیر exec-shield، تکنولوژی NX که توسط AMD و Intel فراهم آمده و همچنین حفاظ Data Execution Prevention که توسط مایکروسافت ارائه شده، به کار گرفته می شود. ممکن است بپرسید که خوب، چرا از اول، این چنین حفاظ هایی را قرار ندادند؟
به این دلیل که وقتی پردازنده های 80x86 ساخته شد، هیچ تفاوتی بین یک قطعه کد از حافظه که "قابل خوندن" باشد، با یک قطعه کد از حافظه که "قابل اجرا کردن" باشد، وجود نداشت. پس هر کدی خوانده می شود، اجرا نیز خواهد شد و این قضیه در پردازنده ها، به دلیل سازگار ماندن با 8086، از سال 1980 به بعد، استفاده می شود، هرچند که چندان استاندارد نیست.
Exec-shield و سایر حفاظ های مشابه (مثل PaX – آدرس اینترنتی: http://pax.grsecurity.net/)، با استفاده از "حدود سگمنت"، یک جداسازی تقریبی بین مجوز های خواندن و نوشتن انجام می دهند. این مجوز خواندن و نوشتن را با مجوز فایلها اشتباه نگیرید... این ها مجوز هایی هستند که برای مکان هایی از حافظه در نظر گرفته می شوند.
این "حدود سگمنت"، یک قابلیتِ گنگ و مبهم از قابلیت های خط تولید 80386 شرکت اینتل می باشد ولی تأثیر استفاده از "حدود سگمنت"، این است که N مگابایت اول حافظۀ مجازیِ پروسه در حال اجرا، قابل اجرا می شود، در حالی که باقی مانده این فضا، قابل اجرا نخواهد بود. این مقدار N هم توسط کرنل سیستم عامل مشخص می شود.














با وجود این حدّ و مرز، سیستم عامل، باید مطمئن باشد که قسمت کد برنامه، زیر این مرز قرار داشته باشه در حالی که data segment و به ویژه stack segment ، بالای این مرز قرار می گیرند. زمانی که تخطّی ای از مجوز اجرا صورت گیرد، برنامه، یک پیغام خطای Segmentation Fault نشان می دهد و از بین می رود. این رفتار، شبیه به رفتاری است که در برابر تخطّی از مجوز های خواندن و نوشتن در حافظه نشان داده می شود.
"حدود سگمنت"، تقریب قابل قبولی از جداسازی بین مجوز "خواندن" و مجوز "اجرا کردن" را با استفاده از این جدا سازی، برای ما به ارمغان می آورد. به این ترتیب، برای همۀ برنامه ها، کرنل قطعه کدِ برنامه را در قسمت پایین حافظه مجازی برنامه و اطلاعات را در دورترین قسمت از این قطعه قرار می دهد. در برخی موارد بسیار خاص و نادر، به خاطر اینکه این کار تقریبی می باشد، ممکن است محافظتی که به عمل می آید، کمتر از حد مطلوب باشد (مانند سرور XFree86 که از گرافیک در لینوکس محافظت می کند).

تکنولوژی NX شرکت های Intel و AMD:
هم AMD و هم Intel، کمبود این تفاوت بین مجوز های خواندن و اجرا کردن را در طراحی x86 احساس می کردند و به همین دلیل نیز AMD در خط تولید AMD64، معماری پردازنده های خود را با حفظ سازگاری با مدل های قبلی، گسترش داد و به گروه مجوز های حافظه ای که از قبل داشت، مجوز No eXecute را هم اضافه کرد. مثل مجوز های "خواندن" و "نوشتن"، کرنل، می تواند مجوز "اجرا نشدن" را هم در مورد واحد های 4KB حافظه، اعمال کند. Intel و سایر تولید کنندگان پردازنده، از این زمان به بعد، پشتیبانی از تکنولوژی NX را در پردازنده های خود قرار دادند.
استفاده از تکنولوژی NX، مناسب تر از استفاده از "حدود سگمنت" است و در Kernel mode هم بر خلاف "حدود سگمنت"، جواب می دهد. به همین دلیل نیز Redhat، از نسخه Red Hat Enterprise Linux v.3, update 3، در کرنل های نسخه هایی که ارائه می دهد، این قابلیت را قرار داده تا در صورت سازگاری سخت افزاری، از تکنولوژی NX استفاده شود.
فقط یک نگرانی در مورد تکنولوژی NX وجود دارد که وقتی اطلاعاتِ بیشتری برای این ساماندهی مجوز ها مورد نیاز باشد، در آن زمان، این تکنولوژی فقط در pagetable های مدل PAE 64 جواب می دهد (PAE 64، برای ساپورت کردن حافظه های بیشتر از 4 گیگابایت در پردازنده های x86 32 بیتی استفاده می شود). Pagetable های PAE هم در همۀ پردازنده های x86، ساپورت نمی شود. در ضمن این pagetable ها، حدود 6% سربار تحمیل سیستم می کنند و کارایی آن را نیز پایین می آروند.
به خاطر همۀ این محدودیت ها، PAE و تکنولوژی NX، در Red Hat Enterprise Linux v.3، فقط برای کرنل های kernel-smp و kernel-hugemem استفاده شده (که PAE رو، برای ساپورت بیشتر از 4 گیگابایت حافظه، به صورت فعال در خود دارند).

تصادفی کردن
همان طور که می دانید برای اینکه شل کد، با موفقیت اجرا شود، لازم است که هکر، آدرس تقریبی شروع شل کد (یا جایی در دنبالۀ NOP) را بداند، تا بتواند با تغییر دادن IP، به اآن مقدار، کاری کند که شل کد، به عنوان ادامۀ برنامه اجرا شود. ولی اگر دقت شود، خیلی از اکسپلویت ها می باشند که تصمیم گیری در مورد آدرس برگشت را به عهدۀ خود هکر می گذارند، یا اینکه با یک تقریبی این کار را انجام می دهند، یا چند گزینه در اختیار استفاده کننده قرار می گیرد که نوع سیستم عامل هدف را مشخص کند. یکی از دلایل این کار، این است که مکانی که آدرس برگشت، باید با آن مقدار باز نویسی شود، تقریباً برای سیستم های مشابه، یکسان می باشد.
البته در بسیاری از زمانها، این آدرس، برای سیستم هایی با برنامه های یکسان، کتابخانه های یکسان و خیلی چیز های دیگر یکسان، اساساً یکسان است یا تغییر خیلی کمی دارد که این امر، کار هکر را در پیدا کردن آدرس مناسب برای بازنویسیِ IP، خیلی آسان می کند. به این ترتیب که یک هکر، فقط کافی است این مقدار را برای سیستم خود بدست آورد و چون سایر سیستم های مشابه نیز چنین آدرسی دارند، اکسپلویت کردن همه آنها، کار ساده ای خواهد بود.
علاوه بر این، با استفاده از روش "بازگشت به درون libc"، برای اکسپلویت کردن، هکر، دیگر نیازی ندارد که کدی را در حافظه اجرا کند، بلکه تنها کاری که انجام می شود، تغییر آدرس برگشت، به آدرس یکی از توابع سیستم، مثل system() است که در این روش، چیزی که هکر باید بداند، مکان (آدرس) قرار گیری آن تابع خاص- مثلاً system()- ، در سیستم هدف است که این نیز به دلیل همان شباهت ها، اکثراً یکسان خواهد بود و به دلیل عدم اجرای کد در پشته، حفاظ exec-shield، دیگر کارایی خودش را در زمینۀ غیر قابل اجرا کردن پشته، از دست می دهد.
امّا توجه داریم که در تمام روش های اکسپلویت کردن که بررسی شد، دانستن آدرس برگشت، خیلی مهم و لازم است. بر این اساس، exec-shield، از Red Hat Enterprise Linux v.3, update 3 به بعد، به خیلی از اجزای اصلیِ درگیر در این قضیه، یک سری آفست های تصادفی اضافه می کند تا به این وسیله، پیدا کردن آدرس برگشت دقیق را تقریباً غیر ممکن کند و جلوی کار این اکسپلویت ها را بگیرد. به این ترتیب، هر بار که برنامه اجرا می شود و برای هر سیستمی که اجرا می شود، این آدرس ها متفاوت خواهد بود.
در Red Hat Enterprise Linux v.3, update 3، حفاظِ exec-shield، موارد زیر را به صورت اتوماتیک، تصادفی می کند:
• مکان قرار گیری پشته.
• مکان قرار گیری کتابخانه ها.
• مکان قرار گیری heap.


اجرایی های مستقل از موقعیت:
حال یک مسئله دیگر که وجود دارد، تصادفی کردن محل قرار گیری خودِ کدِ برنامه است. همان طور که می دانید، در لینوکس، برنامه ها، به شیوۀ قدیمی کامپایل می شوند و به این ترتیب، در حافظه، در مکانی از پیش تعیین شده (مکانی که موقع تولید فایل اجرایی مشخص می شود) قرار می گیرند و به خاطر این مسئله، این آدرس، نمی تواند به صورت تصادفی انتخاب شود و این عدم تصادفی کردن، نقطۀ ضعفی در زمینۀ مقابله با حملات سرریز بافر است.
ردهت، تکنیکی را پیاده سازی کرده به نام PIE (Position Independent Executable) – اجرایی مستقل از موقعیت- که به وسیلۀ این تکنیک، دیگر مشکل عدم تصادفی شدن محل قرار گیری کد برنامه، از بین می رود.
PIEها، به نحو خاصّی کامپایل شدند تا بتوانند آزادانه در هر قسمتی از address space برنامه، قرار بگیرند. در کرنل هایی که exec-shield را دارند، آدرسی که این باینری های PIE، در آن آدرس قرار می گیرند، تصادفی سازی شده ولی در کرنل های بدون exec-shield و فاقد پشتیبانی PIE، این آدرس، عموماً قابل پیش بینی هست. البته توجه داشته باشید که همۀ برنامه ها، مناسب نیست که به صورت PIE کامپایل شوند. با توجه به اینکه باینری هایی که PIE هستند، باید قابلیت تغییر مکان را داشته باشند، به گونه ای کامپایل می شوند که یک سری کد های مستقل از موقعیت (PIC-Position Independent Code) باشند و این مسئله، سربار کم، ولی محسوسی را موقع اجرا، به سیستم اعمال می کند (همان سرباری که کتابخانه های اشتراکی – shared liberary – به سیستم اعمال می کنند؛ چون کتابخانه های اشتراکی هم، به صورت PIC کامپایل می شوند).
در لینوکس، برای اینکه یک باینری را به صورت PIE کامپایل کنیم، کافی است موقع کامپایل کردن و لینک کردن، به ترتیب از آرگومان های –fpie و –pie استفاده کنیم و برای اینکه ببینیم یک باینری، به صورت PIE کامپایل شده یا نه، می توانیم از ترکیب دستورات readelf و grep استفاده کنیم:

readelf -h -d /usr/sbin/smbd | grep 'Type:.*DYN'
Type: DYN (Shared object file)

یک نکته ای که باید توجه کنیم، این است که بعضی برنامه ها، واقعاً نیاز دارند که مقادیری را در پشته اجرا کنند. ممکن است عجیب به نظر برسد ولی بنا به دلایلی، این کار، ممکن است انجام شود. یعنی یک برنامه ممکن است واقعاً احتیاج داشته باشد که کُدی را در پشته اجرا کند. حالا تکلیف برنامه ای، با وجود exec-shield چیست؟
در Red Hat، از نسخه 3 به بعد، امکانی که اضافه شد، همین است. یعنی یک فلگ برای باینری ها و کتابخانه ها قرار داده شد که اگه این فلگ، ست شده باشد، این برنامه، می تواند مقادیری را در پشته اجرا کند. علاوه بر این، اگر برنامه ای، اصلاً این فلگ را نداشته باشد، آن موقع، کرنل، باز هم آن را به عنوان یک برنامه قدیمی در نظر می گیرد که ممکن است احتیاج داشته باشه مقادیری را در پشته اجرا کند و این اجازه را می دهد. جدول زیر، رفتار و وضعیت این فلگ را نشان می دهد:

جدول 1 – پیش نمایی از رفتار فلگ ELF

برای اینکه چک کنیم که وضعیت این فلگ، در یک باینری یا یک کتابخانه چگونه است، می توانیم از ترکیب دستورات eu-readelf و grep استفاده کنیم. مثلاً اینجا وضعیت این فلگ را در فایل /bin/true بررسی می کنیم و می بینیم که پشته، برای این برنامه، غیرقابل اجرا است:

eu-readelf -l /bin/true | grep GNU_STACK
GNU_STACK 0x000000 0x00000000 0x00000000 0x000000 0x000000 RW

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


منابع:


1) Secure programmer: Countering buffer overflows
Preventing today's top vulnerability
David Wheeler (dwheelerNOSPAM@dwheeler.com), Research Staff Member, Institute for Defense Analyses
27 Jan 2004
http://www.ibm.com/developerworks/linux/library/l-sp4.html

2) New Security Enhancements
in Red Hat Enterprise Linux
v.3, update 3
By Arjan van de Ven
August 2004
http://www.redhat.com/f/pdf/rhel/WHP0006US_Execshield.pdf

3) Dr Google & …

تهیه و تنظیم: محمد گلیانی
تاریخ بارگذاری: 86/9/4
  

[ بازگشت به سایر موارد | صفحه اصلی مقالات ]


با مدیریت مرکز تحقیقاتی فناوری اطلاعات و ارتباطات پیشرفته دانشگاه صنعتی شریف و همکاری انجمن کاربران گنو/لینوکس ایران
کارفرمایان

تمامی مطالب و مقالات این سایت تحت مجوز GNU FDL قرار دارند. بنابراین کپی و ایجاد تغییر در آنها مطابق شرایط این مجوز آزاد میباشد. یک نسخه از این مجوز را اینجا می‌توانید برای خود دریافت نمایید.

مسئولیت صحت یا عدم صحت مطالب ارسال شده در سایت به عهده ارسال کننده آن مطلب می باشد


News