PDA

توجه ! این یک نسخه آرشیو شده میباشد و در این حالت شما عکسی را مشاهده نمیکنید برای مشاهده کامل متن و عکسها بر روی لینک مقابل کلیک کنید : مقاله سریز بافر



بانوثریا
7th May 2010, 04:56 PM
سریز بافر (Buffer Overflow) از قدیمیترین مشكلات امنیتی سیستمهای كامپیوتری بوده است. در حال حاضر اگر به ضعفهای امنیتی نرم افزارهای مختلف كه در سایتهایی مثل SecurityFocus ثبت شده اند ،نگاهی بیاندازید ، متوجه می شوید كه حداقل 3/1 از این ضعفها مربوط به Buffer Overflow می شوند.این مشكل در تمام سیستم های عامل دیده شده است.در این مقاله با یك مثال ساده ، موضوع Buffer Overflow و چگونگی استفاده نفوذگرها از آن جهت نفوذ به سیستم های كامپیوتری بررسی خواهد شد. در پایان روشهایی برای جلوگیری از این نوع حملات ارائه خواهد شد.برنامه های ذكر شده در این مقاله به زبان C نوشته شده اند و باید تحت سیستم عامل Windows كامپایل شوند(در این مقاله تنها سرریز بافر در برنامه های Win32 مورد نظر است وبه سیستم های عامل دیگر مثل Unix/Linux اشاره نخواهد شد).
بررسی موضوع را با یك برنامه كوتاه آغاز می كنیم:
---------------------------------------------------------------------------------------------------------------------------------------
/* big.exe */
#include
int insecure_func (char *big) {
char insecure_buff[100];
strcpy(insecure_buff,big);
return 0;
}
int main (int argc, char *argv[]) {
char input_buff[1024];
gets(input_buff);
insecure_func(input_buff);
return 0;
}
-----------------------------------------------------------------------------------------------------
برنامه ابتدا رشته ورودی از صفحه كلید را در آرایه input_buff قرار میدهد سپس هنگامی كه تابع insecure_func با فرستادن input_buff فراخوانی شود ، این تابع مقدار موجود در input_buff رادر insecure_buff كپی خواهد كرد.نكته اصلی كوچكتر بودن اندازه insecure_buff از input_buff است. بطوریكه اگر input_buff بیشتر از 100 كاراكتر را در خود جای داده باشد ، insecure_buff سرریز (Overflow) خواهد شد.
حال برنامه را كامپایل و اجرا كنید و بیش از 100 كاراكتر 'a' را به عنوان ورودی به برنامه بدهید. پس از زدن كلید Enter پیغام خطایی دریافت خواهید كرد
ببینیم چه اتفاقی افتاده است: هر گاه یك تابع از درون یك روال دیگر فراخوانی میشود ، سیستم عامل آدرس برگشت به روال فعلی را در محلی از حافظه به نام "پشته" (ٍStack) قرار داده و كنترل را به روال فراخوانی شده می دهد . بدین ترتیب پس از پایان روال مذكور ، سیستم عامل با بازیابی ادرس برگشت از Stack دوباره اجرای برنامه راه به روال اصلی می دهد. در مثال بالا آدرس برگشت قبل از وقوع سرریز (پیش از اجرای دستور strcpy ) به دستور return 0 اشاره دارد. بنابراین قبل از وقوع سرریز Stack دارای ساختار زیر است :
___________________
| |
_|___________________|
| | |
| | | *************************
100 bytes = | | insecure_buff | !!! stack grows down !!!
| | | *************************
|_|___________________|_
| | |
| return address | | = 4 bytes
|___________________|_|
|___________________|
ساختار Stack
پشته (stack) همیشه به سمت آدرسهای پایین تر رشد می كند. هنگام شروع اجرای برنامه، سیستم عامل 100 بایت برای بافر insecure_buff كنار می گذارد. واضح است كه اجرا شدن دستور strcpy در حالتی كه اندازه رشته موجود در big بزرگتر از insecure_buff باشد ، باعث تغییر آدرس برگشت (return address) خواهد شد. اگر كمی دقت كنید ، می فهمید كه چرا آدرس برگشت بعد از سریز 0x61616161 است .x061 كد اسكی كاراكتر 'a' در مبنای 16 است كه توسط دستور strcpy قرار بوده به بافر insecure_buff كپی شود.
تا اینجا علت و چگونگی بروز stack overflow مشخص شد. اما چگونه این مشكل برای نفوذ به سیستم مورد استفاده قرار می گیرد؟ می دانیم كه تمام برنامه ها و روالهایی كه روی یك سیستم عامل در حال اجرا هستند، در آخرین لایه، چیزی جز كدهای ماشین نیستند كه پشت سرهم خوانده و اجرا می شوند. CPU كامپیوتر آدرس حافظه مربوط به دستورالعمل بعدی را در طول اجرای برنامه از رجیستر EIP خوانده و كنترل اجرای برنامه را به آن آدرس منتقل می كند. حال اگر بتوان آدرس موجود در این رجیستر را در هر مرحله ای از اجرای برنامه به مقدار دیگری تغییر داد، CPU بدون درنگ اجرای بقیه برنامه را از این آدرس جدید ادامه خواهد داد. تصور كنید در محل آدرس جدید كد یك backdoor یا سرویس پنهانی ویا هر نوع كد مخرب دیگری قرار داشته باشد. نتیجه این خواهد شد كه كامپیوتر این كد را بجای كد برنامه اصلی كه مسیرش توسط ما عوض شده، اجرا خواهد نمود و بدین ترتیب نفوذگر خواهد توانست با استفاده از backdoor یا كد محرب اجرا شده، كنترل سیستم مزبور را بدست گیرد. بنابراین نفوذگر برای رسیدن به هدف خود باید دو مساله را حل كند. اول یافتن راهی برای ایجاد overflow در سیستم هدف . برای اینكار نفوذگر ، سرویسها و برنامه های در حال اجرا روی سیستم هدف مانند Web Server ، Mail Server، Ftp Server و ... را برای یافتن روشی جهت overflow كردن هر كدام از آنها آزمایش خواهد نمود. بحث یافتن overflow ها از حوصله این مقاله خارج است و نمی توان روش استانداردی را پیشنهاد كرد و بیشتر روی سعی و خطا استوار است. مرحله دوم استفاده از برنامه overflow شده برای اجرای كد دلخواه.
برای نشان دادن روش كار نفوذگر، سعی می كنیم برنامه با استفاده از برنامه big.exe كد مورد نظر خود را روی سیستم اجرا كنیم. رشته ای را به عنوان ورودی (به جای 100 كاراكتر a) می سازیم كه شامل یك كد كوچك دستورات زبان اسمبلی (كه اصطلاحا exploit نامیده می شود) است كه كار مورد نظر مارا روی سیستم انجام خواهد داد و با تغییر آدرس برگشت، كنترل را به این كد خودمان می دهیم. بدین ترتیب به نتیجه مورد نظر خواهیم رسید.
برای نوشتن كد Exploit احتیاج داریم تا بدانیم رشته ورودی ساخته شده توسط ما در چه محلی روی آدرس برگشت ذخیره شده در انتهای Stack خواهد افتاد.برای دانستن این موضوع دو راه وجود دارد.روش اول استفاده از یك Disassembler برای یافتن اندازه بافر سرریز شده است. در این روش مجبوریم به دنبال تابعی بگردیم كه سرریز در آن اتفاق می افتد. راه دوم انجام آزمون و خطا است ، ابتدا باید رشته كاراكتری از كد های اسكی 32 تا 255 بسازیم ، كد كوچك زیر این كار را برایمان انجام می دهد:
-------------------------------------------------------------------------------------------------------------------------------
/* ascii.exe */
#include
void main(void) {
int i;
for (i=0;i c:\bof\big.exe | ascii.exe
این بار در پیغام خطا رجیستر EIP حاوی آدرس 0x8b8a8988 است(ترتیب قرارگیری از راست به چپ است). یعنی با شروع از محل صدو چهارم بافر (0x88-0x20=104) رشته ورودی روی آدرس برگشت می افتد. پس در رشته ای كه خواهیم ساخت محلهای 104 تا 107 حافظه (به طول 4 بایت) باید حاوی آدرس برگشت به كدی باشد كه می خواهیم اجرا شود.
مشكل اول حل شد ، حالا باید تصمیم بگریریم كه چگونه كد Exploit را تشكیل دهیم . در این باره دو امكان وجود دارد :
1- قرارگیری كد Exploit از ابتدای بافر تا محل 104 بافر
2- قرارگیری كد Exploit از محل 108 بافر به بعد
انتخاب روش اول اندازه كد Exploit مارابه 104 بایت محدود خواهد كرد ، به همین جهت روش دوم را انتخاب می كنیم و محلهای حافظه قبل از آدرس صدوچهارم را نیز با كد دستور اسمبلی NOP (No Operand) یعنی 0x90 پر می كنیم.
مساله آخر تعیین آدرس محل حافظه است كه می خواهیم به جای آدرس برگشت واقعی قرار دهیم. ابتدا به بررسی وضعیت رجیسترها و ساختار بافر درست قبل از اجرای دستور RET اسمبلی (تولید شده توسط دستور return 0 ) می پردازیم:
___________________
| |
0|___________________|
| |
| | *************************
| insecure_buff | !!! stack grows down !!!
| | *************************
104|___________________|
| | JMP ESP--> Our Exploit Code
تركیب 0xff0xe4 را می توان هم در حافظه برنامه big.exe و هم در حافظه مربوط به DLL های متصل به آن جستجو كرد. بهترین راه جستجو در DLL های متصل به برنامه است (در اینجا یكی دو فصل مربوط به فرمت فایلهای PE ویندوز را رد می كنیم و مطالعه آن را به عهده خواننده علاقه مند می گذاریم ). فایلهای DLL سیستم در ویندوز NT با شروع از آدرس Image Base در حافظه Load می شوند با كمك برنامه های PE Analyser می توان به آسانی این آدرس را پیدا كرد. در اینجا از برنامه LISTDLLS استفاده می كنیم كه می توانید آن را از سایت sysinternals دریافت كنید :

C:\bof> listdlls big.exe
. . .
Base Size Version Path
0x00400000 0x27000 C:\bof\big.exe
0x77f60000 0x5c000 4.00.1381.0130 D:\WINNT\System32\ntdll.dll
0x77f00000 0x5e000 4.00.1381.0133 D:\WINNT\system32\KERNEL32.dll
اطلاعات راجع به محل قرارگیری برنامه و DLL های آن در حافظه را می بینیم. می توانیم در حافظه یا داخل هر كدام از این 3 فایل نشان داده شده به دنبال كد دستور jmp esp بگردیم . جستجو در حافظه راحتتر است چون نیازی به محاسبه Offset ها بر خلاف داخل فایل نیست. از یك Debugger مثلا SoftICE استفاده می كنیم و هنگام وقوع سرریز كه كنسول SoftICE ظاهر می شود ، دستور زیر را اجرا می كنیم :
S 1000000 | ffffffff fee4
یعنی جستجوی حافظه از آدرس 0x01000000 (اولین آدرسی كه بایت اول مخالف صفر دارد) تا آخرین Offset حافظه یعنی 0xFFFFFFFF . نتیجه زیر حاصل خواهد شد :
Pattern found at 0023:77f327e5 (77f327e5)
دستور jmp esp در محل آدرس 0x77f327e5 پیدا شد این آدرس حاوی هیچكدام از كدهای CR(0x0c)،EOF(0x1a)، NULL(0x00) ، LF(0x0a) نیست و براحتی می توان از آن استفاده كرد.
توجه : آدرس فوق با توجه به ورژن Service Pack نصب شده روی سیستم عامل هدف مقادیر متفاوتی خواهد بود ، یه این سبب در مواردی كه Remote Exploit می نویسیم به طریقی از شماره Service Pack نصب شده روی كامپیوتر هدف اطلاع پیدا كنیم و سپس آدرس درست برای آن Service Pack را استفاده كنیم. روشهاب پیشرفته دیگری برای Exploit نویسی وجود دارند كه این مشكل را حل می كنند.
در این مرحله تمام اطلاعات لازم را در اختیار داریم : 1-محل قرارگیری كد Exploit معلوم شده است 2-آدرس كه باید بجای آدرس برگشت واقعی قرار داده شود ، می دانیم. تنها كار باقیمانده نوشتن برنامه Exploit است كه بر حسب Local یا Remote بودن هدف متفاوت خواهد بود. در این زمینه مطالب و كدهای فراوانی روی وب موجود هستند كه با پیش زمینه فعلی به آسانی می توانید از آنها ایده بگیرید.
چگونه از حملات Buffer Overflow چلوگیری كنیم؟
حملات buffer overflow از ضعف حاصل از عدم تست اندازه داده ورودی استفاده می كنند. اگر برنامه نویس big.exe قبل از دستور strcpy(insecure_buff,big); اندازه ورودی big را چك می كرد یا بجای تابع strcpy از strncpy به صورت strncpy(insecure_buff,big,100); استفاده می كرد، مشكل overflow بروز نمی كرد. لذا مهمترین اصل در برنامه نویسی یك سرویس یا برنامه مقاوم در برابر overflow ها چك كردن اندازه تمام ورودیها به برنامه قبل از انجام هر كاری روی داده هاست. برای برنامه نویسان محیط linux/unix كتابخانه هایی مانند StackGuard وجود دارند كه برنامه نویس می تواند با لینك كردن این كتابخانه ها به نرم افزارش، جلوی بسیاری از overflow ها را بگیرد.
اما در اكثر موارد، به كد سورس برنامه یا سرویس نصب شده روی سیستم خود دسترسی نداریم و قادر به تشخیص ضعفهای احتمالی از طریق بررسی سورس برنامه نیستیم همچنین اینكار از توان افراد غیر متخصص حارج می باشد. چاره ای كه در بعضی سیستم های عامل مانند Sun/OS و Linux اندیشیده شده است، ممانعت از اجرای كد در محیط پشته (Stack) است. همچنین این روش بصورت محدودی روی سیستمهای ویندوز پیاده شده است. اما بهترین و راحتترین روش برای عموم نصب تمام Patch ها و Fix های ارائه شده توسط تولید كننده نرم افزار است كه در 99% مواقع موثر خواهد بود.


دریافت اطلاعات بیشتر در مورد PE :
http://msdn.microsoft.com/library/en-us/dnwbgen/html/msdn_peeringpe.asp?frame=true
دریافت برنامه LISTDLLS :
http://www.sysinternals.com

استفاده از تمامی مطالب سایت تنها با ذکر منبع آن به نام سایت علمی نخبگان جوان و ذکر آدرس سایت مجاز است

استفاده از نام و برند نخبگان جوان به هر نحو توسط سایر سایت ها ممنوع بوده و پیگرد قانونی دارد