نوشتن Exploit مبتني بر سر ريز بافر

۱۳۸۶ آبان ۲۵, جمعه ۱۸:۳۹ By Hamedan , In


در مسايل امنیت هکران عزیز و مدیران سایت ها در مساله ایی پیش رفته به مبحث buffer over flow میرسند که به نظر همه مبحث بسیار سنگین میباشد ولی در این تایپیک قصد آموزشی عملی به شما دوستان را دارم پس با ما همراه باشید

اين مقاله در پاييز 1383 تهیه و منتشر گرديد . بنابرین پیشاپیش از دوستان عزیز بابت تكراری بودن آن عذر خواهی می نمایم .

مقدمه

در این مقاله قصد بر این است که مباحث کاربردی ارائه گردند ، بنابرین فرض بر این است که خواننده با مفاهیم تئوری Stack Overrun آشنا می باشد . همچنین به دانش پایه در زمینه برنامه نویسی به زبان C یک Compiler ، و یک Debuger احتیاج دارید .
کدهای ارائه شده در Windows XP – SP1 – 2 و VC++ تست شده است . برنامه های اجرایی و کد منبع آن برای راحتی به صورت فایل فشرده شده قابل دریافت می باشد .
این مقاله مبحث سرریز بافر و نوشتن Exploit را به صورت Local بررسی می نماید و مباحث مربوط به Remote Buffer Overflow Exploitation در مقالات بعدی بررسی خواهد شد .


شروع به کار

قبل از شروع به این سلسله از مباحث این نکته را مد نظر داشته باشید که یادگیری کشف Security Bug و نوشتن Exploit مانند یادگیری ورزشهای رزمی می باشد . هیچگاه هنرهای رزمی را نمی توان با مطالعه یک یا صد کتاب فرا گرفت و متخصص شد ، تا شخص اقدام به تمرین عملی زیر نظر استاد ننماید ، بار ها و بارها شكست نخورد ، نمی تواند فنون را بیاموزد و استاد شود . بنابرین صرف مطالعه این مقاله یا مقالات و کتب دیگر و تمرین ننمودن ، نمی توانید انتظار زیادی از خود داشته باشید .

کد زیر را مطالعه نمایید . این کد دارای دو تابع به نامهای vulner و exploit می باشد. تابع اول دارای خطا می باشد که توسط تابع اصلی فرا خوانی می شود . اما تابع دوم در برنامه در حالت عادی اجرا نمی شود . هدف این می باشد که ما با ایجاد سر ریز بافر در تابع اول ، آدرس برگشت را به آدرس شروع تابع دوم تغییر داده ، و برنامه را مجبور به اجرای تابع دوم و نمایش پیغام " Oooops ! I Hacked by You !!! " بر صفحه نمایش نماییم .

 

کد:

/* Start Code
Stack Buffer Overrun Example 1
Bof.c
By Mehdi Ghassemi
2004-08-26
*/
include <stdio.h>#
include <string.h>#

void vulner(const char* input)

{
char buffer[12] ;
strcpy(buffer,input) ;
printf("%s\n",buffer) ;
}

void exploit(void)
{
printf("Oooops ! I Hacked by You !!!\n") ;

}

int main(int argc , char* argv[])
{
if(argc !=2)
{
printf("Please enter a string.\n") ;
return -1 ;
}

vulner(argv[1]) ;
return 0 ;

}

/* End Code */


ابتدا کد را بررسی می نماییم . برنامه یک رشته از کاربر دریافت نموده و آن را به تابع vulner ارسال می نماید . تابع فراخوانده شده نیز ابتدا یک آرایه به اسم buffer و به طول 12 کارکتر ایجاد نموده و با استفاده از تابع داخلی strcpy رشته دریافت شده کاربر را در buffer کپی می نماید . چنانچه ورودی کاربر کمتر از 12 کارکتر باشد ، در خروجی نمایش داده شده و برنامه به صورت نرمال پایان می پذیرد ، اما اگر ورودی کاربر بیشتر از طول buffer باشد ، چون اندازه ورودی چک و اصلاح نمی شود ، اجرای برنامه دچار مشکل شده و با ارسال پیغام خطا ، خروج غیر نرمال از برنامه را خواهیم داشت .

با این توضیح برنامه را compile و اجرا می نماییم . ابتدا برنامه را با ورودی کمتر از 12 کارکتر چک می کنیم . برنامه بدون مشکل اجرا می شود . حال تعداد کارکترها را یکی یکی افزایش می دهیم . وقتی تعداد کارکتر ورودی به عدد 12 می رسد ، برنامه دچار مشکل سر ریز بافر شده و شکل زیر نمایش داده می شود :

 


حالا مسئله ای که باید بدنبال جوابش باشیم این می باشد که به اندازه چه مقدار ورودی کاربر ، کارکترهای وارد شده بر روی آدرس برگشت به تابع فرا خوان قرار می گیرد . این کار را می توان با افزایش تعداد کارکتر ورودی و کنترل رجیستر EIP در لحظه به وجود آمدن خطا انجام داد .
یک را ساده این می باشد که در همین پنجره خطا که نمایش داده می شود ، بر روی لینک click here کلیک کنیم و مقدار Offset را چک نماییم . همانند شکل زیر :

 


این کار را ادامه می دهیم تا مقدار offset برابر با 4 تا کد اسکی A ، یعنی عدد 41 بشود ، یعنی دقیقاً به این شکل :

41414141 Offset:

اگر این کار را درست انجام داده باشید ، حتماً متوجه شده اید که به ازای 20 کارکتر ورودی ، آدرس برگشت تغییر می یابد . بنابرین 4 کارکتر آخر ، یعنی کارکتر 17 ، 18 ، 19 و 20 . یک سوال اینجا مطرح می شود که پاسخ آن را به عهده خواننده می گذاریم. چرا با آنکه ما سایز بافر را 12 کارکتر تعریف کردیم ، آدرس برگشت از کارکتر 16 به بعد آغاز شده است ؟

همین موضوع را با استفاده از یک Debuger کنترل می کنیم . ما از نرم افزار OllyDbg استفاده نمودیم که به راحتی از اینترنت قابل دریافت می باشد .

برنامه OllyDbg را اجرا می نماییم . به منوی file رفته و open را انتخاب می نماییم فایل bof.exe را انتخاب کرده و در همان پنجره در قسمت Arguments تعداد 20 کارکتر A را تایپ نموده و برنامه را اجرا می کنیم . برنامه load می شود ، اما در حالت paused قرار می گیرد ، قبل از اجرای برنامه ، به مقدار رجیستر EIP که در سمت راست نمایش داده شده است ، دقت نمایید . حالا با کلیک بر روی play برنامه را اجرا می نماییم . در این حالت مقدار رجیستر EIP به 41414141 تغییر پیدا می نماید . اگر همین عمل را با تعداد 17 ، 18 و 19 کارکتر انجام بدهید ، باید به نتیجه زیر برسید :

 
کد:



17 کارکتر A ==> 00000041 EIP =
18کارکتر A ==> 00004141 EIP =
19 کارکتر A ==> 00414141 EIP =
20 کارکتر A ==> 41414141 EIP =



 

البته ممکن است در بعضی از حالت ها بجای صفر اعداد دیگری باشد که مهم نمی باشد .
از این موضوع باید به این نتیجه برسیم که وقتی کارکتر ورودی از سمت راست افزایش پیدا می نماید ، قرار گیری بر روی رجیستر از سمت چپ انجام می شود . این موضوع را باید در هنگام نوشتن exploit رعایت نماییم . یعنی ترتیب قرار گیری آدرس را بر عکس نماییم .
حال باید به دنبال آدرس تابع exploit بگردیم تا با قرار دادن آن در خانه های 17 تا 20 ، به نتیجه دلخواه برسیم . برای این کار مجدداً OllyDbg را اجرا نموده و این بار bof.exe را با تعداد کارکتر نرمال که باعث سر ریز نشود اجرا می نماییم . از این مرحله به بعد ممکن است آدرس های بدست آمده با آنچه در اینجا ذکر می شود متفاوت باشد ، شما آدرسهایی که خودتان بدست می آورید ملاک قرار دهید .
در پنجره OllyDbg مطابق شکل زیر بدنبال رشته "Ooops! …" مربوط به تابع exploit می گردیم .

 


همانطور که در شکل مشخص می باشد ، OllyDbg تابع مورد نظر را با رنگ تیره تر مشخص نموده و آن را به اسمبلی تبدیل نموده است . در اینجا آدرس که با یک کادر قرمز رنگ مشخص شده است ، 00401090 می باشد . اگر کمی کنجکاوی به خرج دهید و صفحه را به بالا ببرید و به ابتدای کد اسمبلی مربوط برسید ، به سه دستور jmp بر می خورید که مربوط به سه تابع فایل bof.exe می باشد . می توانیم از آدرس 00401090 jmp نیز برای نوشتن exploit استفاده نماییم . نتیجه حاصله یکی می باشد . در اینجا از آدرس مستقیم استفاده شده است .
حال اطلاعات لازم برای نوشتن این exploit را داریم . اگر به C مسلط باشید ، به روشهای مختلف می توانید این exploit را بنویسید . ما خیلی ساده این برنامه را نوشتیم . کد exploit می تواند مثل قطعه کد زیر باشد :

 
کد:

/* Start Code
Stack Buffer Overrun Exploit Example 1
Expbof.c
By Mehdi Ghassemi
2004-08-27
*/
#include <windows.h>
#include <stdio.h>
unsigned char address[]= "\x90\x10\x40";
int main(void)
{
unsigned char buffer[28] ;
strcpy(buffer,"bof.exe ");
strcat(buffer,"MMMMMMMMMMMMMMMM");
strcat(buffer,address);
WinExec(buffer,SW_MAXIMIZE);
return 0;
}



 

در این کد که بسیار ساده می باشد ، تنها نکته همان قرار گیری آدرس می باشد که همانطور که اشاره شده ، به

0 نظرات: