الفريق العربي للبرمجةأرشيف المنتديات · 2000 – 2023
نسخة أرشيفية للقراءة فقط — التسجيل والمشاركة مغلقان، والمحتوى محفوظ كما كان.

تطبيق #1: برنامج Easy RM to MP3 Converter

بدأه Z3r0n3 في 24 يوليو 2012 · 26 رد · 3,621 مشاهدة · في لغة Assembly لأنظمة 16, 32, 64 بت
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

بسم الله الرحمن الرحيم

السلام عليكم و رحمة الله و بركاته

هذا التطبيق الأول لدرس "ثغرة فيض مخزن المكدس". الموضوع عبارة عن نقاش و سيمّر بالمراحل التالية:

  1. طرق العثور على الثغرة
  2. جمع المعلومات اللازمة لإستغلال الثغرة
  3. كتابة الإستثمار

أرجو من جميع الأعضاء المهتمين بالموضوع المشاركة

بالتوفيق

1
#2

متابع :wink:

#4

أخي هل دلك البرنامج به هدا النوع من التغرات ؟هل وجدتها أم تريد أن نبحت عنها؟

#5
the inventor habib كتب:

أخي هل دلك البرنامج به هدا النوع من التغرات ؟هل وجدتها أم تريد أن نبحت عنها؟

البرنامج مصاب بالثغرة

#6
اقتباس
البرنامج مصاب بالثغرة

أين؟

#7

لماذا لا تحاولوا إيجادها بتطبيق درس Z3r0n3 حول ثغرات فيض المكدس؟

وإلا ما الهدف من هذا التطبيق على الدرس :)

بالتوفيق

1

Do as I say, not as I do

We are Anonymous. We are Legion. We don't forgive. We don't forget

#8

لقد أنشئت ملف q.RA وكتبت فيه ملايين A وعندما ضغطت علي زر LOAD لم يقع شيئا وعندما أقوم بتتبعه ب OLY لا يعمل لا أعرف السببب

#9

أضن أن المشكل سيقع هنا skin_config.ini

#10

المسألة ليست تخمين للملف الذي يتسبب في حدوث الثغرة. أدخل البرنامج إلى OllyDbg و اتبع نفس منهاحية الدرس و تذكر القاعدة التي وضعتها لحدوث الثغرة في البرامج التي تتعامل الملفات.

ننتظرك محاولتك :)

#11

ملاحظة:

-عند حدوث الإستثناء 6BAh قم بتجاوزه باستعمال SHIFT+F9

-البرنامج يستعمل دوال السي++ للتعامل مع الملفات (fopen،fread...)

تم تعديل هذه المشاركة بواسطة Z3r0n3 في 25 يوليو 2012 في 11:40

#12
Z3r0n3 كتب:

-البرنامج يستعمل دوال السي++ للتعامل مع الملفات (fopen،fread...)

أي أنه يخبرك (ولكن لا تخبره بأني أخبرك :P) بأن تبدأ بالبحث حول توابع التعامل مع الملفات فهي مكان جيد للبدء منه، تماماً كما أشار في ملاحظته في مقاله حول ثغرات فيض المكدس

Do as I say, not as I do

We are Anonymous. We are Legion. We don't forgive. We don't forget

#13
Xacker كتب:

أي أنه يخبرك (ولكن لا تخبره بأني أخبرك :P)

الغش ممنوع في الإمتحانات :stop: لكن في التطبيق على الدرس يمكننا العمل معا :hot: شرط مشاركة الجميع

#14

أخي مازال دلك الأستتناء .

لكن عندما أمر ياستعمال shift

لا يريد المرور .

#16

أنضر أين يتوقف التنفيد:

1343216348711.jpg

تم تعديل هذه المشاركة بواسطة the inventor habib في 25 يوليو 2012 في 14:40

#18
the inventor habib كتب:

لقد أنشئت ملف q.RA وكتبت فيه ملايين A وعندما ضغطت علي زر LOAD لم يقع شيئا وعندما أقوم بتتبعه ب OLY لا يعمل لا أعرف السببب

غيّر إمتداد الملف إلى ram و لاحظ التغييرات

#19

تم دلك وتلف

لكن المشكل يقع عندما أتتبعه.

لا أعرف لمادا.

#20

البرنامج يشتغل عندي داخل OllyDbg بدون مشاكل سوى حدوث استثناءات مع العلم أني اشتغل على نظام Windows 7 و استعمل النسخة الأصلية لـ OllyDbg الإصدار 1.10

#21

أعرف ثغرة هذا البرنامج فسبق أن إستُنزِف في الشروحات P:, سأفترض أنني لا أعرفها. أولاً نحتاج أن نفهم البرنامج وماذا يعمل. البرنامج مكتوب بـC++ مع MFC وتستطيع معرفة هذا من أسماء الوظائف التي يستخدمها البرنامج مثل :

....
CDialog::OnCancel(void)                                 .text 00437058 00000006 R . . . . . .
CDialog::OnSetFont(CFont *)                             .text 0043705E 00000006 R . . . . . .
CDialog::DoModal(void)                                  .text 00437064 00000006 R . . . . . .
CDialog::SetOccDialogInfo(_AFX_OCC_DIALOG_INFO *)       .text 0043706A 00000006 R . . . . . .
CDialog::CheckAutoCenter(void)                          .text 00437070 00000006 R . . . . . .
CDialog::PreTranslateMessage(tagMSG *)                  .text 00437076 00000006 R . . . . . .
CDialog::OnCmdMsg(uint,int,void *,AFX_CMDHANDLERINFO *) .text 0043707C 00000006 R . . . . . .
CDialog::GetRuntimeClass(void)                          .text 00437082 00000006 R . . . . . .
CEdit::GetRuntimeClass(void)                            .text 00437088 00000006 R . . . . . .
CComboBox::DeleteItem(tagDELETEITEMSTRUCT *)            .text 0043708E 00000006 R . . . . . .
CComboBox::CompareItem(tagCOMPAREITEMSTRUCT *)          .text 00437094 00000006 R . . . . . .
CComboBox::MeasureItem(tagMEASUREITEMSTRUCT *)          .text 0043709A 00000006 R . . . . . .
....

وظيفته تحويل صيغ وسائط الـRealAudioولو نظرت للمكتبات التي تأتي للبرنامج لوجدت مكتبات تعود ملكيتها لـRealNetworks , الشركة المطورة لريل بلاير:

post-231926-011831400 1343328107_thumb.p

ولو فتحتها بأداة Dll sniper , أدة لإستخراج أسماء الدوال من مكتبة dll, ستجد دوال يظهر أنها للتعامل مع ترميز:

post-231926-060819500 1343328115_thumb.p

هذا يجعلنا نستبعد أن يكون الخطأ من ملفات الـreal مثل rm, ram وغيرها (ملفات الصف الأول الذي يفتحها البرنامج) أو على الأقل لانجعلها أولوية. المكتبات غالباً تكون خضعت لمراجعة وتدقيق وقلما تسمع عن ثغرات في مكتبة , وخصوصاً في مكتبة قديمة لبرنامج منشر مثل real player فالكل كان مهتم بالعثور على ثغرات به. قد يكون البرنامج يتعامل مع المكتبات بطريقة خاطئة إلا أن هذا الشيء مستبعد في الوقت الحالي.

مالدينا من معلومات الآن:

  • البرنامج كتب بـC++ مع MFC.
  • البرنامج يتعامل ويحول الصيغ بإستخدام مكتبات جاهزة.
  • نستبعد حالياً أن يكون الخطأ في صيغ الـReal Media.

الإحتمال الكبير أن الثغرة في ملفات الصف الثاني Playlist files وأنواعها :

m3u, pls, smi, pl, wax, wvx, wmx

قبل أن نتقدم أكثر, لنرى كيف يقوم البرنامج بفتح ملف ما.

قال Z3r0n3 أن البرنامج يستخدم دوال الـC مثل fopen , fread, fclose في قراءة الملفات. لنرى كيف يقرأ البرنامج ملف ما وهل الثغرة عند جزء القراءة. سأستخدم IDA وأعمل تتبع للدوال. من قائمة Debugger في IDA إختر Tracing وإختر Tracing options. ستظهر النافذة التالية :

post-231926-057215100 1343325280_thumb.p

تأكد من جعل الإعدادات كما في الصورة. الأول لجعل التتبع غير محدود والباقية لتتبع كل شيء. شغل البرنامج تحت IDA وإضغط على Load وإختر أي ملف فارغ من نفس نوع ملفات الصف الثاني سمّه foo.m3u, لاتضغط على Open. الآن عد لـIDA من قائمة :

Debugger -> Tracing -> Function tracing

عد للبرنامج وإضغط OK وسيبدأ تسجل الدوال وإستدعاءاتها. بعدها بقليل ستظهر نافذة تخبرك بفشل البرنامج في تحميل الملف , عندما أوقف البرنامج من المنقح. الآن إذهب لنافذة سجل تتبع الدوال من :

Debugger -> Tracing -> Tracing window

ستظهر نافذة سترى بها كل إستدعاء قام به البرنامج من لحظة الضغط على Open إلى ظهور رسالة الخطأ. هذا رأس السجل (يمكنك حفظه لملف نصي ومراجعته, إضغط بزر الفارة الأيمن في النافذة وستجد save) :

Thread  	Address                 	Instruction                     	Result                                  	
00000B18	.text:sub_410A50+65     	retn                            	sub_410A50 returned to sub_41D7C0+10D   	
00000B18	.text:sub_41D7C0+119    	call    ??0CString@@QAE@XZ; CString::CString(void)	sub_41D7C0 call CString::CString(void)  	
00000B18	.text:sub_41D7C0+142    	call    sub_410BA0              	sub_41D7C0 call sub_410BA0              	
00000B18	.text:sub_410BA0+35     	retn                            	sub_410BA0 returned to sub_41D7C0+147   	
00000B18	.text:sub_41D7C0+161    	call    sub_410AC0              	sub_41D7C0 call sub_410AC0              	
00000B18	.text:sub_410AC0+33     	call    ?GetNextPathName@CFileDialog@@QBE?AVCString@@AAPAU__POSITION@@@Z; CFileDialog::GetNextPathName(__POSITION * &)	sub_410AC0 call CFileDialog::GetNextPathName(__POSITION * &)	
00000B18	.text:sub_410AC0+49     	retn    8                       	sub_410AC0 returned to sub_41D7C0+166   	
00000B18	.text:sub_41D7C0+173    	call    ??4CString@@QAEABV0@ABV0@@Z; CString::operator=(CString const &)	sub_41D7C0 call CString::operator=(CString const &)	
00000B18	.text:sub_41D7C0+183    	call    ??1CString@@QAE@XZ; CString::~CString(void)	sub_41D7C0 call CString::~CString(void) 	
00000B18	.text:sub_41D7C0+18F    	call    sub_41B7E0              	sub_41D7C0 call sub_41B7E0              	
00000B18	.text:sub_41B7E0+5      	call    __alloca_probe          	sub_41B7E0 call __alloca_probe          	
00000B18	.text:__alloca_probe+2E 	retn                            	__alloca_probe returned to sub_41B7E0+A 	
00000B18	.text:sub_41B7E0+8D     	call    ds:_strnicmp            	sub_41B7E0 call 768F0578                	
00000B18	.text:sub_41B7E0+122    	call    sub_431900              	sub_41B7E0 call sub_431900              	
00000B18	.text:sub_431900+5      	call    __alloca_probe          	sub_431900 call __alloca_probe          	
00000B18	.text:__alloca_probe+2E 	retn                            	__alloca_probe returned to sub_431900+A 	
00000B18	.text:sub_431900+3D     	call    sub_4312E0              	sub_431900 call sub_4312E0              	
00000B18	.text:sub_4312E0+3C     	call    ds:strncpy              	sub_4312E0 call 768F08A9                	
00000B18	.text:sub_4312E0+4B     	retn                            	sub_4312E0 returned to sub_431900+42    	
00000B18	.text:sub_431900+20E    	call    compare_media_prefix    	sub_431900 call compare_media_prefix    	
00000B18	.text:compare_media_prefix+1C	call    edi ; _strnicmp         	compare_media_prefix call 768F0578      	
00000B18	.text:compare_media_prefix+31	call    edi ; _strnicmp         	compare_media_prefix call 768F0578      	
00000B18	.text:compare_media_prefix+42	call    edi ; _strnicmp         	compare_media_prefix call 768F0578      	
00000B18	.text:compare_media_prefix+53	call    edi ; _strnicmp         	compare_media_prefix call 768F0578      	
00000B18	.text:compare_media_prefix+64	call    edi ; _strnicmp         	compare_media_prefix call 768F0578      	
00000B18	.text:compare_media_prefix+75	call    edi ; _strnicmp         	compare_media_prefix call 768F0578      	
00000B18	.text:compare_media_prefix+86	call    edi ; _strnicmp         	compare_media_prefix call 768F0578      	
00000B18	.text:compare_media_prefix+95	call    ds:strstr               	compare_media_prefix call 768EDE4A      	
00000B18	.text:compare_media_prefix+AE	retn                            	compare_media_prefix returned to sub_431900+213	
00000B18	.text:sub_431900+220    	call    ds:fopen                	sub_431900 call 768FB2C4                	
00000B18	.text:sub_431900+246    	call    ds:fread                	sub_431900 call 768FF3C8                	
00000B18	.text:sub_431900+251    	call    ds:fseek                	sub_431900 call 768FF606                	
00000B18	.text:sub_431900:loc_431B74	call    ds:ftell                	sub_431900 call 769022EA                	
00000B18	.text:sub_431900+27B    	call    ds:fclose               	sub_431900 call 768F3D79                	
00000B18	.text:sub_431900+28F    	retn                            	sub_431900 returned to sub_41B7E0+127   	
00000B18	.text:sub_41B7E0+174    	call    local_format_message    	sub_41B7E0 call local_format_message    	
00000B18	.text:local_format_message+3C	call    ds:_vsnprintf           	local_format_message call 768ED1A8      	
00000B18	.text:local_format_message+53	call    ds:malloc               	local_format_message call 768E9CEE      	
00000B18	.text:local_format_message+B7	call    dword_47BEAC            	local_format_message call 0141C930      	
00000B18	.text:local_format_message+BE	call    ds:free                 	local_format_message call 768E9894      	
00000B18	.text:local_format_message+D0	retn                            	local_format_message returned to sub_41B7E0+179	
00000B18	.text:sub_41B7E0:loc_41BD79	call    sub_422E90              	sub_41B7E0 call sub_422E90              	
00000B18	.text:sub_422E90+95     	call    ??2@YAPAXI@Z    ; operator new(uint)	sub_422E90 call operator new(uint)      	
00000B18	.text:sub_422E90+158    	call    ??3@YAXPAX@Z    ; operator delete(void *)	sub_422E90 call operator delete(void *) 	
00000B18	.text:sub_422E90+1C9    	retn    0Ch                     	sub_422E90 returned to sub_41B7E0+59E   	
00000B18	.text:sub_41B7E0+5AD    	retn    4                       	sub_41B7E0 returned to sub_41D7C0+194   	
00000B18	.text:sub_41D7C0+1CF    	call    ds:PostMessageA         	sub_41D7C0 call 7732B446                	
00000B18	.text:sub_41D7C0+1E1    	call    ??1CString@@QAE@XZ; CString::~CString(void)	sub_41D7C0 call CString::~CString(void) 	
00000B18	.text:sub_41D7C0+1F5    	call    sub_410960              	sub_41D7C0 call sub_410960              	
00000B18	.text:sub_410960+58     	call    ??1CString@@QAE@XZ; CString::~CString(void)	sub_410960 call CString::~CString(void) 	
00000B18	.text:sub_410960+67     	call    ??1CDialog@@UAE@XZ; CDialog::~CDialog(void)	sub_410960 call CDialog::~CDialog(void) 	
00000B18	.text:sub_410960+7B     	retn                            	sub_410960 returned to sub_41D7C0+1FA   	
00000B18	.text:sub_41D7C0+212    	retn                            	sub_41D7C0 returned to .text:00416839   	
00000B18	.text:0041683A          	retn                            	returned to 736340EA                    	
00000B18	.text:sub_41D050+1BE    	retn    4                       	sub_41D050 returned to 73634937

لو دققت النظر, ستلاحظ عملية قراءة ملف هنا , وهي التي ذكرها Z3r0n3 :

00000B18	.text:sub_431900+220    	call    ds:fopen                	sub_431900 call 768FB2C4                	
00000B18	.text:sub_431900+246    	call    ds:fread                	sub_431900 call 768FF3C8                	
00000B18	.text:sub_431900+251    	call    ds:fseek                	sub_431900 call 768FF606                	
00000B18	.text:sub_431900:loc_431B74	call    ds:ftell                	sub_431900 call 769022EA                	
00000B18	.text:sub_431900+27B    	call    ds:fclose               	sub_431900 call 768F3D79                	
00000B18	.text:sub_431900+28F    	retn                            	sub_431900 returned to sub_41B7E0+127

وأخرى هنا :

00000DF0	.text:sub_41B7E0+1CD    	call    ds:fopen                	sub_41B7E0 call 768FB2C4                	
00000DF0	.text:sub_41B7E0+1F6    	call    ds:fread                	sub_41B7E0 call 768FF3C8                	
00000DF0	.text:sub_41B7E0+201    	call    ds:fseek                	sub_41B7E0 call 768FF606                	
00000DF0	.text:sub_41B7E0+21E    	call    ds:ftell                	sub_41B7E0 call 769022EA                	
00000DF0	.text:sub_41B7E0+227    	call    ds:fclose               	sub_41B7E0 call 768F3D79                	
00000DF0	.text:sub_41B7E0+513    	call    sub_418D30              	sub_41B7E0 call sub_418D30

  1. فتح الملف fopen.
  2. قام بقراءته fread.
  3. غير مؤشر الملف fseek.
  4. أخذ موقعه الحالي ftell (هذه مع fseek طريقة سريعة لأخذ حجم الملف).
  5. أغلق الملف fclose.

الدالة أو الوظيفة التي بها تلك الدوال إسمها sub_431900 في الأولى وsub_41B7E0 عند الثانية, إسماء إفتراضية يضعها IDA إذا لم يعرف إسم الدالة وتستطيع إعادة تسميته. إذهب لقائمة الدوال في الجهة اليمنى وإبحث عن إسم الأولى sub_431900 , يمكنك كتابتها مباشرة. عند ظهور إسم الدالة إضغط عليها ثم إذهب لنافذة IDA view وإضغط على F5. سيظهر كود قريب للـC تقريبي للكود الأصلي لتلك الدالة لكنه بشع (لن تظهر أسماء الدوال كما في الصورة لأني اعدت تسمية بعض الدوال والمتغيرات + وضعت تلميحات بالأحمر على الأزرار ):

post-231926-026213000 1343332224_thumb.p

كود هذه الدالة :

FILE *__cdecl sub_431900(const char *Str)
{
  FILE *result; // eax@2
  size_t v2; // esi@4
  FILE *v3; // esi@23
  char DstBuf; // [sp+Ch] [bp-2600h]@22
  char Dest; // [sp+40Ch] [bp-2200h]@3

  if ( !Str )
    return 0;
  memset(&Dest, 0, 0x2200u);
  result = (FILE *)sub_4312E0(Str, &Dest);
  if ( result )
  {
    v2 = strlen(&Dest);
    if ( v2 != strlen("asx")
      && v2 != strlen("m3u")
      && v2 != strlen("pls")
      && v2 != strlen("smil")
      && v2 != strlen("wax")
      && v2 != strlen("wvx")
      && v2 != strlen("wpl")
      && v2 != strlen("wmx")
      && v2 != strlen("ram")
      || strnicmp(&Dest, "asx", v2)
      && strnicmp(&Dest, "m3u", v2)
      && strnicmp(&Dest, "pls", v2)
      && strnicmp(&Dest, "smil", v2)
      && strnicmp(&Dest, "wax", v2)
      && strnicmp(&Dest, "wvx", v2)
      && strnicmp(&Dest, "wpl", v2)
      && strnicmp(&Dest, "wmx", v2)
      && strnicmp(&Dest, "ram", v2) )
    {
      memset(&DstBuf, 0, 1024u);
      if ( !sub_431330((char *)Str) )
      {
        result = fopen(Str, "rb");
        v3 = result;
        if ( !result )
          return result;
        fread(&DstBuf, 1u, 0x400u, result);
        if ( fseek(v3, 0, 2) )
        {
          fclose(v3);
          return 0;
        }
        ftell(v3);
        fclose(v3);
      }
      result = 0;
    }
    else
    {
      result = (FILE *)1;
    }
  }
  return result;
}

الآن إذهب للدالة الثانية sub_41B7E0 وإعمل نفس الشيء , سيظهر هذا الكود :

FILE *__thiscall sub_41B7E0(void *this, const char *Str)
{
  void *v2; // ebx@1
  FILE *result; // eax@1
  unsigned int v4; // kr18_4@2
  unsigned int v5; // kr20_4@2
  const char *v6; // edi@2
  char *v7; // edi@6
  signed int v8; // ecx@6
  bool v9; // zf@8
  signed int v10; // ecx@9
  const void *v11; // esi@9
  char *v12; // edi@9
  unsigned int v13; // edx@9
  signed int v14; // ecx@9
  FILE *v15; // esi@18
  __int32 v16; // edi@21
  void *v17; // ecx@22
  int v18; // edx@22
  int v19; // ebx@22
  signed int v20; // edx@22
  void *v21; // ebp@22
  int v22; // esi@23
  int v23; // edi@24
  int v24; // edx@27
  signed int v25; // edx@28
  int v26; // esi@29
  int v27; // ecx@29
  void *v28; // eax@31
  void *v29; // edi@31
  void *v30; // eax@31
  int v31; // eax@35
  void *v32; // eax@36
  void *v33; // edi@37
  int v41; // [sp-Ch] [bp-4930h]@14
  signed int v42; // [sp-8h] [bp-492Ch]@14
  int *v43; // [sp-4h] [bp-4928h]@14
  void *v44; // [sp+10h] [bp-4914h]@31
  void *v45; // [sp+14h] [bp-4910h]@31
  char DstBuf; // [sp+18h] [bp-490Ch]@1
  unsigned int v47; // [sp+418h] [bp-450Ch]@1
  char ArgList; // [sp+41Ch] [bp-4508h]@14
  char v49; // [sp+2724h] [bp-2200h]@1

  v2 = this;
  result = 0;
  memset(&v49, 0, 0x2200u);
  memset(&v47, 0, 0x230Cu);
  memset(&DstBuf, 0, 0x400u);
  if ( Str )
  {
    v4 = strlen(Str) + 1;
    v5 = strlen("PNM") + 1;
    v6 = Str;
    if ( v4 - 2 >= v5 - 2 )
      v6 = "PNM";
    if ( !strnicmp("PNM", Str, strlen(v6) - 1) && !dword_47BD31 )
    {
      strcpy(&v49, "rtsp");
      v7 = (char *)(Str + 3);
      v8 = -1;
      do
      {
        if ( !v8 )
          break;
        v9 = *v7++ == 0;
        --v8;
      }
      while ( !v9 );
      v10 = ~v8;
      v11 = &v7[-v10];
      v12 = &v49;
      v13 = v10;
      v14 = -1;
      do
      {
        if ( !v14 )
          break;
        v9 = *v12++ == 0;
        --v14;
      }
      while ( !v9 );
      memcpy(v12 - 1, v11, v13);
      strcpy((char *)Str, &v49);
    }
    if ( !sub_431900(Str) )
    {
      strcpy(&ArgList, Str);
      v47 = strlen(Str);
      sub_432C30(-1, "%s is added to the source list .", (unsigned int)&ArgList);
      v43 = (int *)&v47;
      v42 = 1;
      v41 = *(_DWORD *)((char *)v2 + 137542);
LABEL_45:
      sub_422E90(v41, v42, v43);
      return (FILE *)1;
    }
    if ( !*(_DWORD *)((char *)v2 + 25702) || !*(_DWORD *)((char *)v2 + 25706) )
    {
      strcpy(&ArgList, Str);
      v47 = strlen(Str);
      sub_432C30(-1, "%s is added to the source list .", (unsigned int)&ArgList);
      v43 = (int *)&v47;
      v42 = 1;
      v41 = *(_DWORD *)((char *)v2 + 137542);
      goto LABEL_45;
    }
    if ( sub_431330((char *)Str) )
      goto LABEL_48;
    result = fopen(Str, "rb");
    v15 = result;
    if ( !result )
      return result;
    fread(&DstBuf, 1u, 0x400u, result);
    if ( fseek(v15, 0, 2) )
      return 0;
    v16 = ftell(v15);
    fclose(v15);
    if ( v16 <= (signed int)0x40000u )
    {
LABEL_48:
      sub_418D30(v2, 2);
      sub_41E2B0(Str);
      result = (FILE *)1;
    }
    else
    {
      strcpy(&ArgList, Str);
      v47 = strlen(Str);
      sub_432C30(-1, "%s is added to the source list .", (unsigned int)&ArgList);
      v17 = *(void **)((char *)v2 + 137542);
      v18 = *(_DWORD *)((char *)v2 + 137546);
      v19 = (int)((char *)v2 + 137534);
      v20 = (signed int)((unsigned __int64)(1960787567i64 * (v18 - (signed int)v17)) >> 32) >> 12;
      v21 = v17;
      if ( ((unsigned int)v20 >> 31) + v20 >= 1 )
      {
        sub_423250(v17, v17, (char *)v17 + 8972);
        sub_423290(*(_DWORD *)(v19 + 8), 1 - (*(_DWORD *)(v19 + 8) - (signed int)v21) / 8972, &v47);
        v32 = *(void **)(v19 + 8);
        if ( v21 == v32 )
        {
          *(_DWORD *)(v19 + 8) += 8972;
          result = (FILE *)1;
        }
        else
        {
          do
          {
            v33 = v21;
            v21 = (char *)v21 + 8972;
            memcpy(v33, &v47, 0x230Cu);
          }
          while ( v21 != v32 );
          *(_DWORD *)(v19 + 8) += 8972;
          result = (FILE *)1;
        }
      }
      else
      {
        v22 = *(_DWORD *)(v19 + 4);
        if ( !v22
          || (v23 = (signed int)((char *)v17 - v22) / 8972, (unsigned int)((signed int)((char *)v17 - v22) / 8972) <= 1) )
          v23 = 1;
        if ( v22 )
        {
          v25 = (signed int)((unsigned __int64)(1960787567i64 * (signed int)((char *)v17 - v22)) >> 32) >> 12;
          v24 = ((unsigned int)v25 >> 31) + v25;
        }
        else
        {
          v24 = 0;
        }
        v26 = v24 + v23;
        v27 = v24 + v23;
        if ( v24 + v23 < 0 )
          v27 = 0;
        v28 = operator new(8972 * v27);
        v45 = v28;
        v29 = v28;
        v30 = *(void **)(v19 + 4);
        v44 = *(void **)(v19 + 4);
        if ( v30 != v21 )
        {
          while ( 1 )
          {
            sub_423310(v29, v30);
            v29 = (char *)v29 + 8972;
            v44 = (char *)v44 + 8972;
            if ( v44 == v21 )
              break;
            v30 = v44;
          }
        }
        sub_423290(v29, 1, &v47);
        sub_423250(v21, *(_DWORD *)(v19 + 8), (char *)v29 + 8972);
        nullsub_2(*(_DWORD *)(v19 + 4), *(_DWORD *)(v19 + 8));
        operator delete(*(void **)(v19 + 4));
        *(_DWORD *)(v19 + 12) = (char *)v45 + 8972 * v26;
        v31 = sub_422E10(v19) + 1;
        *(_DWORD *)(v19 + 4) = v45;
        *(_DWORD *)(v19 + 8) = (char *)v45 + 8972 * v31;
        result = (FILE *)1;
      }
    }
  }
  return result;
}

إنظر لطريقة قراءة الملف في كل الدالتين. ستجدها متشابهة تماماً :

FILE *__cdecl sub_431900(const char *Str)

    ....

      if ( !sub_431330((char *)Str) )
      {
        result = fopen(Str, "rb");
        v3 = result;
        if ( !result )
          return result;
        fread(&DstBuf, 1u, 0x400u, result);
        if ( fseek(v3, 0, 2) )
        {
          fclose(v3);
          return 0;
        }
        ftell(v3);
        fclose(v3);
      }
      result = 0;
    }
    else
    {
      result = (FILE *)1;
    }
  }
  return result;
...

FILE *__thiscall sub_41B7E0(void *this, const char *Str)

    ....

    result = fopen(Str, "rb");
    v15 = result;
    if ( !result )
      return result;
    fread(&DstBuf, 1u, 0x400u, result);
    if ( fseek(v15, 0, 2) )
      return 0;
    v16 = ftell(v15);
    fclose(v15);
    if ( v16 <= (signed int)0x40000u )
    {
LABEL_48:
      sub_418D30(2);
      sub_41E2B0(Str);
      result = (FILE *)1;
    }

    ....

سأخذ الثانية كمثال sub_41B7E0, لو أعدت كتابة جزء قراءة الملف بالـC سيكو شيء كهذا (أمضيت بعض الوقت في معرفة دلالات المتغيرات والرموز) :

    FILE *file_handler;
    uint32_t file_size;
    char *file_name              = "foo.media";
    char readbuffer[1024];

    memset(&readbuffer, 0, 1024);

    file_handler    = fopen(file_name, "rb");
    if(!file_handler)
        return NULL;
    fread(&readbuffer[0], sizeof(char), 1024, file_handler);
    if( fseek(file_handler, 0, SEEK_END) )
        return 0;
    file_size = ftell(file_handler);
    if( file_size <= 262144) {
        Object.unknown(2);
        Object.setFileName(file_name);
    }
    else {
        // Some code
    }

طريقة قراءة الملف نفسها سليمة, فهناك buffer بحجم 1024 ويقرأ البرنامج 1024. أي أنه لامشكلة مع ذلك الجزئين. فلو حاولت وضع بيانات بحجم 10,000 بايت, فلن يقرأ إلا 1024 بايت منها في دورة واحدة.

هذه معلومة مهمة.إذا كانت هناك مشكلة فهي في طريقة معالجة الملف وليس في قراءته. يعني أننا نحتاج لإستخدام طريقة الـfile format fuzzing. هذه طريقة تقوم على أخذ ملف سليم ثم البدء بتشويه بنيته ثم مراقبة طريقة معالجة البرنامج. أبسط بنية لملفات الـxml مثلاً تكون بالشكل التالي :

<block>
    <subblock name="Ahmed"></subblock>
</block>

في بعض الحالات يخطئ البرنامج في معالجة صيغة مثل هذا الملف, فقد يضع المبرمج 255 بايت كحجم قيمة name مثلاً. فيقوم مهاجم بوضع ألف بايت :

<block>
    <subblock name="AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA..."></subblock>
</block>

حينما يقرأ البرنامج name , بوم.. حصل هناك فيض.

ماهي الخطوة التالية؟ أن تتعرف على بنية الملفات هذه :

m3u, pls, smi, pl, wax, wvx, wmx

ويمكنك إسنخدام قوقل لهذا الغرض بإستخدام إسم الصيغة متبوعة بـfile format. قم بعمل ملفات مشوهه والعبث في بنية تلك الملفات, وراقب كيف يقرأها البرنامج.

المرفقات
1.png2.png3.png4.png
6
#22

تحليلك منطقي جدا لإمتداد الملفات التي يمكن أن تتسبب في حدوث خطأ، و هذه بداية جيدة.

اقتباس
طريقة قراءة الملف نفسها سليمة, فهناك buffer بحجم 1024 ويقرأ البرنامج 1024. أي أنه لامشكلة مع ذلك الجزئين. فلو حاولت وضع بيانات بحجم 10,000 بايت, فلن يقرأ إلا 1024 بايت منها في دورة واحدة.

هذا غير صحيح، بستعمل البرنامج الجزء التي قمت بكتابته لقراءة الملفات الصوتية (rm، rmvb، ...) و ملفات الـPlayList مع القليل من الفوارق المهمة خاصةَ الإجراءات التي تنفذّ بعد الرجوع من هذه الدالة. تخيّل أن لدينا ملف حجمه يفوق 1024 بايت خاصتا و أنّ الملفات الصوتية غالبا يتجاوز حجمها 1024 بايت. هذا يعني أن هذا ليس الجزء الرئيسي لقراءة الملفات

قم بالبحث في الإجراءات التي تلي هذا الجزء من الكود :wink:

=====

محاولة رائعة و تحليل منطقي :) ننتظر إكمالك للمهمة الأولى :wink:

بالتوفيق

1
#23

مرحلة 1: طريقة العثور على الثغرة

نعلم أنّ البرنامج مصاب بثغرة فيض مخزن المكدس، و يحصل هذا عند التعامل مع الملفات

يتعامل البرنامج مع نوعين من الملفات. ملفات وسائط لها الامتداد:

*.ra; *.ram; *.rm; *.rmj; *.rmvb; *.smi

و ملفات الـPlaylist (عبارة عن ملف يحتوي على روابط إلى ملفات وسائط):

*.m3u, *.pls, *.smi, *.wpl, *.wax, *.wvx, *.wmx

نفتح البرنامج داخل OllyDbg و نقوم باستخراج أهم الدوال التي تتعامل مع الملفات:

  • fopen: لفتح ملف (تشبه الدالة CreateFile). ترجع الدالة قيمة مخالفة للصفر في حالة تمّ فتح الملف بنجاح
  • fread: للقراءة من ملف (تشبه الدالة ReadFile)
  • ftell: ترجع الموقع الحالي لمؤشر الملف
  • fseek: تستعمل لتغيير مؤشر الملف
  • fclose: لغلق الملف. بعد استعمال هذه الدالة لن تكون أي من الدوال السابقة تشتغل

مثل ما ذكرت سابقا، أن أول عملية يقوم بها البرنامج للتعامل مع الملفات هي استعمال الدالة fopen لفتح الملف. لذلك تتبع البرنامج بدابة من هذه الدالة سيكون الطريق الصحيح للعثور على الثغرة. من برنامج OllyDbg نضغط على CTRL+N لإظهار قائمة الدوال التي يقوم البرنامج باستيرادها. نبحث عن الدالة fopen ثم نضغط Enter لإظهار إستدعاءات البرنامج لهذه الدالة. نقوم بوضع نقاط توقف على تعليمات استدعاء الدالة وهي أربع تعليمات.

نضغط F9 لتشغيل البرنامج:

أول توقف للبرنامج سيكون عند استدعاء الدالة لفتح الملف "ProgramPath\skins\Default\ skin_config.ini" (ألقي نظرة على المكدس لتعرف ذلك من خلال البرامترات الممررة للدالة)

004270BE  |. FF15 20C74300  CALL DWORD PTR DS:[<&MSVCRT.fopen>]      ; \fopen

أكمل التتبع خطوة بخطوة إلى أن تصل إلى التعليمة:

004270C7  |. 3BC5           CMP EAX,EBP

و هي تعليمة مقارنة بين القيمة المرجعة من الدالة fopen (EAX) و المسجل EBP الذي دائما يحتوي على القيمة 0 عند هذا السطر. أكمل التتبع إلى أن تصل إلى تعليمة القفز المشروطة:

004270CA  |. 74 4C          JE SHORT RM2MP3Co.00427118

يتم القفز إلى العنوان 427118h في حالة كان الملف غير موجود (EAX=EBP=0)، ما عدا ذلك يقوم بتنفيذ الدالة fclose لإغلاق الملف. يعني لا يوجد فائدة لإكمال التتبع داخل هذا الإجراء طالما لم يقم بقراءة بايتات من الملف. نزيل نقطة التوقف عند هذا الاستدعاء للدالة fopen و نكمل التنفيذ (F9).

ثاني توقف للبرنامج سيكون مشابه لأول توقف. نزيل عنه نقطة التوقف و نكمل التنفيذ. سيقوم البرنامج بإنشاء النافذة الرئيسية و إظهارها.

ملاحظة: في حالة حصول الاستثناء 6BAh نستعمل SHIFT+F9 لتجاوزه (سيحصل الاستثناء أكثر من مرة)

ننشأ ملف فارغ يحمل الامتداد rm (مثل: sound.rm) ثم من نافذة البرنامج نضغط على الزر Load لتحميل هذا ملف (لاحظ أنه يندرج ضمن ملفات النوع الأول التي يتعامل معها البرنامج). عندها سيتوقف البرنامج عند استدعاء جديد للدالة fopen التي ستقوم بفتح الملف و ترجع مؤشر إلى الكائن FILE الذي يستعمل من باقي الدوال للوصول إلى الملف. نكمل التنفيذ للتعليمة الموالية:

00431B26  |. 8BF0           MOV ESI,EAX ; ESI=EAX=pFile

نواصل التنفيذ إلى أن نصل إلى بداية استدعاء الدالة fread:

00431B39  |> 56             PUSH ESI                                 ; /stream
00431B3A  |. 68 00040000    PUSH 400                                 ; |n = 400 (1024.)
00431B3F  |. 8D4C24 14      LEA ECX,DWORD PTR SS:[ESP+14]            ; |
00431B43  |. 6A 01          PUSH 1                                   ; |size = 1
00431B45  |. 51             PUSH ECX                                 ; |ptr
00431B46  |. FF15 1CC74300  CALL DWORD PTR DS:[<&MSVCRT.fread>]      ; \fread

تقوم هذه الدالة بقراءة مصفوفة تحتوي على n عنصر كل عنصر يكون حجمه size بايت من الملف المحدد في stream و نقلها إلى المخزن الذي يشير إليه المعامل ptr. حجم البيانات التي يتم قراءتها هو n*size.

إذا تقوم هذه الدالة بقراءة 1024*1 بايت من الملف و نقلها إلى المخزن الذي يشير إلى المسجل ECX و هو مخزن موجود في المخزن (يمكنك التثبت من ذلك بعد تنفيذ التعليمة عند العنوان 431B3Fh)

تحقق شرط الأول من حدوث ثغرة فيض مخزن المكدس وهو أن يكون المخزن الذي سيستقبل البيانات من الملف موجود في المكدس. الشرط الثاني هو أن يقوم البرنامج بنقل كامل بيانات الملف إلى المخزن. هذا ما سنبحث عنه الآن.

=====

نكمل لاحقا

3
#24
Z3r0n3 كتب:

تحليلك منطقي جدا لإمتداد الملفات التي يمكن أن تتسبب في حدوث خطأ، و هذه بداية جيدة.

هذا غير صحيح، بستعمل البرنامج الجزء التي قمت بكتابته لقراءة الملفات الصوتية (rm، rmvb، ...) و ملفات الـPlayList مع القليل من الفوارق المهمة خاصةَ الإجراءات التي تنفذّ بعد الرجوع من هذه الدالة. تخيّل أن لدينا ملف حجمه يفوق 1024 بايت خاصتا و أنّ الملفات الصوتية غالبا يتجاوز حجمها 1024 بايت. هذا يعني أن هذا ليس الجزء الرئيسي لقراءة الملفات

قم بالبحث في الإجراءات التي تلي هذا الجزء من الكود :wink:

=====

محاولة رائعة و تحليل منطقي :) ننتظر إكمالك للمهمة الأولى :wink:

بالتوفيق

في كل البرنامج لايوجد هناك الا دالتين تستدعيان fread, , وهي الدالة التي عنوانها 431900 و41B7E0 :

post-231926-018942300 1343427776_thumb.p

وهذا ProcessMonitor يؤكد أن ملف الـram لم يُقرأ الا مرتين من لحظة تشغيل البرنامج إلى أن حولته إلى mp3 :

12:26:39.7332624 AM	RM2MP3Converter.exe	5084	ReadFile	C:\Users\Barakat\Desktop\Projects - Shortcut.lnk	SUCCESS	Offset: 0, Length: 1,258, Priority: Normal
12:26:43.0705573 AM	RM2MP3Converter.exe	5084	ReadFile	C:\Users\Barakat\Desktop\pandemonium-porject-the-active-building.ram	SUCCESS	Offset: 0, Length: 4,096, Priority: Normal
12:26:43.0713547 AM	RM2MP3Converter.exe	5084	ReadFile	C:\Users\Barakat\Desktop\pandemonium-porject-the-active-building.ram	SUCCESS	Offset: 0, Length: 4,096, Priority: Normal
12:26:57.3658014 AM	RM2MP3Converter.exe	5084	ReadFile	C:\Users\Barakat\Desktop\pandemonium-porject-the-active-building.mp3	END OF FILE	Offset: 262,144, Length: 32,768, I/O Flags: Non-cached, Paging I/O, Synchronous Paging I/O, Priority: Normal
12:27:00.8011276 AM	RM2MP3Converter.exe	5084	ReadFile	C:\Users\Barakat\Desktop\pandemonium-porject-the-active-building.mp3	END OF FILE	Offset: 524,288, Length: 32,768, I/O Flags: Non-cached, Paging I/O, Synchronous Paging I/O, Priority: Normal
12:27:04.2356360 AM	RM2MP3Converter.exe	5084	ReadFile	C:\Users\Barakat\Desktop\pandemonium-porject-the-active-building.mp3	END OF FILE	Offset: 786,432, Length: 32,768, I/O Flags: Non-cached, Paging I/O, Synchronous Paging I/O, Priority: Normal
12:27:07.9130749 AM	RM2MP3Converter.exe	5084	ReadFile	C:\Users\Barakat\Desktop\pandemonium-porject-the-active-building.mp3	END OF FILE	Offset: 1,048,576, Length: 32,768, I/O Flags: Non-cached, Paging I/O, Synchronous Paging I/O, Priority: Normal
12:27:11.3664798 AM	RM2MP3Converter.exe	5084	ReadFile	C:\Users\Barakat\Desktop\pandemonium-porject-the-active-building.mp3	END OF FILE	Offset: 1,310,720, Length: 32,768, I/O Flags: Non-cached, Paging I/O, Synchronous Paging I/O, Priority: Normal
12:27:14.9483023 AM	RM2MP3Converter.exe	5084	ReadFile	C:\Users\Barakat\Desktop\pandemonium-porject-the-active-building.mp3	END OF FILE	Offset: 1,572,864, Length: 32,768, I/O Flags: Non-cached, Paging I/O, Synchronous Paging I/O, Priority: Normal
12:27:18.2552300 AM	RM2MP3Converter.exe	5084	ReadFile	C:\Users\Barakat\Desktop\pandemonium-porject-the-active-building.mp3	END OF FILE	Offset: 1,835,008, Length: 32,768, I/O Flags: Non-cached, Paging I/O, Synchronous Paging I/O, Priority: Normal
12:27:21.3757078 AM	RM2MP3Converter.exe	5084	ReadFile	C:\Users\Barakat\Desktop\pandemonium-porject-the-active-building.mp3	END OF FILE	Offset: 2,097,152, Length: 32,768, I/O Flags: Non-cached, Paging I/O, Synchronous Paging I/O, Priority: Normal
12:27:24.6982671 AM	RM2MP3Converter.exe	5084	ReadFile	C:\Users\Barakat\Desktop\pandemonium-porject-the-active-building.mp3	END OF FILE	Offset: 2,359,296, Length: 32,768, I/O Flags: Non-cached, Paging I/O, Synchronous Paging I/O, Priority: Normal
12:27:27.8699878 AM	RM2MP3Converter.exe	5084	ReadFile	C:\Users\Barakat\Desktop\pandemonium-porject-the-active-building.mp3	END OF FILE	Offset: 2,621,440, Length: 32,768, I/O Flags: Non-cached, Paging I/O, Synchronous Paging I/O, Priority: Normal
12:27:34.1350483 AM	RM2MP3Converter.exe	5084	ReadFile	C:\Users\Barakat\Desktop\pandemonium-porject-the-active-building.mp3	END OF FILE	Offset: 3,145,728, Length: 32,768, I/O Flags: Non-cached, Paging I/O, Synchronous Paging I/O, Priority: Normal
12:27:36.9088937 AM	RM2MP3Converter.exe	5084	ReadFile	C:\Users\Barakat\Desktop\pandemonium-porject-the-active-building.mp3	END OF FILE	Offset: 3,407,872, Length: 32,768, I/O Flags: Non-cached, Paging I/O, Synchronous Paging I/O, Priority: Normal
12:27:40.2135647 AM	RM2MP3Converter.exe	5084	ReadFile	C:\Users\Barakat\Desktop\pandemonium-porject-the-active-building.mp3	END OF FILE	Offset: 3,670,016, Length: 32,768, I/O Flags: Non-cached, Paging I/O, Synchronous Paging I/O, Priority: Normal
12:27:43.4558275 AM	RM2MP3Converter.exe	5084	ReadFile	C:\Users\Barakat\Desktop\pandemonium-porject-the-active-building.mp3	END OF FILE	Offset: 3,932,160, Length: 32,768, I/O Flags: Non-cached, Paging I/O, Synchronous Paging I/O, Priority: Normal
12:27:46.6552974 AM	RM2MP3Converter.exe	5084	ReadFile	C:\Users\Barakat\Desktop\pandemonium-porject-the-active-building.mp3	END OF FILE	Offset: 4,194,304, Length: 32,768, I/O Flags: Non-cached, Paging I/O, Synchronous Paging I/O, Priority: Normal
12:27:50.4866867 AM	RM2MP3Converter.exe	5084	ReadFile	C:\Users\Barakat\Desktop\pandemonium-porject-the-active-building.mp3	END OF FILE	Offset: 4,456,448, Length: 32,768, I/O Flags: Non-cached, Paging I/O, Synchronous Paging I/O, Priority: Normal
12:27:57.4050849 AM	RM2MP3Converter.exe	5084	ReadFile	C:\Users\Barakat\Desktop\pandemonium-porject-the-active-building.mp3	END OF FILE	Offset: 4,980,736, Length: 32,768, I/O Flags: Non-cached, Paging I/O, Synchronous Paging I/O, Priority: Normal
12:28:00.5001721 AM	RM2MP3Converter.exe	5084	ReadFile	C:\Users\Barakat\Desktop\pandemonium-porject-the-active-building.mp3	END OF FILE	Offset: 5,242,880, Length: 32,768, I/O Flags: Non-cached, Paging I/O, Synchronous Paging I/O, Priority: Normal
12:28:02.1140813 AM	RM2MP3Converter.exe	5084	ReadFile	C:\Users\Barakat\Desktop\pandemonium-porject-the-active-building.mp3	SUCCESS	Offset: 0, Length: 4,096, Priority: Normal
12:28:02.1141282 AM	RM2MP3Converter.exe	5084	ReadFile	C:\Users\Barakat\Desktop\pandemonium-porject-the-active-building.mp3	SUCCESS	Offset: 417, Length: 4,096, Priority: Normal
12:28:02.1160049 AM	RM2MP3Converter.exe	5084	ReadFile	C:\Users\Barakat\Desktop\pandemonium-porject-the-active-building.mp3	SUCCESS	Offset: 5,407,844, Length: 128, Priority: Normal

عند تحويل الملف فإن البرنامج لا يقرأه, بل هناك إستدعاء لـCreateFileMapping :

12:26:43.1463523 AM	RM2MP3Converter.exe	5084	CreateFileMapping	C:\Users\Barakat\Desktop\pandemonium-porject-the-active-building.ram	SUCCESS	SyncType: SyncTypeOther

أي أنه يقوم بعمل mapping للملف وليس قراءة مباشرة . هذا يفسر كيف يقوم بقراءة الملفات الكبيرة.

المرفقات
ref.png

تم تعديل هذه المشاركة بواسطة Mr.B في 28 يوليو 2012 في 01:38

1
#25

=====

نفتح الملف "sound.rm" بأي محرر نصوص و نضع فيه 1024 حرف (حرف=1 بايت)، بعدها نضيف إليه حروف أخرى مختلفة عن الحرف الأول و ذلك لنتمكن من معرفة إذا نقل محتوى الملف كاملا إلى المخزن الموجود في المكدس.

AAAAAAAAAAAAAAAAAAAAAAAAAAAA...BBBBEEEEEEEFFFFFFGGGGHHHH

قلنا أنّ البرنامج يقوم باستدعاء الدالة fopen لقراءة 1024 بايت فقط مهما كان حجم الملف، فمن غير المنطق أن تكون هذه الدالة الرئيسية لقراءة البيانات من الملفات.

لو ألقينا نظرة على المجلّد الذي تمّ فيه تنصيب البرنامج سنجده يحتوي على مكتبات ربط ديناميكي (ملفات DLL). إذا هناك إمكانية أن تقوم إحدى هذه المكتبات بقراءة محتوى الملف كاملا. من أهم هذه المكتبات نجد:

MSRMCcodec00.dll ; MSRMCcodec01.dll ; MSRMCcodec02.dll ; MSRMCctn00.dll ; MSRMfilter01.dll ; MSRMfilter02.dll ; MSRMfilter03.dll

نعود لنافذة OllyDbg و نختار الأمر View -> Executable Modules لإظهار الملفات التنفيذية التي يستعملها البرنامج

post-228541-096039700 1343567086_thumb.p

-1-الملفات التنفيذية التي يتعامل معها البرنامج

نبحث عن مكتبات الربط الديناميكي التي ذكرتها سابقا، في كل مرة نقوم بتضليل مكتبة (مثل المكتبة "MSRMCcodec01.dll" في الصورة) نضغط Enter ثم CTRL+N لإظهار جدول استيراد تلك المكتبة ثم نبحث عن الدوال التالية و نضع عليها نقاط توقف

ReadFile
fread

نضغط F9 لتشغيل البرنامج، سيقوم بالتوقف عن تعليمة استدعاء الدالة ReadFile:

0147DD75   FF15 24814801    CALL DWORD PTR DS:[<&KERNEL32.ReadFile>] ; kernel32.ReadFile

نلقي نظرة على المكدس:

0454716C   0000055C  |hFile = 0000055C (window)
04547170   01624428  |Buffer = 01624428
04547174   00001000  |BytesToRead = 1000 (4096.)
04547178   0454718C  |pBytesRead = 0454718C
0454717C   00000000  \pOverlapped = NULL

لاحظ أن الدالة تقوم بقراءة 4096 بايت من الملف "sound.rm"، نعود للملف و نضع فيه أكثر من 4096 بايت. نقوم بتشغيل البرنامج و نفتح الملف "sound.rm" سيقوم البرنامج بالتوقف عند الدالة السابقة و يقوم بقراءة نفس عدد البايتات.

يمكننا أن نستنتج أن البرنامج يستعمل طريقة أخرى لتعامل مع ملفات الوسائط مثل طريقة الـ File Mapping

بقي علينا تحليل سلوك البرنامج عند تعامله مع ملفات Playlist. نقوم بتغيير امتداد الملف sound.rm (الذي أصبح حجمه يفوق 4096 بايت) إلى امتداد يندرج ضمن النوع الثاني من الملفات التي يتعامل معها البرنامج (مثلا: sound.pls).

من نافذة البرنامج نختار Load و نفتح الملف sound.pls، سيتوقف البرنامج عند التعليمة:

0041B9AD |. FF15 20C74300 CALL DWORD PTR DS:[<&MSVCRT.fopen>] ; \fopen

نواصل التنفيذ إلى أن نصل إلى بداية استدعاء الدالة fread:

0041B9C9  |> 56             PUSH ESI                                 ; /stream
0041B9CA  |. 68 00040000    PUSH 400                                 ; |n = 400 (1024.)
0041B9CF  |. 8D4C24 20      LEA ECX,DWORD PTR SS:[ESP+20]            ; |
0041B9D3  |. 6A 01          PUSH 1                                   ; |size = 1
0041B9D5  |. 51             PUSH ECX                                 ; |ptr
0041B9D6  |. FF15 1CC74300  CALL DWORD PTR DS:[<&MSVCRT.fread>]      ; \fread

لاحظ أنها لا تختلف كثيرا عن نفس الاستدعاء الذي يقوم بقراءة ملفات الوسائط خاصةَ عدد البايتات التي تقوم بقراءتها، يعني لسنا بحاجة لتغيير محتوى الملف "sound.pls". نضغط F9 لتشغيل البرنامج:

1002A906   FF15 D8200310    CALL DWORD PTR DS:[<&KERNEL32.ReadFile>] ; kernel32.ReadFile

سيتوقف البرنامج عند هذه الدالة، نلقي نظرة على المكدس:

000F6C38   000004DC  |hFile = 000004DC (window)
000F6C3C   01861E2C  |Buffer = 01861E2C
000F6C40   00000800  |BytesToRead = 800 (2048.)
000F6C44   000F6C58  |pBytesRead = 000F6C58
000F6C48   00000000  \pOverlapped = NULL

تقوم الدالة بقراءة 2048 بايت من الملف "sound.pls" الذي يفوق حجمه 4096 بايت. نضغط F9 مرة أخرى سيتوقف البرنامج عند نفس الدالة و يقوم بقراءة 2048 بايت أخرى من الملف. لو أكملنا تشغيل البرنامج سنلاحظ أنه توقف أكثر من مرة عند دالة القراءة.

من هنا يمكننا أن نستنتج أنّ البرنامج يقوم بقراءة ملفات الـPlaylist كاملة على عدة مرات، كل مرة يقرأ فيها 2048 بايت.

تحقق الشرط الثاني من حدوث ثغرة فيض المخزن. نفتح الملف "sound.pls" و نضيف إليه حروف و في كل مرة نفتح البرنامج و نقوم بتحميل الملف، نقوم بإعادة هذه العملية إلى أن ينهار البرنامج:

post-228541-026438100 1343567124_thumb.p

-2-انهيار البرنامج

المرفقات
pic1.pngpic2.png
2

مواضيع مشابهة