حل المهمة مع pwnable.kr 07 - المدخلات. فهم pwntools

صورة

في هذه المقالة ، سنقوم بتحليل حل مهمة متعددة المستويات باستخدام مكتبة pwntools .

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

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

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

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

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

حل وظيفة الإدخال


نضغط على الأيقونة مع إدخال التوقيع ، وقيل لنا إننا بحاجة إلى الاتصال عبر SSH بضيف كلمة المرور.

صورة

عند الاتصال ، نرى الشعار المقابل.

صورة

دعونا نعرف ما هي الملفات الموجودة على الخادم ، وكذلك ما هي الحقوق التي لدينا.

ls -l 

صورة

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

شفرة المصدر input.c
 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <arpa/inet.h> int main(int argc, char* argv[], char* envp[]){ printf("Welcome to pwnable.kr\n"); printf("Let's see if you know how to give input to program\n"); printf("Just give me correct inputs then you will get the flag :)\n"); // argv if(argc != 100) return 0; if(strcmp(argv['A'],"\x00")) return 0; if(strcmp(argv['B'],"\x20\x0a\x0d")) return 0; printf("Stage 1 clear!\n"); // stdio char buf[4]; read(0, buf, 4); if(memcmp(buf, "\x00\x0a\x00\xff", 4)) return 0; read(2, buf, 4); if(memcmp(buf, "\x00\x0a\x02\xff", 4)) return 0; printf("Stage 2 clear!\n"); // env if(strcmp("\xca\xfe\xba\xbe", getenv("\xde\xad\xbe\xef"))) return 0; printf("Stage 3 clear!\n"); // file FILE* fp = fopen("\x0a", "r"); if(!fp) return 0; if( fread(buf, 4, 1, fp)!=1 ) return 0; if( memcmp(buf, "\x00\x00\x00\x00", 4) ) return 0; fclose(fp); printf("Stage 4 clear!\n"); // network int sd, cd; struct sockaddr_in saddr, caddr; sd = socket(AF_INET, SOCK_STREAM, 0); if(sd == -1){ printf("socket error, tell admin\n"); return 0; } saddr.sin_family = AF_INET; saddr.sin_addr.s_addr = INADDR_ANY; saddr.sin_port = htons( atoi(argv['C']) ); if(bind(sd, (struct sockaddr*)&saddr, sizeof(saddr)) < 0){ printf("bind error, use another port\n"); return 1; } listen(sd, 1); int c = sizeof(struct sockaddr_in); cd = accept(sd, (struct sockaddr *)&caddr, (socklen_t*)&c); if(cd < 0){ printf("accept error, tell admin\n"); return 0; } if( recv(cd, buf, 4, 0) != 4 ) return 0; if(memcmp(buf, "\xde\xad\xbe\xef", 4)) return 0; printf("Stage 5 clear!\n"); // here's your flag system("/bin/cat flag"); return 0; } 


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

صورة

في المستوى الأول ، يتم التحقق من أن عدد وسيطات البرنامج هي 100. في هذه الحالة ، يجب أن يكون العنصر 65 هو السلسلة "\ x00" ، ويجب أن يكون العنصر 66 "\ x20 \ x0a \ x0d". قم بإنشاء الدليل الخاص بك في الدليل / tmp / وقم بإنشاء نص بيثون هناك.

صورة

لحل المستوى الأول ، سنقوم بإنشاء مجموعة من مائة سطر من "A". وتعيين الوسائط اللازمة للقيم المطلوبة. يمكننا بدء العملية باستخدام هذه الوسيطات كما يلي:

 from pwn import * a = ['A']*100 a[0] = '/home/input2/input' a[ord('A')] = '\x00' a[ord('B')] = '\x20\x0a\x0d' ex = process(argv=a) ex.interactive() 

صورة

تجاوزنا المستوى الأول. نلقي نظرة على الثانية.

صورة

في هذا المستوى ، يتم قراءة سطرين ، أحدهما stdin الإدخال القياسي ، والآخر من stderr. نحتاج إلى إنشاء ملفين يحتويان على هذه الخطوط.

صورة

افتح التدفقات إلى هذه الملفات وحدد واصف دفق أحد الملفات على أنه واصف stdin ، وملف آخر مثل واصف stderr.

 from pwn import * a = ['A']*100 a[0] = '/home/input2/input' a[ord('A')] = '\x00' a[ord('B')] = '\x20\x0a\x0d' fin = open('/tmp/ex/in.txt', 'r') ferr = open('/tmp/ex/err.txt', 'r') ex = process(argv=a, stdin=fin, stderr=ferr) fin.close() ferr.close() ex.interactive() 

صورة

ننتقل إلى قرار المستوى الثالث.

صورة

ترجع الدالة getenv () قيمة متغير البيئة ، والتي يجب أن تكون مساوية للقيمة المرجعية. وبالتالي ، تحتاج إلى إنشاء متغير بيئة بقيمة محددة.

 from pwn import * a = ['A']*100 a[0] = '/home/input2/input' a[ord('A')] = '\x00' a[ord('B')] = '\x20\x0a\x0d' fin = open('/tmp/ex/in.txt', 'r') ferr = open('/tmp/ex/err.txt', 'r') e={'\xde\xad\xbe\xef':'\xca\xfe\xba\xbe'} ex = process(argv=a, stdin=fin, stderr=ferr, env=e) fin.close() ferr.close() ex.interactive() 

صورة

لقد قمنا بإدارة متغير البيئة ، والآن لنبدأ من المستوى الرابع.

صورة

وفقًا للرمز ، يمكننا القول أن البرنامج يفتح ملفًا باسم "\ x0a" ويقرأ 4 أحرف منه ، وبعد ذلك يقوم بمقارنتها بالبايتات "\ x00". نظرًا لأن كل من الأحرف نفسها واسم الملف يتكونان من أحرف غير قابلة للطباعة ، فإننا نستخدم python.

صورة

صورة

يبقى المستوى الأخير. لنبدأ.

صورة

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

 from pwn import * a = ['A']*100 a[0] = '/home/input2/input' a[ord('A')] = '\x00' a[ord('B')] = '\x20\x0a\x0d' a[ord('C')] = '1234' fin = open('/tmp/ex/in.txt', 'r') ferr = open('/tmp/ex/err.txt', 'r') e={'\xde\xad\xbe\xef':'\xca\xfe\xba\xbe'} ex = process(argv=a, stdin=fin, stderr=ferr, env=e) fin.close() ferr.close() ex.interactive() 

صورة

صورة

هذا كل شيء ، الحصول على النقاط الخاصة بك.

صورة

نراكم في المقالات التالية!

نحن في قناة برقية: قناة في برقية .

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


All Articles