דף הבית   על אודות   צרו קשר   לפני האיתחול  
1 ביוני2018

אנטומיה של פרצה - המקרה המצער של רשות התעופה האזרחית


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

הכל התחיל בפרויקט גדול יותר של סריקת הרשת הישראלית, שזה לא המקום לפרט אודותיו אבל עוד אכתוב עליו לכשיבשיל בעתיד. אחד הנדבכים בפרויקט הוא בדיקה של “הלשנות DNS”. מה הן הלשנות DNS? ובכן, אם פעולה רגילה של שרת DNS (עליה כתבו לודה ובלעם בפירוט) היא שאלה: “מה הכתובת של מתחם כזה או אחר”, ותשובה: “הכתובת היא 1.2.3.4”, שרת מלשין הוא שרת שאפשר לשאול אותו “תגיד לי כל מה שאתה יודע על מתחם כזה או אחר” והוא מספר הכל.

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

dig ns caa.gov.il

בתשובה מופיעים שרתי שם המתחם (Nameservers) האחראיים לדומיין. למשל:

;; ANSWER SECTION:

caa.gov.il. 3599 IN NS ns1.gov.il.

aa.gov.il. 3599 IN NS ns2.gov.il.

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

dig axfr @ns1.gov.il caa.gov.il

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

ברשימה הזו נתמקד רק ברשומות מסוג A, אבל אפשר לעשות המון כיף גם עם רשומות דוא”ל ורשומות אחרות שמתחבאות שם. בתמונה הזו אפשר לראות את הפלט שהתקבל בפניה לשרת המלשין של רשות התעופה האזרחית. טשטשתי את התשובות, כי סיבות, אבל כן אפשר לראות שורה ארוכה של רשומות. בונוס: אחת הרשומות היא מסוג RP, וכוללת את כתובת המייל והטלפון הסלולרי של האחראי על המתחם.

dig axfr

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

caa form

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

caa form post

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

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

בגדול, אם מה שהמפתח החובב התכוון לעשות זה משהו כמו:

SELECT * FROM table WHERE category=’Airplane’ AND char=’c’

הזרקת SQL מאפשרת לנו לגרום לשאילתה של המפתח להראות ככה:

SELECT * FROM table WHERE category=’Airplane’ AND char=’c’ OR (1=1) #

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

SELECT * FROM table WHERE category=’Airplane’ AND ORD(MID((SELECT IFNULL(CAST(table_name AS CHAR),0x20) FROM INFORMATION_SCHEMA.TABLES WHERE table_schema=0x6d7973716c LIMIT 7,1),1,1))>104 AND ‘iHUS’=’iHUSAND char=\’c’

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

במקרים רבים, הקוד הפגיע פשוט מקיא החוצה את המידע. אלה המקרים הקלים יותר. למשל בעמוד שמציג פרטים של משתמש, אפשר פשוט לבקש בנימוס פרטים של משתמשים אחרים, או אפילו מידע מטבלאות אחרות, והקוד ידפיס אותו החוצה בשמחה כמו כלבלב שמביא בבוקר את העיתון של השכן. במקרים אחרים המצב בעייתי יותר כי אין הדפסה של פלט, או שההדפסה מוגבלת, ולכן צריך לעבוד קצת קשה יותר. למשל, אני יכול לשאול, “האם שם המשתמש הוא אבי?” והקוד רק יגיד כן או לא. אבל לשאול ככה יקח שנים, ואנחנו בעלי סבלנות מוגבלת, לכן נשתמש במשהו שנקרא “התקפת SQL מבוססת זמן”, או בלעז time-based SQL attack, שעובדת בערך ככה:

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

SELECT CASE WHEN substr(username, 3, 1) = ‘a’ THEN sleep(3) ELSE NULL END FROM table WHERE id = 1;

ובשפת בני אדם: אם התו השלישי בשדה “שם המשתמש” של המשתמש הראשון בטבלת המשתמשים הוא א’ אז תישן 3 שניות, אחרת תגיד לי עכשיו.

וככה זה נראה בפועל:

time blind SQL injection

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

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

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

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

סיכום הכשלים, כפי שאני מבין אותם:

  • שרת DNS מלשין שחשף שורה של מערכות שפותחו בסטנדרטים לא גבוהים

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

  • אי הגבלת הרשאות המשתמש של הסקריפט כך שהיתה לו גישה לכל מסדי הנתונים על השרת

  • העדר מנגנון הגבלת קריאות בכל הרמות, החל מהפיירוול ועד לשרת הווב

  • העדר מנגנון זיהוי הזרקות SQL בכל הרמות, החל מהפיירוול ועד לשרת הווב

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

  • בגדול יותר: העדר בקרה על הקוד שנמצא בשימוש על שרת ממשלתי

  • בגדול יותר: העדר בדיקות חדירה פשוטות למערכות חיות שהיו מזהות את הפרצה בקלות

  • בגדול יותר: העדר שקיפות בטיפול בפרצות שהתגלו על מנת להרתיע מפתחים העובדים עבור הממשלה כדי שלא ייצרו קוד חובבני כל כך

  • ולבסוף, חסימת כתובת הדוא”ל שלי (וטף?!) ב-CERT הממשלתי, מנגנון שתפקידו לקבל דיווחים על פרצות, ועיכוב של שעות במענה לדיווח. אלמלא אנשים שהכירו אנשים אחרים שעובדים באבטחת מידע במערכות הממשלתיות ושראו את דיווחי הפומביים, ספק אם מישהו שם היה מתייחס להסגרה שלי עד היום.


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