quic-go היא המימוש הנפוץ של פרוטוקול QUIC בשפת Go, והבסיס שעליו תוכניות Go מגישות ומבקשות HTTP/3. לפי הרשומה, בגרסאות 0.56.0 ומטה אפשר לשלוח בקשה אחת שהכותרות שלה נפרשות לכמות זיכרון גדולה, ולמלא בה את הזיכרון של הצד שמקבל אותה. הציון הוא 5.3 מתוך 10, והתיקון הוא גרסה 0.57.0.

מה החולשה?

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

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

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

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

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

מי מושפע?

כל גרסה של quic-go מתחת ל-0.57.0. הספרייה היא github.com/quic-go/quic-go, והיא נמצאת בתוך תוכניות ולא מותקנת בנפרד, כך שמי שמושפע אינו מי שהתקין quic-go אלא מי שמריץ תוכנית Go שבנויה עליה.

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

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

האם מנוצלת בפועל?

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

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

מה עושים?

1. בדקו באיזו גרסה אתם. בשורש פרויקט Go הריצו go list -m all ואחריו סינון לפי quic-go, או פשוט חפשו את השורה של github.com/quic-go/quic-go בקובץ go.mod.
2. עדכנו ל-0.57.0 ומעלה, עם go get github.com/quic-go/[email protected] ואחריו go mod tidy.
3. בנו מחדש את הבינארי ופרסו אותו. בספריית Go אין עדכון שנכנס לתוקף בלי בנייה מחדש, וזה הבדל מרכזי מול עדכון של שרת מותקן: קובץ go.mod מעודכן בלי בנייה חדשה אינו משנה דבר בייצור.
4. בדקו את הדבר הזה גם בתוכניות שאינן שרתים. כל תוכנית Go שלכם שפונה אל שרתים חיצוניים ב-HTTP/3 צריכה את אותו עדכון. הודעת האבטחה והעדכון בקוד מרכזים את הפרטים.