ב-5 באוקטובר, ב-05:31 לפי שעון UTC, מי שניגש לכתובת ה-onion הראשית של Dread, אחד מפורומי הדארקנט הגדולים, קיבל הודעה שהאתר נפרץ. חצי שעה אחר כך הציגה אותה כתובת מסר מהמנהל של Conclave, פורום מתחרה, שטען שהמפתח הפרטי של הכתובת נמצא בידיו. מנהלי Dread הסבירו באותו יום שמדובר בטעות אנוש, ארכיון שהועלה בגרסה חדשה של התוכנה והכיל בשוגג את המפתח. יומיים לאחר מכן נלקחה גם כתובת הגיבוי, זו שנשמרה למשתמשים מועדפים, ואת זה כבר היה קשה להסביר בהעלאה שגויה אחת.

ב-8 באוקטובר פרסמו חוקרי Searchlight Cyber, ד"ר Gareth Owenson ו-David Andreas, את ההסבר הטכני. בכלי שהאתרים האלה מריצים כדי לשרוד מתקפות מניעת שירות יש חולשה שמאפשרת לכל אחד לחשב את המפתח הסודי של כתובת onion מתוך מידע שהאתר עצמו מפרסם בגלוי. בלי גישה לשרת, בלי נוזקה, בלי סיסמה. נעבור על למה האתרים האלה בכלל צריכים את הכלי, איפה נשמט בדרך חצי מהמפתח, ואיך החצי החסר הופך חתימה פומבית אחת לתרגיל שאפשר לפתור.

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

שווקים ופורומים גדולים בדארקנט סופגים מתקפות מניעת שירות באופן קבוע, לא פעם מהמתחרים שלהם. פרויקט Tor מציע לכך מענה בשם OnionBalance, שמאפשר לכתובת onion אחת להיות מוגשת בפועל על ידי כמה שרתי backend במקביל, כך שהפלת שרת בודד לא מפילה את האתר. מפעילי הדארקנט לא היו מרוצים מקצב ההתקדמות של הגנות ה-DDoS של Tor עצמו, ולכן בנו ערכת כלים משלהם בשם EndGame. בתוך הערכה הזאת יש רכיב בשם GoBalance, שהוא כתיבה מחדש של OnionBalance בשפת Go. (הכלי נבנה כדי שהאתרים האלה לא ייפלו תחת מתקפה, ובסוף הוא זה שהעביר את הכתובות שלהם לידיים אחרות.)

כאן נקודה שקובעת את גבולות הסיפור: החולשה היא בכתיבה מחדש, לא במקור. Searchlight מדגישים ש-OnionBalance המקורי ו-Tor עצמו אינם מושפעים.

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

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

חצי מפתח שנזרק בדרך

ל-OnionBalance יש שני פורמטים אפשריים למפתח הזהות. בפורמט ed25519 התקני הקובץ מכיל זרע של 32 בתים, והתוכנה מרחיבה אותו בעזרת SHA-512 לשני חלקים שונים בתפקידם: סקלר סודי שאיתו חותמים, ומפתח נוסף שכל תפקידו לייצר את המספר החד-פעמי של כל חתימה. Tor עצמו עובד אחרת. הוא לא שומר את הזרע בכלל, אלא כותב לקובץ את 64 הבתים שכבר הורחבו, הסקלר ואחריו המפתח שמייצר את המספר החד-פעמי.

והנה הבאג. פונקציית החתימה ב-GoBalance בודקת באיזה מהפורמטים נמצא המפתח, ובשני המסלולים קוראת לאותה שיטה שמחזירה את הזרע. השיטה הזאת שייכת לספריית ed25519 של Go, והיא מחזירה תמיד את 32 הבתים הראשונים בלבד. במסלול התקני זה תקין לחלוטין, כי הקוד שממשיך מרחיב את הזרע מחדש ומייצר את שני החלקים. במסלול של הפורמט של Tor, מה שנטען מהדיסק הוא כבר 64 הבתים המורחבים, ולכן אותה שיטה מחזירה את הסקלר ומשמיטה בשקט את החצי השני. הקוד שממשיך מניח שבידיו 64 בתים, חותך מהם את החלק שמתחיל בבית ה-32, ומקבל מחרוזת ריקה.

אז למה חצי מפתח שווה את כל המפתח?

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

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

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

חתימה אחת שפורסמה. זה הכל.

מה קרה ב-Dread, ומה נשאר במחלוקת

עד כאן המתמטיקה, שהיא חד-משמעית. מה שקרה ל-Dread בפועל חד פחות. החוקרים בונים את הכרונולוגיה מהצהרות וצילומי מסך פומביים, ומציינים במפורש שלא יכלו לאמת באופן עצמאי את טענותיו של אף אחד מהצדדים. ב-5 באוקטובר HugBunter, מייסד Dread, פרסם דוח שתלה את האירוע במנהל השותף Paris, שלקח אחריות וכתב שהעלה בטעות את הספרייה הלא נכונה. ב-6 באוקטובר HugBunter חזר על אותה גרסה.

ב-7 באוקטובר, בסביבות 02:29, הופיעה בכתובת הגיבוי הודעה ברוסית שחלקה על הגרסה הזאת, בטענה שהשתלטות על כתובת שנייה מוכיחה שלא מדובר בהעלאה מוטעית. ההודעה כללה איומים מרומזים, דרישת התנצלות ופיצוי, והבטחה לפרסם את השיטה בהמשך. עד 12:37 המנהלים החזירו לעצמם את הכתובת, ואז HugBunter אישר שהתוקף השתמש בחולשת יום-אפס ב-GoBalance נגד כמה שירותים בדארקנט. לגבי הכתובת הראשית הוא נשאר בעמדתו שהיא אבדה בדליפת מפתח נפרדת, וזו גם הקריאה של Searchlight: את ההשתלטות השנייה הם רואים כסימן החזק לשימוש בחולשה, ואת הראשונה כאירוע נפרד.

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

למה זה לא נגמר בהחלפת כתובת

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

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

מה זה אומר בפועל

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

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