Mongoose היא ספריית מידול נתוני אובייקטים (ODM) עבור MongoDB המפשטת אינטראקציות של מסדי נתונים ביישומי Node.js. על ידי מתן פתרון מבוסס סכימה, Mongoose מאפשרת למפות אובייקטי JavaScript למסמכי MongoDB, ופועלת כשכבת הפשטה המסייעת בבניית נתונים לניהול ואימות קלים יותר. עם תכונות כמו תוכנת ביניים לביצוע לוגיקה מותאמת אישית ומערכת אינטואיטיבית לבניית שאילתות, Mongoose משפרת את יעילות העבודה עם MongoDB. Mongoose, שתוארה כ"מידול אובייקטים אלגנטי של MongoDB עבור Node.js", צברה 27,000 כוכבים ב-GitHub, המשקפים את השימוש הנרחב שלה וההערכה שלה בקרב מפתחים.
OPSWAT תוכנית מלגות וגילוי פגיעויות קריטיות
תוכנית המלגות לתואר שני בתחום אבטחת סייבר OPSWAT , הממוקמת בווייטנאם, מספקת לסטודנטים לתארים מתקדמים ניסיון מעשי באבטחת תשתיות קריטיות. כחלק מתוכנית זו, לעמיתים יש הזדמנות לנתח ולטפל בפגיעויות אבטחת סייבר, תוך שיתוף פעולה עם... OPSWAT מומחים להתמודדות עם אתגרים מהעולם האמיתי בתחומים כמו זיהוי תוכנות זדוניות, אבטחת קבצים ומניעת איומים.
במהלך ה OPSWAT במסגרת תוכנית המלגות, המשתתפים חוקרים ומשחזרים באופן שיטתי קוד גישה (CVE) ידוע במוצרים, ספריות ומערכות הפעלה שונות. כחלק מיוזמה זו, דאט פונג - אחד מעמיתינו המכובדים - בחר לבחון את Mongoose בשל אימוץ נרחב בסביבות ייצור. בנובמבר 2024, הוא גילה פגיעות קריטית ב-Mongoose בעת ביצוע ניתוח מעמיק של הספרייה. הפגיעות אפשרה לתוקף לנצל את הערך $where , מה שעלול להוביל לביצוע קוד מרחוק (RCE) בשרת היישומים Node.js. לאחר דיווח מיידי על הבעיה ל-Mongoose, שוחרר תיקון כחלק מגרסה 8.8.3, ו-CVE-2024-53900 נחשף במסד הנתונים הלאומי של פגיעויות (NVD).
ציר זמן של CVE-2024-53900 ו-CVE-2025-23061
- 7 בנובמבר 2024: דאט פונג זיהה פגיעות קריטית ב-Mongoose והגיש דוח אבטחה ל-Snyk.
- 26 בנובמבר 2024: Mongoose הוציאה את גרסה 8.8.3 כדי לטפל ולתקן פגיעות זו.
- 2 בדצמבר 2024: מסד הנתונים הלאומי של פגיעויות (NVD) חשף את CVE-2024-53900 עבור פגיעות זו.
- 17 בדצמבר 2024: לאחר ניתוח עדכון 8.8.3 של Mongoose, דאט פונג מצא עקיפה שעדיין אפשרה ביצוע קוד מרחוק (RCE). דוח אבטחה מפורט הוגש ל-Tidelift.
- 13 בינואר 2025: Mongoose הוציאה את גרסה 8.9.5, והציגה תיקון משופר שטיפלו ביעילות בעקיפת הבעיה.
- 15 בינואר 2025: מסד הנתונים הלאומי של פגיעויות (NVD) חשף רשמית את CVE-2025-23061, תוך הדגשת חומרת הפגיעות שזוהתה לאחרונה.
שיטת Populate() של Mongoose
Mongoose מספקת גם תכונה שימושית בשם populate() אשר משפרת את היכולת לעבוד עם קשרים בין מסמכים. בעוד שגרסאות MongoDB ≥ 3.2 כוללות את אופרטור הצבירה $lookup עבור צירופים, populate() של Mongoose מציעה אלטרנטיבה חזקה יותר להחלפה אוטומטית של הפניה בנתונים המתאימים ממסמכים קשורים. זה שימושי במיוחד לניהול קשרים בין אוספים שונים של MongoDB, כגון כאשר מסמך אחד מפנה לאחר באמצעות ה-_id שלו. [2]



בעת הגדרת סכימה ב-Mongoose, ניתן להגדיר שדה להפנות למודל אחר באמצעות האפשרות ref. לאחר מכן, השיטה populate() משמשת להחלפת השדה המופנה (ObjectId) במסמך המלא מהמודל הרלוונטי. לדוגמה, ביישום חנות ספרים, שדה המחבר ב- bookSchema מפנה למסמך המחבר , ושדה הסקירה מפנה למסמך הסקירות . השיטה populate() מאפשרת למפתחים להחליף את שדה המחבר (שהוא ObjectId) במסמך המחבר המלא בעת ביצוע שאילתה על מודל הספר.
הפונקציה populate() מאפשרת למפתחים להחליף את שדה המחבר (שהוא ObjectId) במסמך המחבר המלא בעת ביצוע שאילתה על מודל הספר :


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

ניתוח CVE-2024-53900
כחלק מ- OPSWAT במסגרת תוכנית המלגות לתואר שני באבטחת סייבר, תוך כדי ניתוח Mongoose כדי לשחזר CVEs ידועים, דאט פונג ערך סקירה מקיפה של הפעולה הפנימית של שיטת populate(), אשר ממלאת תפקיד מפתח בטיפול בקשרים בין מסמכי MongoDB. שיטת populate() תומכת הן בארגומנטים של מחרוזות והן בארגומנטים של אובייקטים, ומפתחים יכולים להשתמש באפשרות ההתאמה כדי להחיל מסננים ספציפיים על הנתונים המאוחזרים:

בדוגמה לעיל, אפשרות ההתאמה היא אובייקט מסנן שיכול לכלול אופרטורי שאילתה של MongoDB, כמפורט במדריך Query and Projection Operators - MongoDB גרסה 8.0 . אופרטור בולט אחד הוא $where , המאפשר ביצוע JavaScript ישירות בשרת MongoDB. עם זאת, ביצוע זה בשרת MongoDB מוגבל, ותומך רק בפעולות ופונקציות בסיסיות.

דאט פונג ערך ניתוח מעמיק של קוד המקור של Mongoose כדי להבין את תהליך העבודה של מתודת populate() . הוא קבע שאחרי שהאפליקציה קוראת למתודת populate() במודל, הפונקציה populate() מופעלת. בתוך פונקציה זו, Mongoose קורא לפונקציה _execPopulateQuery() , אשר מבצעת את השאילתה באמצעות האופרטור $where בשרת MongoDB. לאחר מכן, כל המסמכים מהאוסף הזר מאוחזרים לצורך אכלוס בשלבים הבאים.

לאחר אחזור הנתונים מ-MongoDB, Mongoose מבצעת את פונקציית ה-callback _done() , אשר קוראת ל- _assign() כדי להכין את הנתונים לפני "איחוד" שני המודלים על ידי קריאה לפונקציה assignVals() .

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

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

כאשר התנאי קיים, האופרטור $where הועבר לאחר מכן לפונקציית sift() .

ספריית sift היא כלי עזר קל משקל ב-JavaScript שנועד לסנן ולבצע שאילתות ב-Oscoops נתונים כגון מערכים או אובייקטי JSON באמצעות תחביר דמוי MongoDB. על פי התיעוד הרשמי, "Sift היא ספרייה זעירה לשימוש בשאילתות MongoDB ב-JavaScript." הפונקציה sift() מעריכה פעולות סינון דמויות MongoDB בשרת היישומים במקום בשרת מסד הנתונים, דבר שעלול לחשוף את המערכת לסיכוני אבטחה משמעותיים בעת עיבוד קלט לא מהימן.

בהמשך לניתוחו, עמיתנו זיהה בעיה בפונקציית createDefaultQueryTester() של ספריית sift. פונקציה זו ממירה כל פעולה במערך ההתאמה לפונקציות JavaScript ניתנות לביצוע, אשר לאחר מכן משמשות לסינון ועיבוד נתוני מסמך MongoDB באופן מקומי. לשם כך, הפונקציה createDefaultQueryTester() מפעילה את הפונקציה createNamedOperation() , ומעבירה פעולות כגון $where ממערך ההתאמה כארגומנטים.

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

אם הפעולה היא $where , נוצרת פונקציית JavaScript באמצעות הערך הגולמי "params", הנגזר מהאופרטור $where במערך ההתאמה וניתן לשלוט בו על ידי המשתמש.

CVE-2024-53900: פרטי ניצול
בעוד ש-MongoDB מגביל את ביצוע פונקציות JavaScript דרך פעולת $where , כפי שניתח קודם לכן, הפונקציה sift() מאפשרת ביצוע פונקציות אלו ללא הגבלות כאלה. חוסר אימות והגבלת קלט זה מציג פגיעות אבטחה משמעותית, שכן ערך ה-"params" - הנשלט ישירות על ידי קלט המשתמש - עלול להיות מנוצל, מה שעלול להוביל להתקפות הזרקת קוד. כדי לבחון נושא זה בצורה יסודית יותר, דאט פונג בנה את השאילתה הבאה:

בתחילה, השאילתה נכשלה בביצוע תהליך אחר, וכתוצאה מכך נוצרה השגיאה הבאה:

שגיאה זו מציינת ש-Mongoose מנסה לבצע את פעולת $where בשרת MongoDB לפני העברת השליטה לפונקציית sift(). עם זאת, עקב המגבלות על פונקציות JavaScript בפסקת $where של MongoDB, מתרחשת שגיאה המונעת את ביצוע השאילתה. כתוצאה מכך, Mongoose עוצר את התהליך לפני שהוא יכול להגיע לפונקציית sift() .
כדי לעקוף את המגבלה, עמיתנו השתמש במשתנה "גלובלי" הקיים בשרת היישומים, שאינו קיים בשרת MongoDB. גישה זו אפשרה לו לעקוף את המגבלה בשרת MongoDB ולאפשר לשאילתה להגיע לפונקציית sift() :

עם ערך זה, כאשר Mongoose מבצעת את הפעולה $where ב-MongoDB, היעדר המשתנה "global" גורם לאופרטור הטרנרי (typeof global != "undefined" ?global.process.mainModule.constructor._load("child_process").exec("calc") : 1) להחזיר 1, ובכך למנוע מ-MongoDB להראות שגיאה. כתוצאה מכך, השאילתה מבוצעת בשרת MongoDB ללא בעיות.
עם זאת, כאשר אותו ערך מגיע לפונקציית sift() , אשר פועלת בשרת היישומים שבו המשתנה "global" זמין, היא מפעילה את יצירת הפונקציה הבאה:

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


הסרטון מדגים את הוכחת ההיתכנות עבור CVE-2024-53900 המשפיע על גרסאות Mongoose קודמות לגרסה 8.8.3, שחסרות בהן אימות קלט מתאים כדי למנוע שימוש לרעה באופרטור $where לצד ספריית sift .
תיקון לא שלם ו-CVE-2025-23061
בהתבסס על דוח האבטחה של דאט פונג, Mongoose הציגה תיקון שמטרתו לפתור את הפגיעות שזוהתה בעבר (CVE-2024-53900) לפני חשיפתה לציבור. התיקון הרלוונטי ( Automattic/mongoose@33679bc ) הוסיף בדיקה כדי לאסור שימוש ב- $where בתוך המאפיין match שהועבר ל- populate() .

קטע זה בודק האם המאפיין match שהועבר ל-populate() הוא מערך. אם כן, הקוד עובר על כל אובייקט במערך כדי לראות אם הוא מכיל את האופרטור $where . אם מזוהה $where , נוצרת שגיאה, המונעת מהמטען הזדוני להתפשט לפונקציית sift() המסוכנת.
כתוצאה מכך, המטען המנצל את CVE-2024-53900 נכשל בבדיקה זו מכיוון שאובייקט במערך ההתאמה מכיל את $where , מה שחוסם אותו למעשה מלהגיע לפונקציה sift() .

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


כתוצאה מכך, תוקף יכול לקנן $where מתחת ל- $or כדי להתחמק מבדיקת ה-single-level של התיקון. מכיוון ש-Mongoose בודק רק את המאפיינים ברמה העליונה של כל אובייקט במערך ההתאמה, מטען העקיפה נותר בלתי מזוהה ובסופו של דבר מגיע לספריית ה-sift, מה שמאפשר את ה-RCE הזדוני.

הוכחת היתכנות עבור CVE-2025-23061
כדי להמחיש את אופיו הלא שלם של התיקון, דאט פונג בנה מחדש את יישום הדוגמה באמצעות גרסה של Mongoose 8.9.4 (מאוחרת יותר מ-8.8.3). על ידי קינון $wher e בתוך פסוקית $or , תוקף יכול לעקוף בהצלחה את הבדיקה ולהשיג RCE.
פרצת הוכחת ההיתכנות מדגימה כיצד ניתן להפעיל את CVE-2025-23061 בגרסאות Mongoose קודמות לגרסה 8.9.5, מה שמאפשר לתוקף לבצע קוד שרירותי בשרת:
הפחתה והנחיה
כדי לצמצם את הפגיעויות שדנו בהן לעיל, אנא ודא שהמערכת שלך מעודכנת לגרסה העדכנית ביותר של Mongoose.
MetaDefender Core שימוש במנוע SBOM יכול לזהות פגיעות זו
Core OPSWAT MetaDefender , מצוידת ב- SBOM מתקדמת ( Software יכולות (רשימת חומרים), מאפשרות לארגונים לנקוט בגישה פרואקטיבית להתמודדות עם סיכוני אבטחה. על ידי סריקת יישומי תוכנה והתלויות שלהם, MetaDefender Core מזהה פגיעויות ידועות, כגון CVE-2024-53900 ו-CVE-2025-23061, בתוך הרכיבים המפורטים. זה מאפשר לצוותי פיתוח ואבטחה לתעדף מאמצי תיקון נתונים, תוך הפחתת סיכוני אבטחה פוטנציאליים לפני שניתן לנצל אותם על ידי גורמים זדוניים.
להלן צילום מסך של CVE-2024-53900 ו-CVE-2025-23061, אשר זוהו על ידי MetaDefender Core עם SBOM:

בנוסף, ניתן לזהות את אירועי ה-CVE גם על ידי MetaDefender Software Supply Chain , אשר ממנפת את MetaDefender Core עם SBOM כדי לזהות את הפגיעויות הללו.


