נורמליזציית Unicode - תרגיל¶
הכנה¶
# vulnerable_app.py
from flask import Flask, request
import unicodedata
app = Flask(__name__)
@app.route('/search')
def search():
q = request.args.get('q', '')
# האפליקציה מנרמלת NFKC לפני הצגה
normalized = unicodedata.normalize('NFKC', q)
return f"<html><body>Results for: {normalized}</body></html>"
@app.route('/api/query')
def query():
q = request.args.get('q', '')
normalized = unicodedata.normalize('NFKC', q)
# הזרקה ישירה ל-SQL (לצורך תרגול)
sql = f"SELECT * FROM items WHERE name = '{normalized}'"
return f"Query: {sql}"
if __name__ == '__main__':
app.run(port=5000)
שימו לב: הריצו את האפליקציה מאחורי WAF (כגון ModSecurity) לצורך התרגיל.
תרגיל 1 - מיפוי תווי Unicode חלופיים¶
משימה:
כתבו סקריפט Python שמוצא תווי Unicode שמתנרמלים לתווים רגישים:
import unicodedata
def find_alternatives(target_char):
"""מציאת כל תווי Unicode שמתנרמלים (NFKC) לתו מסוים"""
alternatives = []
# השלימו: עברו על טווח Unicode ומצאו תווים שאחרי NFKC הופכים ל-target_char
for codepoint in range(0x0080, 0x10000):
# ...
pass
return alternatives
# מצאו חלופות עבור:
targets = ['<', '>', "'", '"', '/', '(', ')', ' ', '=', ';']
for t in targets:
alts = find_alternatives(t)
print(f"'{t}' -> {len(alts)} חלופות: {alts[:5]}")
- מצאו לפחות 3 חלופות לכל תו ברשימה
- לכל חלופה, ציינו את שם התו ב-Unicode (השתמשו ב-
unicodedata.name()) - סמנו אילו חלופות עוברות גם נורמליזציית NFC (לא רק NFKC)
תרגיל 2 - מטעני XSS עם Full-width¶
משימה:
- בנו מטען XSS שמשתמש רק בתווים ברוחב מלא (full-width) עבור תווים מיוחדים:
- המטען:
<img src=x onerror=alert(1)> -
החליפו את
<,>,(,),=בגרסאות full-width -
שלחו את המטען לאפליקציית הבדיקה וודאו ש:
- ה-WAF לא חוסם
-
האפליקציה מנרמלת והמטען מתבצע
-
בנו מטען חלקי - החליפו רק תו אחד ובדקו מהו המינימום הנדרש לעקיפת ה-WAF
תרגיל 3 - מטעני SQLi עם Unicode¶
משימה:
- בנו מטען SQLi שמנצל תווי Unicode חלופיים:
- מטען מקורי:
' UNION SELECT username, password FROM users-- -
החליפו את הגרש, רווחים, ופסיקים בחלופות Unicode
-
בדקו אילו צורות נורמליזציה מפענחות את המטען:
-
מצאו מטען שעובר רק ב-NFKC ולא ב-NFC (כלומר, WAF שעושה NFC לא יתפוס)
תרגיל 4 - התקפות הומוגרף¶
משימה:
-
כתבו פונקציה שמייצרת כל הקומבינציות ההומוגרפיות של מילה:
def homograph_variants(word): # מיפוי Latin -> Cyrillic latin_to_cyrillic = { 'a': '\u0430', 'c': '\u0441', 'e': '\u0435', 'o': '\u043e', 'p': '\u0440', 'x': '\u0445', 'y': '\u0443', 's': '\u0455', } # השלימו - יצרו כל הקומבינציות pass variants = homograph_variants("script") print(f"מספר וריאנטים: {len(variants)}") -
בדקו אילו מהווריאנטים של
scriptעוקפים את ה-WAF - בדקו אילו מהם עדיין מתפקדים כתגית HTML בדפדפן
תרגיל 5 - תווים בלתי נראים¶
משימה:
- הכניסו תווי zero-width בתוך מילים שה-WAF חוסם:
scr\u200bipt(zero-width space בתוך script)-
SEL\u200bECT(zero-width space בתוך SELECT) -
בדקו:
- האם ה-WAF חוסם את המטען?
- האם האפליקציה (אחרי נורמליזציה) מקבלת אותו כתקין?
-
האם הדפדפן מתעלם מתווים אלו בתוך תגיות HTML?
-
נסו תווי zero-width נוספים ותעדו את ההתנהגות של כל אחד
תרגיל 6 - בעיית ה-I הטורקי¶
משימה:
-
בנו מטען שמנצל את הבעיה הטורקית:
-
בנו רשימת מילות מפתח SQL שמושפעות מ-case mapping טורקי
- האם
I(U+0130, I with dot above) מתנרמל ל-iב-NFKC?
תרגיל 7 - כלי אוטומטי¶
משימה:
בנו כלי Python שמקבל מטען ומייצר אוטומטית וריאנטים עם Unicode:
class UnicodeWAFBypass:
def __init__(self, payload):
self.payload = payload
self.variants = []
def generate_fullwidth(self):
"""יצירת וריאנט full-width"""
pass
def generate_homograph(self):
"""יצירת וריאנטים הומוגרפיים"""
pass
def generate_zero_width(self):
"""הכנסת תווי zero-width"""
pass
def generate_mixed(self):
"""שילוב של כל הטכניקות"""
pass
def test_all(self, target_url):
"""בדיקת כל הווריאנטים מול ה-WAF"""
pass
# שימוש
bypass = UnicodeWAFBypass("<script>alert(1)</script>")
bypass.generate_fullwidth()
bypass.generate_homograph()
bypass.generate_zero_width()
bypass.generate_mixed()
bypass.test_all("http://localhost:5000/search")
- השלימו את כל המתודות
- הוסיפו מתודה שבודקת אם הווריאנט עדיין תקין (מתנרמל חזרה למטען המקורי)
- הריצו מול סביבת הבדיקה ותעדו: כמה ווריאנטים עברו את ה-WAF? אילו טכניקות הכי יעילות?