مقال : رفع الصلاحيات على نظام Linux بإستخدام Local Privilege Escalation بشكل يدوي
في المقال الماضي كنت تحدثت عن طريقة لعمل Local Privilege Escalation من خلال الـMysql وكما أخبرتكم في المقال السابق أنني بعد حصولي على حساب مستخدم محدود على النظام وجدت طريقتين لعمل Privilege Escalation أو لزيادة صلاحياتي. الأولى وهي من خلال ثغرة Buffer Overflow داخل ملف مملوك للروت والثانية هي التي قمت بشرحها في المقال السابق والتي كانت تستغل ثغرة موجودة في الـMysql.
التحدي كان كالتالي، بعد أن قمت بالحصول على الحساب ذو الصلاحيات المحدودة قمت بالتنقل في بعض المسارات ووجدت مجلد اسمه SECRET وكان بداخله ثلاثة مجلدات door1 وdoor2 وdoor3، قمت باستخدام أمر ls لرؤية محتويات المجلدات بهذه الطريقة:
ما نلاحظه في الصورة السابقة هو حجم الملفات، يوجد ملفين متطابقين في الحجم والملف الموجود في door1 هو الملف الوحيد المختلف في الحجم.
سأقوم بأخذ نسخه من الملف للمسار /tmp لأنه من الواضح أنه يوجد سكربت يقوم بنقل مكان الملف المختلف ما بين المجلدات الثلاثة. ولكن لاحظ أنني سأقوم ببدأ العمل عليه للوصول إلى الـShellCode النهائي ولكن يجب أن تقوم بتنفيذ الـShellCode النهائي على الملف الأصلي وليس الملف الموجود في /tmp وذلك لأنك لو لاحظ فالملف الذي قمت بنسخه ستجد أنه مملوك للمستخدم ذو الصلاحيات المحدودة وليس الروت كما هو الحال مع الملف الأصلي.
قبل أن أبدأ العمل على الملف سأقوم بتحميل إضافة للـGDB ستساعدني كثيرًا في العمل من خلال الـGDB وهي إضافة يمكنك تحميلها من الرابط التالي واسمها Peda-GDB:
بعد تحميل الملف المضغوط يمكنك نقله إلى الهدف من خلال الـnc أو إن كان الهدف متصل بالإنترنت يمكنك تحميلها مباشرة على الهدف، قم بفك الضغط على الملف المضغوط وبعد ذلك قم بإضافة الـpeda.py لملف إعدادات الـGDB كما هو موضح في الصورة التالية:
لاحظ أن سكربت الـpeda.py موجود داخل الـ/tmp/peda/ فإن كان السكربت موجود في مسار أخر قم بكتابة المسار الصحيح في الأمر السابق.
بعد ذلك يمكننا أن نقوم بفتح الملف الذي سنقوم باختباره داخل الـgdb ولكن قبل ذلك أريد أن أتأكد إن كانت الـASLR مفعلة على النظام وذلك من خلال الأمر التالي:
بالتأكد من القيمة الموجودة داخل ملف randomize_va_space وجدت أن القيمة الموجودة داخله هي 2 وهذا يعني أن الـASLR مفعلة بكامل قوتها 🙁
دعنا نتأكد من خلال أمر ldd فهو يظهر لي الـShared Libraries الخاصة بالملف ومكانها في الميموري، إن كان يتغير فهذا معناه أن الـASLR بالفعل مفعلة:
لاحظ أنها العناوين في الميموري تتغير مع كل مرة أقوم فيها بتشغيل أمر ldd وهذا معناه إن الـASLR مفعل.
ماذا أفعل لحل هذه المشكلة؟
يبدو أن النظام من نوع 32Bit، هذا جيد.. يوجد أكثر من طريقة لتخطي الـASLR ولكن أسهلها بما أن النظام من نوع 32Bit فهي استخدام أمر ulimit 🙂 فالأمر يتحكم في مصادر النظام التي يتم إعطائها للمستخدم، دعنا نرى ماذا سيحدث لو قمنا باستخدامه لإعطاء الـStack قيمة unlimited 🙂
كما نلاحظ فالعناوين أصبحت ثابتة =D
بالفعل أنا أعلم أن بهذا الملف ثغرة فهذا تحدي 🙂 ولكن للتأكد سأقوم بتشغيل البرنامج مع إضافة مدخل كبير الحجم للبرنامج لكي أرى كيف سيتعامل معه.
كما نرى في الصورة السابقة قمت بتشغيل الملف وكـArgument قمت باستخدام لغة البايثون لتمرير 500 حرف A وحدث كما نرى، Crash 🙂 هذا معناه أننا من الممكن أن نقوم بمحاولة استغلال هذا الخطأ البرمجي كثغرة.
دعنا الآن ننتقل للـGDB، وكما سنلاحظ سنجد أن الـPeda يعمل 🙂
الخطوة الأولى في استغلال ثغرات الـBuffer Overflow هي تحديد مكان الـCrash بالضبط، بمعنى أنني يجب أرسلت 500 حرف ولكن عند أي حرف بالضبط حدث الـCrash وهذا ما أريد تحديده، يمكننا فعل ذلك ببساطة من خلال إرسال Unique Characters وذلك لتحديد مكان الـCrash بالضبط كما سنرى في الخطوات التالية. يمكننا استخدام سكربت Peda لفعل ذلك ولكنني سأشرح كيفية فعل ذلك بدونها. سنقوم باستخدام سكربتين داخل مشروع الميتاسبلويت الأول سنستخدمه لعمل الـPattern أو الـUnique Characters والثاني سنستخدمه لتحديد مكان الـCrash. دعنا نرى كيف سنقوم بذلك الآن:
ما قمت به في الصورة السابقة هو أنني قمت بالبحث عن السكربت وبعدها قمت باستخدامه لصنع Unqiue Characters عددها 500، الآن سأقوم بنسخها وإرسالها للملف من خلال الـGDB كما هو موضح في الصورة التالية:
حرف الـr الموجود في البداية استخدمته لإخبار الـGDB أنني أريد عمل Run للملف.
النتيجة ستكون كالتالي:
هذا هو العنوان الذي حدث عنده الـCrash، دعنا الآن ننتقل للكالي مجددًا ونستخدم سكربت أخر لتحديد مكان العنوان بالضبط:
السكربت قام بتحديد مكان الـCrash بالضبط وهو عند 171 Character 🙂 رائع، هذا يعني أنني أستطيع التأكد من سيطرتي على الـEIP من خلال إرسال 4 Characters بعد الـ171 Character للتأكد من أنني استطعت الوصول لعنوان الـEIP الصحيح:
رائع، بالفعل الـ4 Characters التي قمت بإرسالها هي التي ظهرت في الـEIP. للذين سيسألون عن هوية الـ”\x90″ التي قمت بإرسالها في أخر الأمر فلمن لا يعرفها هذه قيمة الـNo Operation في الـHex وهي تخبر البرنامج بأن أريد تنفيذ No Operation وعدد مراتها 16 ونقوم باستخدامها عادةً في ثغرات الـBuffer لكي يعمل الـShellCode الخاص بنا بدون مشاكل.
الآن بعد أن قمت بتحديد مكان الـCrash وقمت بالتأكد من أنني أسيطر على الـFlow الخاص بالبرنامج أو التحكم في توجيه البرنامج. نرى أن الـESP مكان جيد لتنفيذ الأوامر الخاصة بي والتي أريد من البرنامج أن يقوم بها. لكن كيف أقوم بتوجيه تحكم البرنامج للـESP؟ يوجد تعليمة أو Instruction تسمى jmp esp أو call esp وكلاهما يقومان بنفس المهمة تقريبًا وهي توجيه البرنامج للـESP. لكي أستطيع توجيه تدفق تشغيل البرنامج للـESP يجب أن أبحث داخل البرنامج عن هذه التعليمة.. سأقوم باستخدام سكربت peda ليقوم بهذه المهمة ببساطة كما سنرى في الصورة التالية:
الأمر السابق معناه أنني أريد أن أبحث عن أي تعليمة داخل البرنامج تحتوي على jmp esp أو call esp ولكن النتيجة سلبية للأسف 🙁
ماذا أفعل الآن؟ هل فشلت الآن؟
لا، يمكننا أن نبحث داخل الـShared Library الخاصة بالبرنامج وذلك كما بالصورة:
رائع، يوجد الكثير من العناوين التي تحتوي على هذه التعليمة.
سأقوم باختيار العنوان الأول، لاحظ أنه عليك اختيار عنوان لا يحتوي على أي Bad Characters. والـBad Characters المشتركة بين معظم البرامج هي “\x00\x0a\x0d”.. تجنب أي عناوين تحتوي على أيًا من هذه القيم الثلاثة.. يمكن أن تزيد عدد الـBad Character على حسب البرنامج الذي تتعامل معه ولكن هذه القيم الثلاثة هي المشتركة بين معظم البرامج.
سأقوم أولاً بتحديد الـRET الخاص بالـMain داخل البرنامج وسأقوم بعمل Breakpoint عندها وذلك لأرى كيف سيعمل البرنامج بعد أن أقوم بمحاولة توجيهه:
أمر disass تعني أنني أريد عمل DisAssembly للـMain داخل البرنامج، بعدها سأقوم بعمل Breakpoint عند عنوان الـRET كما أخبرتكم:
دعنا الآن نعيد تشغيل البرنامج ونرسل الكود الجديد 🙂
الكود سيكون كالتالي، سنرسل 171 حرف A، وبدلاً من الـ4 Character سنقوم بوضع عنوان الـJMP ESP التي قمنا باختيارها ولكن لاحظ أنك يجب أن تقوم بإضافتها بطريقة Little-Endian وذلك لأننا نستهدف Intel 32 وهي تعني أنك يجب أن تقوم بإضافة العنوان بالعكس (سترى كيف في الصورة القادمة)، وبعد ذلك سنرسل الـNop Slide الخاصة بنا 🙂
لاحظ طريقة كتابة العنوان، هذه هي طريقة الـLittle-Endian. دعنا الآن نرى تأثيره على البرنامج:
لاحظ أن البرنامج توقف عند الـBreakpoint التي قمنا بصنعها وهي الـRET. دعنا نحاول الانتقال للـInstruction التالية في البرنامج لنرى ماذا يحدث بعد الـRET:
لاحظ أنني عندما حاولت الانتقال إلى الـNext Instruction أخبرني أن هناك خطأ في عنوان الميموري. هذا رائع.. فهذا مؤشر جيد 🙂
دعنا نتأكد من القيم الموجودة داخل الـEIP والـESP، الـEIP يجب أن تحتوي على عنوان الـJMP ESP الخاص بنا، والـESP يجب أن تحتوي على أي شيء أرسلته للبرنامج بعد عنوان الـJMP ESP وفي هذه الحالة سيكون الـNop Sled 🙂
رائع، الـEIP بالفعل يحتوي على عنوان الـJMP ESP الذي وضعناه 🙂 الأمر السابق معناه (i)nfo (r)egister وهي تظهر لي معلومات عن الـRegister وفي هذه الحالة معلومات عن الـRegister الـEIP والـESP.
الخطوة التالية هي التأكد من محتوى الـESP وسنقوم بذلك كما هو موضح في الصورة التالية:
رائع، الـESP يحتوي بالفعل على الـNop Sled الخاصه بنا، أمر x/x يعني أظهر لي القيمة الموجودة داخل Register.
حسنٌ، بما أنني تأكد من أن كل شيء يعمل بنجاح وأنني أسيطر على الـEIP وتدفق البرنامج، أستطيع الآن إضافة الـShellCode الخاص بي ونرى النتيجة. يمكنك من خلال الـPeda توليد ShellCode صغير الحجم كما سنرى في الصورة التالية:
رائع، دعنا الآن نقوم بإضافته للكود الخاص بنا وبعدها نرى تأثيره على البرنامج 🙂
هذا هو الكود النهائي، كل ما علينا فعله الآن هو محاولة تشغيله على البرنامج نفسه، في هذه الحالة لن أقوم بتشغيله على الملف الموجود في مجلد /tmp ولكن سأقوم بتشغيله على الملف الأصلي ولكن بعد التأكد من المكان فربما تغير مكانه الآن 🙁
يبدو انه انتقل بالفعل للـdoor3، دعنا الآن ندخل على مجلد door3 ونجرب الـShellCode الخاص بنا ونرى النتيجة، ما نريد أن نصل إليه هو Shell بصلاحيات root:
كما نرى فقد تم إضافة صلاحيات الروت للـShell الجديد 🙂 رائع جدًا، نجحنا في زيادة صلاحيات المستخدم ذو الصلاحيات المحدودة من خلال استغلال ثغرة Buffer Overflow..
ملحوظة : لو كانت الـASLR مفعلة لن ينجح الـShellCode النهائي، تأكد من أنك قمت بتخطيها.
بهذا نكون انتهينا من هذا المقال وأتمنى أن تكونوا قد استفدتم وإن شاء الله نلتقي في مقالات أخرى شيقة وممتعة 🙂
بزركت على الطرح . استمتعت
ما شاء الله ما شاء الله ما شاء الله يعجز لساني عن التعبير من هذا المقال الاحترافي الاكثر من رائع بارك الله فيك أخ عمر أحمد و زاد في علمك و نفع به كم نفتقد مثل هذه المقالات الجميلة خصيصا في Buffer Overflow و باللغة العربية مقال رائع جدا و أرجوا مع كل مقال في مثل هذه الثغرات ان تزودنا بالمراجع لكي نتعلم التقنية المستعملة أكثر و بدقة و أرجوا الاكثار منها فهي مهمة موفق ان شاء الله 🙂
اولا وين مسار المجلد يلي اسمه سر وداخله 3ابواب ما لقيته للاسف مع اني حاولت بعدين مش عم تفوت بعقلي تلاقي ملف اسمه فايل يقبل معطيات من المستخدم وفيه بيفر اوفر فلو انتظر ومكتوب بلغة سي ومملوك من قبل الروت همممم ممكن مساره المجلد وهذا الفايل اذا كان شغال ممعقول ما تلقاه بمهام النظام ومخفي بكل هذه الدرجة
عزيزي كما أشار صديقنا عمر إلى أن هذا “تحدي” أي أن السيناريو هذا موجود داخل تحدي وليس بتوزيعات لينكس العادية ، أتمنى أن تراجع المقال مُجدداً وشكراً لمشاركتك
فضلا وليس أمرا ممكن تبطلو سرقة مواضيع من موقع Infosec ؟
بعيدًا عن الاتهام، لو كان هذا المقال مترجم من مقال أجنبي لكنت قد ذكرت المصدر يا عزيزي. ولكن شكرًا على مرورك الكريم.
وللعلم، هذا التحدي واجهته في شهادة عالمية أنا حاصل عليها.
أهلاً عزيزي محمد ، شُكراً لك على تعليقك ،، المقال كما ذكر الأخ عمر هو من أحد التحديات التي واجهها وأحب أن يقوم بمُشاركتها معنا ، نحن لا نسرق أي مواضيع وفي حال قمنا بترجمة مقال سوف نقوم بذكر المصدر ولا نضعه كما هو دون أي مصدر 🙂
جميل جداً عزيزي عمر 🙂 يبدو ذلك جيداً ,
سؤال: لم إخترت عدد الـ NOP 16 تحديداً؟
وشكراً لك على المقال ..
أنا معتاد على استخدام هذا العدد، ولكنه يختلف أحيانًا على حسب التحدي الذي أواجهه.
مرحباً 🙂
شكراً لك على المقال أخي , ولكن بعيداً عن التحديات ..
هل سوف تواجه مثل هذه الأمور في الـ Real life ؟ ام أنك فقط تحب توصيل الفكرة , التي لربما سوف تستخدمها في بعض الحالات ؟
لأنني بصراحة لأتوقع أن تجد مثل هذه الأشياء في الإختراقات الحقيقية ( وأقصد بذلك مجلد الـ SECRET ) …
وشكراً لك مرة أخرى على هذا المقال .. 🙂
لن يكون الأمر واضحًا بالطبع كما هو الآن، فلن يكون تحدي بل سيكون تحدي حقيقي، ولكن هذا المقال لتوصيل الفكرة. ولكن في الواقع ستجد أشياء مماثلة ولكن ليس بنفس الوضوح.. فلن تجد مجلد Secret أو كل ذلك ولن تجد الملف جاهزًا للاستغلال.. ولكن الفكرة هي الثغرة نفسها الـBuffer Overflow.
شكراً على المقال ,
دعوني أذهب بعيداً ..
هناك خطأ كتابي في اسفل الموقع 🙂
iSeurty Arab Hacker Community | ©2015
iSeurty ..
شكرًا على التنويه يا عزيزي.
مرحباً
قمت بإرسال رسالة لك على الإيميل ..
أرجو أن تقوم بتفقدها .. حالما يكون ذلك ممكناً ..
مقال رائع صحيح اني لم ادخل في ثغرات Buffer Overflow بشكل جاد ومعرفتي بها مجرد امور عامة,ولكن رغم ذلك فهمت الفكره من الشرح
وارجو منك مساعدتي بكورس مطول لتعلم Buffer Overflow ويفضل لو يكون عربي
وشكرا
رائع اخ عمر واجهني مثل هذا التحدي من قبل وتم حلها بنفس الاسلوب .. هناك عدت مواقع اجنبيه تقدم مثل هذه التحديات … اخ عمر ممكن اسم الشهاده؟ شكرا