מדריך: XSS – Cross Site Scripting – הזרקת קוד (חלק 2)

אמשיך בסדרת המאמרים על הזרקות קוד (כהמשך לחלק הראשון), ואזכיר שראשי התיבות XSS מתייחסות לסוג פרצות האבטחה Cross Site Scripting, ולא לשפת עיצוב הגליונות CSS, עליה בוודאי אדבר בהזדמנויות אחרות.

פרצות XSS לרוב מתחלקות לשני סוגים עיקריים:

הראשונה היא פרצה זמנית, כלומר חד פעמית, שנעשית במכוון ולכן יש צורך להפנות את הקורבן לעמוד הספציפי עם הטעות. לרוב, פרצה זו קורה בעמודים של מנועי חיפוש שמציגים את שאילתת החיפוש באופן חד פעמי לאתר, אך לא שומרים זאת אצלם, כך שצריך להפנות את המשתמש אל עמוד תוצאות החיפוש הספציפי.

השנייה היא פרצה קבועה, שבה ההאקר שומר בדרך כלשהי את הסקריפט על השרת (דוגמא טובה היא למשל מערכת פורומים, בה ההאקר שותל את הסקריפט כהודעה מן המניין), והוא הופך לחלק אינטגרלי מעמוד מסויים.

יש המחשיבים אופציה נוספת שנקראת פרצת XSS מקומית. בפרצה מסוג זה מתכנת שומר בצד המשתמש קוד (לרוב JavaScript פשוט) שנחוץ לו לפעולה שוטפת באופן שגלוי למשתמש ולעיתים קרובות אפילו מאוכסן על מחשבו, למשל, קוד בדיקת תקינות טפסים. בצורה כזו, המשתמש יכול לערוך את קוד בדיקת התקינות באופן עצמאי, ובכך להתגבר על בדיקת התקינות, ולבצע פעולות שלא היה אמור לעשות מההתחלה.

כבודק אתרים, אין צורך לעשות עבודה מרובה כדי לבדוק האם האתר מכיל פרצות XSS או לא. כל מה שצריך זה ידע מועט בJavaScript, והרבה דמיון, שהרי האפשרויות לפרצות – כמעט ואין-סופיות. אדגים מספר תרחישים אפשריים:

  • האקר מוצא פרצת XSS. הוא מנצל את הפרצה כדי להפנות את כל מי שמגיע לעמוד שהוא יוצר לעמוד דמה, שגונב את פרטיהם.
  • האקר מוצא פרצת XSS. הוא מנצל את הפרצה כדי לגנוב את פרטי העוגייה של המשתמש ולשלוח אותם אליו.
  • האקר מוצא פרצת XSS. הוא מנצל את הפרצה כדי להחדיר לאתר קוד זדוני. הקוד הזדוני שותל במחשב הקורבן רוגלה.

למעשה, הקלות שבה ניתן להשיג את הפרטים החסויים של המשתמשים פשוט מטרידה.

במאמר הבא ניכנס לעשייה, נתחיל לבדוק האם האתר מכיל פרצות אבטחה מסוג XSS, איך בודקים, מהם הסקריפטים הנפוצים ואיך מתמודדים עם תיבת הפנדורה שפתחתם ברגע שהתחלתם לקרוא את המאמר הזה. נתראה שם!

גלישת חוצץ, גלישות זכרון ותכנות נכון

מדריך זה ינסה להסביר קצת על פרצות האבטחה בשם "גלישת חוצץ" (Buffer Overflow) וגלישה נומרית (Integer Overflow), על הנזקים שגלישות אלו יכולות לעשות ומעט על תכנות נכון. עם זאת, טכניקה זו דומה מאוד להזרקות SQL, לכן אולי כדאי גם לקרוא את הנושא על SQL Injections ולהיות בקיא בנושא.

ניתן להגדיר (דיי בקלות) את גלישות החוצץ כשגיאה השטותית ביותר, אך עם התוצאות ההרסניות ביותר. עם זאת, חלק גדול ממה שנאמר כאן כבר לא רלוונטי, אבל מכיוון שהבלוג הזה לא מוגבל לשפה כלשהי או מהדר ספציפי, אפשר לדבר כאן בקלות גם על מקרים שכבר לא תקפים בשפות מסוימות, במהדרים מסוימים וכו'.

כדאי שנבהיר מהו חוצץ (buffer), בכמה משפטים קצרים – חוצץ הוא מקטע זיכרון שמשמש כשלב ביניים בעת העברת המידע. בדרך כלל, המידע ייכתב אל החוצץ, ולאחר שהחוצץ יתמלא הוא יועבר למיקום הסופי שלו, והחוצץ יחל להתמלא מחדש. שימוש נפוץ כזה לחוצץ הוא בעת פעולת הצריבה לדיסק. מכיוון שיש צורך שהמידע ייצרב ברצף וללא הפסקות לדיסק, צריך להעביר את המידע באופן זמני אל חוצץ, שמשם הוא ייצרב אל הדיסק. בתוכנות רבות גודלו של חוצץ זה הוא 2.2 GB, ולכן לא ניתן לצרוב קבצים בסך של מעבר לגודל זה. כיום גודל החוצצים גדול הרבה יותר.

וכעת לעניינו – גלישת חוצץ מתבטאת בכך שתוכנית כלשהי חורגת ממגבלותיה, ורושמת לזיכרון יותר ממה שהוגדר לה. דוגמה לכך תהיה להכניס משפט שלם למקום בזכרון שמסוגל להכניס רק תו אחד, אם כי שגיאה כזו תהיה נדירה מאוד, או מספר גדול מאוד למקום שבו ניתן היה להכניס רק ספרות בודדות (מספר קטן בהרבה). התווים האחרים, אם כן, ימשיכו להירשם לזיכרון למקומות בזיכרון שאינם שייכים למשתנה, ובכך ישנו ערכים עליהם אין לנו שליטה. כלומר, בכך אנחנו יכולים לשנות (בטעות) ערכים חשובים של מערכת ההפעלה, משתנה אחר של התוכנית וכו' ולגרום לקריסה של התוכנית (בשפה המקצועית – Denial Of Service), במקרה הטוב, לשינוי ערכים מהותיים של מערכת ההפעלה או להרצה של קוד זדוני, במקרה הרע.

סוג נוסף של גלישה היא הגלישה הנומרית. שבמקרים רבים משעשעת הרבה יותר. כשאנו מתעסקים עם מספרים, הרבה פעמים נצטרך לבחור את סוג המשתנה בו נשתמש – במקרים רבים "הבחירה הטבעית" Integer (שמספק לנו טווח של בין 32,000- ל- 32,000+)יספיק לנו, ולא נרצה להשקיע מאמץ גדול בבחירת המשתנה. אבל קורה שאנחנו לא מערכים בצורה נכונה את גודל המשתנה את צורת ההצגה שלו וכדומה. במקרים כאלה, נוצרים באגים שנובעים מהכנסה של ערך גדול מדי. במקרים מסוימים, ייכנס הערך המקסימלי אליו יכולנו להגיע. במקרים אחרים, ייכנסו רק מספר הספרות האחרונות, ובכך נאבד חלק חשוב מהמספר אליו התכוונו (ראו ערך באג 2000. מכיוון שהשנים היו מיוצגות בשתי ספרות, לאחר השנה 99 הגיעה השנה 00) או בשיגור של משגר הלוויינים אריאן 5 (שנחל כישלון, אתם יכולים להניח) תוצאות מוזרות אפילו יותר יכולות להתקבל.

ידע בשפת C נדרש.

נניח ותוכנית מקבלת כארגומנט מחרוזת, ומשתמשת בפונקציה שאינה מוגנת כדי להכניס אותה למקום בזיכרון. כידוע, בשפת C מחרוזת בנויה כמערך של תווים, ולכן יש צורך לתת לה גודל מוגדר, אך מכיוון שהמחרוזת נקלטת מהמשתמש, אין אנחנו יכולים לדעת בוודאות כי הקלט שנתקבל תקין ועומד בסטנדרטים שנקבעו בתוך התוכנית (למשל, להגביל את המערך במספר התווים). פונקציה לא מוגנת כגון gets(), יכולה לגרום לפרצת אבטחה חמורה אם לא משתמשים בה כראוי. פונקציות נוספות שלא מבצעות בדיקות תקינות הן:

  • gets()
  • memcpy()
  • strcpy()

בצורה הזו, אנו יכולים להכניס אל הזיכרון קטע קוד זדוני שמשפיע על גרעין מערכת ההפעלה (בשפה המקצועית – Shell Code) ולגרום לכך שהמעבד יריץ את הקוד הזדוני. ניתן לעשות זאת על ידי הכנסת מצביע אל הקוד הזדוני שלנו לאוגר בשם EIP (שעובד על עקרון זהה לזה של PSW – מכיל בתוכו הצבעה לפקודה הבאה שצריכה להתבצע) ולשם להכניס קטע קוד שייתן לנו הרשאות בצורה מסודרת.

מחפש שרת אכסון,

טוב, Godaddy מתחיל להמאס עליי. הוא רחוק ואיטי וזה משהו שאני לא כל כך מצליח להסתדר איתו. יש למישהו המלצות על שרת מהיר, סביר במחיר ואמין? עדיפות לישראלי.

סטודיו לבניית אתרים בקלות: dropbox ושרת ביתי – שילוב מנצח

אני בטוח שכל מי שקורא את הפוסט הזה ויצא לו לנסות לבנות אתר בצוותא, מה שנקרא "דרך המסנג'ר" מכיר את התופעה: כאשר הפרטנר אינו מוחשי לידך אתה נתקל בהמון קשיים – קשיי תקשורת ותשתית. האנשים שאני מכיר לרוב בחרו בפתרונות הפשוטים והאינסטינקטיביים לפתרון חלקי של הבעיות האלה. אם זה בעזרת שליחה תמידית של הקבצים עליהם עובדים דרך תוכנות המסרים המיידיים (מה שגורם לאיטיות וסרבול, ולא פעם לבזבוז זמן כששני הצדדים מעדכנים את הדף בו זמנית) ובין אם זה פתרון אחר, גם הוא אינסטינקטיבי לא פחות – לעבוד על שרת משותף, אך לזה חסרון גדול – שרתים מעצם היותם שרתים הרבה יותר איטיים מאשר עבודה על המחשב. הם גם מספקים הרבה פחות פרטיות ממה שאנחנו רוצים כיאה לפרויקט בתחילת דרכו.

ובכן, בעת עבודתי עם חברי אלירן פאר (הידוע בכינויו "בלוז"), מצאנו פתרון הרבה יותר טוב: התקנו שרת ביתי על שני המחשבים שלנו, בעזרת התוכנה EasyPHP (אבל אני מניח שכל תוכנת שרת בקלות תעבוד, כמו למשל Wamp, בחרנו בEasyPHP בגלל היכרות מוקדמת עם התוכנה), ואילו את תיקיית השרת שיתפנו על ידי התוכנה dropbox.

dropbox היא אולי התוכנה היעילה ביותר שראיתי מזה שנים. התוכנה משתמשת בצבא של שרתי-ענן שמעלים את תוכן התיקיה אותה אנו משתפים באופן תמידי, עם כל עדכון של הקבצים, ומעדכנים את כל המחשבים בקבוצה. ובתרגום לעברית פשוטה: כל שינוי שאני עשיתי בקבצי השרת התעדכן באופן מיידי במחשבו של אלירן, וכך גם להפך. רענון פשוט בדפדפן הציג לי את הגרסא של הקובץ עליה אלירן עבד באותה דקה בדיוק, התראות מודיעות לי כשהוא מעדכן את הקבצים, גיבויים של הקבצים נשמרים באופן אוטומטי והשרתים המהירים גורמים לעבודה להיות חלקה מתמיד.

הבעיה היחידה היא בעבודה עם sql – לא מצאנו דרך יעילה מספיק לעדכן ולשתף במהירות את אותו המסד, אז החלטנו להתחבר אל שרת חיצוני.

אני בטוח שהעבודה בשיטה הזו תפתח חלון הזדמנויות לעבודה מהירה, בטוחה וקלה יותר לכלל קהילת המפתחים ממנה אני חלק. אני מגיש לכם את הפתרון הזה בעיניים עצומות ובבטחון ואני סמוך ובטוח שהפתרון הזה יעשה את החיים שלכם להרבה יותר קלים.