إيجاد الـ Bad Characters في الـ Shellcode

مقدمة

في مرحلة من مراحل كتابتنا لثغرة BufferOverflow  فإننا قد نعاني من مشكلة مملة و نجد أن الـPayload  يعطّل الـ Exploit  بكامله مع أننا قد تأكدنا أن كل شئ يمشى بأفضل حال قبل وضع الـ Shellcode  الحقيقي. السبب في ذلك هو وجود الـ Bad Characters أو الـ Restricted Characters.

ستكتشف تلك المشكلة عندما تضع نقطة وقوف Break Point  في الـ Debugger  ولكن عند تنفيذ الثغرة لن تصل إلى ذلك العنوان. أو أنك ستصل ولكن الـ Shellcode لن يعمل (بشرط تأكدك أن جميع الأجزاء الأخرى سليمة).

ما هي الـ Bad/Restricted Characters؟

هي Characters عادية من ضمن الـ Shellcode يتم عمل Decoding لها بشكل طبيعي ولكن لها معنى لا يقبله البرنامج المصاب كأن يكون هذا الـ Characters سيدخل في تسمية ملف مثلا و فلو فرضنا أن في الشل كود قيمة ستدخل في تسمية ملف ما و كانت القيمة “\x7D” و التي تعني “}” و من المعروف أننا لا نستطيع وضع هذا الحرف في إسم ملف فوقتها سيوقف هذا الحرف مجرى عملية الـ Decoding  للـ Shellcode.

قد يبدر إلى أذهاننا بعض الأسئلة, منها..

س/ هل جميع البرامج المصابة سيكون بها Bad Characters Restriction ؟

ج/ لا

س/ هل يوجد Bad Characters أساسية يجيب أزيلها من أي Shellcode  أقوم بعمله؟

ج/ نعم, هما:  x00 و  x0d

س/ هل كل البرامج لها نفس الـ Bad Characters أي أنني أستطيع أن أحذف كل ما تم اكتشافه سابقا في البرامج اللاحقة؟

ج/ لا, لكل برنامج Bad Characters  مختلفة تختلف بطبيعة البرنامج و طريقة تنفيذه

س/ هل يمكن أن يحتوي البرنامج على أكثر من Bad Character واحد ؟

ج/ للأسف نعم

إيجاد الـ Bad Characters – الطريقة الأولى

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

تعتمد هذه الطريقة على إنشاء جميع احتمالات الحروف من 0-255 عن طريق سكريبت يسمى generatecodes.pl.

في البداية تقوم بتنفيذ السكريبت مع إزالة الـBad Characters الشائعة x00  و x0d .
./generatecodes.pl 00,0d
"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0e\x0f\x10"
"\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
"\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e"
"\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d"
"\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c"
"\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b"
"\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a"
"\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79"
"\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88"
"\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97"
"\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6"
"\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5"
"\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4"
"\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3"
"\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2"
"\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1"
"\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"

الأن نأخذ أول سطر من المخرجات و نستبدل الـ Shellcode  بهذا السطر و نضع الـ Break Point خاصتنا و من ثم ننفذ البرنامج. إذا وصلنا للعوان الصحيح فهذا يعني أن Bad Characters ليست من ضمن الحروف التي في السطر الأول.

مثال:
shellcode = ("\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0e\x0f\x10")
الأن نضيف السطر الثاني من المخرجات إلى السطر الأول و نضع الـ Break Point خاصتنا و من ثم ننفذ البرنامج. إذا وصلنا للعوان الصحيح فهذا يعني أن Bad Characters ليست من ضمن الحروف التي في السطر الثاني, و هكذا.

مثال:
shellcode = ("\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0e\x0f\x10"
"\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f")

عندما لا نصل للعنوان الصحيح, نقوم بقسم السطر الذي وصلنا عنده و حصل عنده خطأ في النتائج و نستبدل النصف الأول منه بـ “\x41” مثلا . ثم نجرب فإن حصل خطأ, فهذا يعني أن الـ Bad Character في النصف الأخر, وقتها نبدأ نغير حروف النصف الثاني من السطر الأخير إلى “\x41” و نجرب في كل مره حتى نصل أنه لا يوجد خطأ في النتائج و عندها سنعرف ال Bad Character

مثال:
"\x41\x41\x41\x41\x41\x41\x41\x41\x28\x29\x2a\x2b\x2c\x2d\x2e"
سنفترض أننا وجدنا و أنه “x0a”  إذا سنقول بعمل الأتي
./generatecodes.pl 00,0d,0a
"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0b\x0c\x0e\x0f\x10\x11"
"\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20"
"\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
"\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e"
"\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d"
"\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c"
"\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b"
"\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a"
"\x7b\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89"
"\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98"
"\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
"\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6"
"\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5"
"\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4"
"\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3"
"\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2"
"\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"

و نتأكد مرة أخرى, لو لظهر أي خطأ في مجرى سير البرنامج في الـ Debugger  إذن كل شئ على ما يرام. و إن لم!!, فهذا يعني -ولا حول ولا قوه إلا بالله- أنه يوجد Bad Character أخر و يجب أن تكمل المسيرة حتى تجده.

إيجاد الـ Bad Characters – الطريقة الثانية – تحديث 19/2/2013

قام فريق Corelan بإيقاف تطوير الإضافة pvefindaddr واستبدلها بالإضافة الجديدة والأفضل mona.py مع استخدام الدالة compare

حمل الإضافة من هنا mona.py

كل ما عليك فعله هو وضع الإضافة في مجلد الـمنقح Immunity debugger  في المسار التالي

C:\Program Files\Immunity Inc\Immunity Debugger\PyCommands

ثم ضع ملف الـ Shellcode  في الـ C  حيث يكون مساره

c:\shellcode.bin

ملاحظة: إذا كان الـShellcode بصيغة الـ Hex فيجب تحويله إلى Binary , الرجاء زيارة هذا الرابط

الأن ضع الـ Break point   خاصتك ثم نفذ الـ exploit  الذي يحتوي على الـ shellcode  الحقيقي

بمجرد توقف البرنامج, نفذ الأمر التالي في Command bar  في الـ Immunity Debugger

!mona compare c:\shellcode.bin

ستخرج لك نافذة تحتوي على العناوين التي تتواجد بها الـ Bad Characters مثل هذه

الأن اذهب إلى نافذة الـسجلات  من

View >> Log  أو اضغط   ALT + L

ستجد التالي: (يرجى تكبير الصورة)

كما ترى في حالتي كانت الـ Bad Characters  هي  5c و 2f

أيضا تستطيع أن تجد النتائج في ملف compare.txt على هذا المسار

C:\Program Files\Immunity Inc\Immunity Debugger
(هذا المسار يحتوي على معظم نتائج استخدام mona.py).

إيجاد الـ Bad Characters – الطريقة الثانية

في البداية أحب أن أرفع القبعة إلى Peter Van رئيس فريق Corelan  و هو من أشهر و أقوى الأشخاص في شرح الـ Buffer Overflow ومبرمج للعديد من السكربتات المفيدة جدا في هذا المجال.

الطريقة الثانية هي عن طريق إضافة رائعة إسمها pvefindaddr مع استخدام الدالة compare

ملاحظة: لا تنسى إضافة pvefindaddr فلها استخدامات كثيرة و رائعة في الـ Buffer Overflow

كل ما عليك فعله هو وضع الإضافة في مجلد الـمنقح Immunity debugger  في المسار التالي

C:\Program Files\Immunity Inc\Immunity Debugger\PyCommands

ثم ضع ملف الـ Shellcode  في الـ C  حيث يكون مساره

c:\shellcode.bin

ملاحظة: إذا كان الـShellcode بصيغة الـ Hex فيجب تحويله إلى Binary , الرجاء زيارة هذا الرابط

الأن ضع الـ Break point   خاصتك ثم نفذ الـ exploit  الذي يحتوي على الـ shellcode  الحقيقي

بمجرد توقف البرنامج, نفذ الأمر التالي في Command bar  في الـ Immunity Debugger

!pvefindaddr compare c:\shellcode.bin

ستخرج لك نافذة تحتوي على العناوين التي تتواجد بها الـ Bad Characters مثل هذه

الأن اذهب إلى نافذة الـسجلات  من

View >> Log  أو اضغط   ALT + L

ستجد التالي: (يرجى تكبير الصورة)

كما ترى في حالتي كانت الـ Bad Characters  هي  5c و 2f

أيضا تستطيع أن تجد النتائج في ملف compare.txt على هذا المسار

C:\Program Files\Immunity Inc\Immunity Debugger (هذا المسار يحتوي على معظم نتائج استخدام pvefindaddr).

تحياتي واحترامي

نبذة عن الكاتب

المهندس صبري صالح. مهندس حماية شبكات و أنظمة و فحصها معالجة و تحليل الأحداث الأمنية و المسؤول عن تطبيق معايير الـ ISO 27001 , يعمل في بيئات متعددة المنصات. حاصل على عدة شهادات تقنية.

التعليقات:

اترك تعليقاً | عدد التعليقات: (18)

  1. يقول [email protected]:

    يارجل تسلم يمناك على هذا الموضوع …
    يبدو صاير تدرس وتتعلم من وراي 🙂
    ألف شكر يا صبري على هالموضوع ولا تحرمنا من إبداعاتك …
    يوجد كنز مخفي بداخلك، سنخرجه من خلال Security4Arabs بإذن الله !

    دمت بود …

  2. يقول بركات:

    بارك الله فيك أستاذ صبري ونفع الله بك على هذه المقالة الرائعة. ولكن فقط لمزيد من ال توضيح :

    سأوضح لما هما غير مرغوبين . ( سببت لي مشاكل عندما قرأت عنها أول مرة ولم أكن
    أفهم سببها , حتى بعد وقت طويل. لذا سأحاول توضيحها لمن لم يفهمها 🙂 )

    ربما يجهل البعض لم هذه المحرّفات (Bad Characters) السبب أن الأولى “x00”
    والتي تعني NULL في جدول الآسكي و تمثّل نهاية سلسلة نصّية . مثلاً في الأسمبلي إذا
    أردت تعريف متغير نصّي اسمه “text” مثلاً :

    text db “My name is Barakat”,0

    يوضع الصفر ( في النظام الست عشري 0x00 ) . لإخبار بنهاية السلسلة النصيّة
    لذا سيتم تجاهل مابعد !. لمزيد من الفهم , أنشئ ملف بالإمتداد c : ـ

    #include

    int main() {

    printf(“My name is Barakat\n”);

    return 0;

    }

    شغل هذا البرنامج المكتوب بالسي بعد( ترجمته) , ستجده طبع My name is Barakat
    جرّب أن تفتحه بأي hex editor (في لينكس توجد الأداة hexedit متوفرة مع النظام )
    إبحث عن النص السابق وإستبدل قيمة الحرف i (في النظام الست عشري 0x69 )
    بـ x00 أو 00 (حرف x إشارة بأنها قيمة هكس فقط ). ماذا سيطبع ؟

    ستجده يطبع My name فقط !

    الآن ماذا لو كان هذا المحرّف في الشل كود ؟ سيتم تجاهل الباقي من الشل ولن ينفّذ “حتماُ تم تخريبة ” \ :

    x0D أو 0xD, يمثل هذا المحرّف “r\” في جدول الآسكي. وتعمل عكس الـ NULL .
    حيث يتم تجاهل ماقبلها (بينما في الأولى العكس “مابعدها”). جرب أن تستخدم المثال الأول
    وتستبدل قيتمة حرف “i” بـ “x0D أو 0D”.

    ستجد أنه طبع : s Barakat

    لست متأكد من مشكلتها بصراحة مع الشل لأنني لا أعرف طريقة تنفيذة فالمفترض أن
    ماسبق تنفيذه من الشل لايهم . الا اذا كانت هناك قفزة للخلف بعد هذا المحرّف. مما يعني
    أنها قد لاتكون دائماً Bad Characters. ربما في بعض الشلات , وربما في مواضع
    مثلاً لو كان لديك إثنان منها , قد يكون الأول Bad Characters والثاني لا !
    وأبسط حل التخلص منها كلها فلا وجود للمزاجية p: .

    ربما تكون هنا طريقة ثالثة ( لست متأكد ) وهي تشفير الشل بإستخدام الأداة ALPHA2 حيث تشفره بمحرّفات
    لاتسبب مشاكل عادة وتنتج شل كود مشفر بالمحرفات 0-9 و A-Z قرأتها هنا :

    http://skypher.com/wiki/index.php/Hacking/Shellcode/Alphanumeric/ALPHA2

    أرجو الإطلاع عليها.

    زادك الله علما أخي صبري والإخوة في مجتمع الحماية ووفقكم الله لكل خير .

  3. يقول صبري صالح:

    @Binary: حياك الله دكتور,, أبدا والله فقط أحببت أن أرفع معنوياتي بكتابة موضوع أما ما تم كتابته فهو من بعض ما عندكم. يكفي أن الموضوع أعجبك يأبو محمد

    @بركاتـ: سلمت يداك حفظك الله و بالطبع استفدنا من إضافتك الرائعة
    لكن أريد أن انوه أن استخدام الـ Encoders يزيد من حجم الـ Shellcode و هذا الشئ أحيانا يكون غير مسموح به حيث الحجم المسموح به يكون محدود و لهذا ابتعدت عن هذه الطريقة لأني عانيت من مسألة حجم الـShellcode في وقت كان حساس جدا.
    مرة أخرى سلمت يداك أخوي بركات و كثر الله من أمثالك

  4. يقول Hit-Man:

    بارك الله فيك يا مهندس

  5. يقول سليمان الجعيثن:

    ماشاء الله تبارك الله, عقول جداً راقيه بمفهومها وبتوصيل تلك المعلومه بالطريقه الصحيحه,
    بارك الله فيك أخي صبري.
    موضوع يستحق القراءه أكثر من مّره.

  6. يقول h-security:

    السلام عليكم

    الله يعطيك العافية ما قصرت على التوضيح
    بالنسبة لأستخدم ال encoding وبعض الانواع تحتاج الى احد الريجسترات يكون يؤشر الى مكان مسموح فيه الكتابه …. فقط الalpha هو الي ما يحاتج ريجستر لكن تحتاج تقريبا الى دبل حجم الشل العادي

    بالتوفيق

  7. يقول واحد:

    طيب انت متاكد ان carriage return دائما bad
    x0d??

  8. يقول صبري صالح:

    @واحد أقرأ الردود و ستفهم و تجد رد على سؤالك

  9. يقول واحد:

    اه انت قلت ان دائما بيبقى bad ممكن اعرف ليه ؟

  10. يقول wxcxw:

    @واحد: ال bad char يختلف من برنامج لآخر حسب كيفية تعامله مع البيانات لكن هناك بعض chars التي تكون bad في أغلب البرامج
    و منها 00 0a 0d
    لكن ممكن أن نجد برامج تقبل حتى null byte

    بالمناسبة كيف الأحوال lnxg33k ؟ 😉

  11. يقول واحد تانى:

    عنوان العوده مش شرط يكون bad char على الفكره
    wxcxw@ كلامك فل ال null مش شرط يكون bad 🙂
    افضل طريقه هى استخدام pvefindaddr او اى differ اخر

    انا مش lnxg33k بس انا واحد بتكلم معاه فى #corelan
    IRC

  12. […] مراجعة موضوع (قمت بتحديث الموضوع): إيجاد الـ Bad characters في الـ Shellcode إيجاد الـ Bad Characters في الـ […]

  13. يقول ThreatActor:

    ولا عجب
    الناس تركض خلف دروس البفر اوفرفلو، واخر رد في هذا المووضوع 2011!!!

    ملاحظة بعد 4 سنوات
    هذه bad char في معظم البرامج وانا دائما اتجنبها
    x00
    xff
    x0a
    x0d
    x1a

  14. يقول سعيد:

    بارك الله فيكم والله نورتونا بمعلوماتكم القيم
    شكر اخ بركات واخ ThreatActor على الاضافات المميزة
    زادكم الله علما ويحفظ والديكم

  15. يقول krypton:

    موضوع جدا مهم وقوي ونفتقر في العالم العربي عن مثل هذه المواضيع
    ولكن عندي تعقيب على Bad Characters
    انها غالباً تكوني
    \x0d
    ولكن الاجهزه الجديده win7 and 8 and 10
    ماتكون x0d من ضمن Bad Characters
    الاكيد يكون فقط \x00
    وايضا على حسب البرنامج
    في برنامج اشتغلت عليه
    كان Bad Characters

    \x00\x04\x37\x44\x62\xb8

    وكان برنامج على win 7

    وصحيح الموضوع قديم ولكن المعلومات قيمه
    وايضا الاجهزه الجديده صارت تظهر شكل Bad Characters بشكل التالي

    \x0b\x0b
    نفترض انه السطر الاول بشكل هذا
    x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f
    وكان Bad Characters موجود
    راح يظهر بهذا الشكل
    x01\x02\x03\x04\x05\x06\x07\x0b\x0b\x0a\x0b\x0c\x0d\x0e\x0f

    نلاحظ تم اضافه ( x0b\x0b )
    هنا Bad Characters فقط x08 في حال تم الحذف سوف يظهر بهذا الشكل
    x01\x02\x03\x04\x05\x06\x07\x09\x0a\x0b\x0c\x0d\x0e\x0f

    وشكرا لكم

أكتب تعليق