9.4 מפת גישה לאתגרים הקשים תרגול
תרגול - מפת גישה לאתגרים הקשים¶
בתרגול הזה לא נפצח אתגר בודד מקצה לקצה - נתרגל את המיומנות שמאפשרת לפצח את כולם: טריאז' וכתיבת תוכנית ניתוח. תלמדו לקחת אתגר קשה מ-pwnable.kr (Grotesque או Hacker's Secret), לסווג אותו למשפחת טכניקה, ולכתוב תוכנית עבודה מסודרת - כלים, השערות, וצעד ראשון. בנוסף תקימו שני בינארי הדגמה מקומיים ותפתרו אותם באמת עם angr, כדי שהכלי החדש של הפרק יהיה בידיים ולא רק בראש.
האתגרים הרלוונטיים ב-pwnable.kr הם כל אתגרי Grotesque ו-Hacker's Secret. מתחברים כרגיל:
חלק מהאתגרים האלה הם שירות רשת או דורשים סביבה מיוחדת - קראו את עמוד האתגר באתר. אל תריצו fuzzing או עומס על השרת: כל העבודה הכבדה נעשית מקומית, השרת הוא רק היעד.
תרגיל 1 - טריאז' מהריקון¶
לפני שבונים תוכנית, ממיינים. נניח שקיבלתם אתגר לא מוכר ואלה תוצאות הריקון:
$ file ./chall
./chall: ELF 32-bit MSB executable, MIPS, MIPS-I version 1 (SYSV), dynamically linked
$ strings -n 6 ./chall | grep -i -E 'win|maze|move|lose|flag'
Left or Right?
You lose
Correct! flag:
- לאיזו משפחת טכניקה תמיינו את האתגר הזה? נמקו משתי ראיות שונות מהפלט.
- איזה פרק בקורס מכסה אותו, ואיזה כלי ריצה/ניפוי תצטרכו?
- כתבו את הצעד הראשון הקונקרטי (הפקודה הראשונה שתריצו אחרי הריקון).
רמז: יש כאן שני איתותים נפרדים - אחד בשורת ה-file ואחד בשורות ה-strings. כל אחד לבדו כבר מכריע חלק מהסיווג.
תרגיל 2 - תוכנית ניתוח לפי תבנית¶
בחרו שניים או שלושה אתגרים מהרשימה (מומלץ אחד מכל טיפוס: אחד סימבולי כמו maze/hunter, אחד kernel/CVE כמו rootkit/towelroot/exynos, ואחד אמולטור כמו softmmu). לכל אחד, כתבו תוכנית ניתוח בכתב לפי התבנית הבאה:
שם האתגר:
קטגוריה (Grotesque / Hacker's Secret):
משפחת טכניקה (מהמיון בהרצאה):
פרק בקורס שמכסה:
הגנות/סביבה משוערות (מה תבדקו ב-checksec / איזו סביבה):
השערת הבאג (מה אתם מנחשים שהחולשה, לפני שראיתם קוד):
שלושת הצעדים הראשונים (פקודות קונקרטיות):
הכלים שתוציאו מהארגז:
מהו תנאי ה"ניצחון" (מה מוכיח שפתרתם):
המטרה היא לא לפתור עדיין - אלא לחשוב כמו חוקר לפני שנוגעים במקלדת. תוכנית טובה חוסכת שעות.
רמז: אם אתם תקועים על "השערת הבאג" לפני שראיתם קוד, הישענו על המיון מההרצאה. אמולטור? הבאג כמעט תמיד בתרגום הכתובת. אתגר CVE? הבאג כבר מתועד - חפשו אותו.
תרגיל 3 - להריץ angr על מבוך אמיתי¶
הגיע הזמן להוציא את angr לפועל. קודם התקינו (pip install angr), ואז בנו בינארי מבוך מקומי:
// maze.c
#include <stdio.h>
#include <string.h>
int main() {
char moves[9];
int x = 0, y = 0;
puts("Navigate the maze (8 moves: u/d/l/r):");
if (read(0, moves, 8) < 0) return 1;
moves[8] = 0;
for (int i = 0; i < 8; i++) {
char m = moves[i];
if (m == 'u') y--;
else if (m == 'd') y++;
else if (m == 'l') x--;
else if (m == 'r') x++;
else { puts("You lose"); return 0; }
// walls: going outside the board -> lose
if (x < 0 || x > 3 || y < 0 || y > 3) { puts("You lose"); return 0; }
}
if (x == 3 && y == 3) puts("You win");
else puts("You lose");
return 0;
}
- מצאו בדיסאסמבלי את כתובת ה-
callל-putsשל "You win" ושל "You lose". רמז:objdump -d ./maze | grep -B2 -A2 puts, והצליבו עם כתובות המחרוזות ב-.rodata. - כתבו סקריפט angr שמשתמש ב-
explore(find=WIN, avoid=LOSE)ומדפיס את הקלט הפותר. - הזינו את הקלט שקיבלתם ל-
./mazeוודאו שהוא מדפיס "You win".
רמז: ה-find וה-avoid מקבלים את הכתובת של ה-call (או השורה שאחריו), לא של המחרוזת עצמה. את הקלט מחלצים עם state.posix.dumps(0).
תרגיל 4 - שלד AEG על overflow פשוטה¶
עכשיו נראה איך angr מוצא לבד את ה-offset ובונה payload. בנו בינארי vulnerable:
// vuln.c
#include <stdio.h>
void win() { system("/bin/sh"); }
int main() { char buf[32]; gets(buf); return 0; }
- מצאו את כתובת
win(nm ./vuln | grep win). - כתבו סקריפט angr שמריץ עם stdin סימבולי, שומר מצבים בלתי מאולצים (
save_unconstrained=True), מריץ עד שיש מצב עםpcסימבולי, מאלץpc == win, ומחלץ את הקלט ל-payload.bin. - הזינו את הpayload לבינארי (
./vuln < payload.binבהרצה אינטראקטיבית, או דרך pwntools) וודאו שאתם מגיעים ל-win.
רמז: אזהרת ה-gets בזמן הקמפול היא בדיוק הבאג שאתם מנצלים. אם angr לא מוצא מצב בלתי מאולץ, הגדילו את אורך ה-stdin הסימבולי (למשל 8 * 100 ביט) כדי לוודא שהoverflow מגיעה ל-rip.
תרגיל 5 - מחקר CVE בכתב¶
בחרו את towelroot או את exynos, וכתבו דף מחקר קצר (בלי לממש - רק מחקר):
- מהו ה-CVE המדויק, ובאיזו שנה פורסם?
- מהו הפרימיטיב שהחולשה נותנת (מה בדיוק אפשר לקרוא/לכתוב)?
- מהם שלושת השלבים העיקריים בchain מ-userland ל-root?
- מהו האילוץ הסביבתי (איזו גרסת kernel/מכשיר), ולמה הוא חשוב לשחזור?
רמז: התחילו מ-NVD (חיפוש מספר ה-CVE) ומהכתיבה המקורית של החוקר. עבור towelroot חפשו את FUTEX_REQUEUE; עבור exynos חפשו את /dev/exynos-mem.
תרגיל 6 (בונוס) - הגבולות של angr¶
קחו את בינארי ה-maze מתרגיל 3 והגדילו אותו ל-40 מהלכים ולוח 10x10. הריצו שוב את סקריפט ה-angr.
- כמה זמן זה לוקח עכשיו? האם הוא מסיים בכלל?
- מה קורה ל-angr כשמספר המסלולים גדל (state explosion)? הסבירו במילים שלכם.
- הציעו רעיון אחד לצמצום מרחב החיפוש (למשל: לחתוך מסלולים עם
avoidנדיב יותר, או להתחיל את החקירה ממצב קרוב יותר ליעד).
רמז: הרצה סימבולית עולה אקספוננציאלית עם ההסתעפות. זו בדיוק הסיבה שבאתגרים גדולים משלבים ניתוח ידני עם angr במקום לזרוק עליו את כל הבינארי.