X
تبلیغات
رایتل
چهارشنبه 27 آبان 1394 @ 16:40

درهم شکستن برنامه کاربردی یا سیستم عامل از طریق سرریز کردن پشته (Exploit Code)


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

    

پشته چیست ؟

پشته یک نوع ساختمان داده است که آیتم های داده در آن ذخیره می شود.دسترسی به آیتمها، مبتنی بر روش LIFO (Last In First Out ) است. یعنی در هر لحظه می توان به آخرین عنصر ذخیره شده در پشته دسترسی داشت. برای دسترسی به عناصر زیرین یک پشته،ابتدا باید عناصر روی آن ، از پشته خارج شوند.برای تجسم یک پشته ، سینی هایی را در نظر بگیرید که روی هم چیده شده اند. آخرین سینی که روی پشته سینی ها قرار گرفته اولین سینی خواهد بود که از روی آن برداشته می شود.برای دسترسی به سینی های زیرین ابتدا باید سینی های روی آن را بردارید.
اجزای سیستم عامل و همچنین برنامه های کاربردی ازپشته ، برای مقاصدی همانند فراخوانی توابع استفاده می کنند. در هنگامی که یک تابع فراخوانی می شود(Function Call ) اطلاعات بسیار حیاتی نظیر"آدرس برگشت تابع" ، "آرگومانهای ارسالی تابع" و "متغیر های محلی تابع" در فضای پشته ذخیره می شوند.( به عمل قرار دادن اطلاعات در بالای پشته عمل “push” گفته می شود.)هنگام باز گشت از یک تابع به برنامه اصلی ، آدرس محل بازگشت از پشته استخراج شده و نهایتا پشته به حالت اول خود برگشته و خالی می شود.(به عمل برداشتن اطلاعات از پشته اصطلا حا “pop” گفته می شود.)
به قطعه کدزیر دقت کنید

 

x0q8ohvw8kcz7aeoqt1u.jpg


وقتی اجرای این برنامه آغاز میشود، ابتدا اصلی ترین تابع برنامه یعنی Main() شروع به کار می نماید.

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

orjom31hqlecld17rof3.jpg

 

· ابتدا آرگومانهای ارسالی به تابع، (input arguments ) درون پشته قرار می گیرند.(درمثال قبل برای سادگی کار هیچگونه آرگومان ورودی برای تابع تعریف نشده است لذا چیزی برای ذخیره در پشته وجود ندارد)

· سپس آدرس از تابع، درون پشته ذخیره می شود.این آدرس، موقعیت اولین دستوری است که پس ازبازگشت از تابع باید اجرا شود.
· سپس اشاره گر فریم (frame pointer ) بر روی پشته قرار می گیرد.
· نهایتا فضایی بر روی پشته بمنظور ذخیر متغییر های محلی ، ایجاد می شود.
در مثال قبل یک متغیر محلی به نام buffer[10] تعریف شده که نیاز به تخصیص فضایی ده بایتی بر روی پشته دارد.در هنگام فرا خوانی تابع، این متغیر محلی ایجاد می شود و تا زمان بازگشت از تابع،فضای آن جهت پردازشهای محلی در اختیار تابع است.هنگام بازگشت از تابع تمام فضای ایجاد شده بر روی پشته آزاد می شود(popمی شود) و پشته به حالت قبل از فرا خوانی بر می گردد.(عمل آزاد سازی پشته فقط با تغییر مقدار اشاره گر پشته یعنی “stack pointer” انجام می شود) البته قبل از آن تمام رجیستر های پردازنده باید به حالت قبل از فرا خوانی تنظیم شوند.


نفوذگر به پروسه در حال اجرا داده هایی را ارسال می کند که اندازه ی آن بزرگتر از فضای بافر اختصاص داده شده است ، این داده ها می توانند کد های اجرایی ماشین باشند. بدلیل کمبود فضای بافر ، این داده ها حریم پشته را در هم شکسته و حتی اشاره گر بازگشت ازتابع را نیز بازنویسی می کنند. پس از اتمام تابع ، کنترل اجرا به محلی بر می گردد که اشاره گر بازگشت به آنجا اشاره میکند. اگر مقدار این اشارهگر آشغال باشد برنامه مختل شده و قفل میکند و اگر به مقدار دقیقی تنظیم شده باشد کنترل اجرا به محل مورد نظر نفوذگر منتقل خواهد شد.
مشکل سرریز شدن پشته از آنجای ناشی می شود که قبل ازانتقال داده ها به درون متغیر هایمحلی ، اندازه انها تطبیق داده نمی شود.
بسیاری از توابع کتابخانه ای در زبان c ، از این مشکل رنج می برند.
(مثل توابع strcpy() ، memcpy() ونظایر آنها)
حال اندکی بهاین نکته بپردازیم که چگونه نفوذگر میتواند کدهای ماشین راتولید وتنظیم کرده تا پس از سرریزشدن پشته ، کنترل اجرارا بدست بگیرد. در سیستم عامل یونیکس خطرناکترین کد اجرایی که نفوذگر می تواند از آن استفاده کندقطعه کدی است که برنامه " پوسته فرمان یا command shell " را فراخوانی واجرا می کند. اجرای چنین کدی راه را برای اجرای بقیه فرامین باز میکند. برای اینکار باید کد های اجرایی " تابع execve" که جزو توابع کتابخانه کتابخانه ای زبان c محسوب می شود ، تولید و اجرا شود. پس از اجرای این قطعه کد ، نفوذگر قادر است حملات دیگری را برنامه ریزی کند.



در سیستم عامل windows NT/2000 ، نفوذگر اغلب سعی می کند کدهای اجرایی یک از DLL ه را جهت بدست گرفتن کنترل برنامه فراخوانی واجرا کند. DLL ها در عبارتی غیر دقیق ولی ساده ، برنامه های نسبتا کوچکی هستند که توسط برنامه های کاربردی مختلف مورد استفاده قرار می گیرد وهر یکوظیفه ی خاصی دارند. یکیاز موثرترین DLL ها که می تواند برای اینگونهحملات مورد استفاده نفوذگر قرار بگیرد WININET.DLL است که با اجرای آن می توان اطلاعاتی را ازشبکه دریافت یا ارسال کرد.
موفقیت یا عدم موفقیت در این نوع حمله وابستگی شدید به نوع سیستم عامل ونوع پردازنده دارد.
بدلیل آنکه کدهای ماشین پردازنده ها متفاوت استبنابراین حمله به پشته در ماشین های x86 باحمله به پشته در ماشین های sun sparc ازلحاظ نوع کد ارسالی و روش ارسال فرق میکند. همچنین حمله به linux با حمله به windows بدلیل تفاوت در نوع فراخوانی توابع سیستمی ، کاملا متفاوت است.
سوء استفاده از از نقاطاسیب پذیر برنامه ها برایکسی که تابه حال بهاینمسئله فکر نکرده کمی غیر محتمل و بعید بهنظر می رسد ولیکن دقت داشته باشید که برنامه های امروزی در حجم بسیار وسیعی از فراخوانی تابع استفاده میکندد که متاسفانه بخش عظیمی از آنها هیچگونه کنترلی روی اندازهی دادههای ورودی نداشته وبصورت پیش فرض (وخوشبینانه) منتظر ورود داده با اندازه صحیح هستند.
بنابراین احتمال فروپاشی این برنامه ها وجود دارد.



دقیت کنید تفاوتی که برنامه های تحت شبکه با برنامه های معمولی (همانند مثال قبل) دارند در آن است که برنامه های معمولی ، داده های ورودی را از طریق پنجره ها یا آرگومانهای خط فرمان می گیرند در حالیکه برنامه های شبکه ، داده های ورودی را از طریق " پورت های باز " و از روی شبکه دریافت می کنند. بنابراین تلاش نفوذگر برای درهم شکستن پشته یک پروسه ی سرویس دهنده ، از راه دور نیز ممکن خواهد بود.
البته باید بپذیریم که ارسال کد های اجرایی برای پورتهای باز ( به منظور سرریز شدن پشته) به نحوی که کنترل اجرا در اختیار نفوذگر قرار بگیرد ، بسیار مشکل است . جزو یکی از پیچیده ترین مکانیزمهای حمله به شمار میرود. تا کنون نقاط ضعف سرویس دهنده های معروف و جهانی (مثل BIND/UNIX FTP/IIS و..) کشف شده و کد های لازم جهت در اختیار قرار گرفتن کنترل کامل آنها معرفی شده است. به این کد ها اصطلاحا “کدهای exploit " گفته می شود. ارسال داده برای پورتهای باز، فقط به منظور درهم شکستن برنامه سرویس دهنده احتمال موفقیت بالاتری دارد.
Exploit code
کد های که با ارسال آنها به یک پروسه سرویس دهنده ، ان را مختل کرده و در هم می شکند و کنترل ان را در اختیار نفوذگر قرار می دهد ، اصطلاحا Exploit code نام دارد. برنامه های مستقلی که این کد هارا ارسال می کنند ، برنامه های Exploit نامیده می شوند.



 پیدا کردن نقاط آسیب پذیر

نفوذگر از کجا متوجه می شود که یک برنامه یا پروسه دارای نقطه ضعف  است و پشته آن استعداد سرریز شدن دارد ،تا ان را هدف بگیرد؟

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

استفاده تز توابع زیر در زبان c  ، برنامه را بشدت آسیب پذیر می کند:

·         Fgets

·         Gets

·         Getws

·         Memcpy

·         Memmove

·         Scanf

·         Sprint

·         Strcat

·         Strncpy

·         …….

·         اگر نفوذگر ، کدبرنامه مورد نظرش را در اختیار نداشته باشد، می تواند با استفاده از یک debugger هدفش را تعقیب کند

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

گروه eEye Security برنامه سرویس دهنده Microsoft IIS را که یک سرویس دهنده وب محسوب می شود موردبمباران داده های طولانی قرار دادند. بعد از یک ساعت برنامه IIS با بجا گذاشتن پیغام " نقض حریم حافظه"  وگزارشی از محتوای رجیستر ها بصورت زیر درهم شکست شد:

EAX=00F7FCC8                                                                             EBX=00F41130
ECX=41414141                                                                             EDX=77F9485A
ESI=00F7FCC0                                                                                          EDI=00F7FCC0
EIP=41414141                                                                                          ESP=00F4106C
EBP=00F4108C                                                                             EFL=00000246

به مقادیر هیچکدام از رجیستر ها بغیر از رجیستر EIP کاری نداشته باشید به طور طبیعی محتوی رجیستر EIP آدرس دستور العملی در حافظه است که بایداجراشود. محتوای رجیستر EIP مقدار 41414141(hex) یعنی ‘AAAA’ گزارش شده است یعنی دقیقا مشابه با حمله ای که برنامه ساده مثال ، در ابتدای این بخش شده است. براساس نتیجه ای که گروه eEye از این حمله گرفتند حمله بعدی را بگونه ای ترتیب داد تا کنترل اجرابه  command shell منتقل شود.

نظرات (0)
برای نمایش آواتار خود در این وبلاگ در سایت Gravatar.com ثبت نام کنید. (راهنما)
نام :
ایمیل :
وب/وبلاگ :
ایمیل شما بعد از ثبت نمایش داده نخواهد شد