Mongoose 是用於 MongoDB 的物件資料建模 (ODM) 函式庫,可簡化 Node.js 應用程式中的資料庫互動。透過提供基於模式的解決方案,Mongoose 可將 JavaScript 物件映射至 MongoDB 檔案,作為抽象層幫助資料結構化,使管理和驗證更加容易。Mongoose 具備用於自訂邏輯執行的中介軟體和直覺式查詢建置系統等功能,可提升 MongoDB 的工作效率。Mongoose 被形容為「Node.js 的優雅 MongoDB 物件建模」,在 GitHub 上獲得了 27K 顆星星,反映出它在開發人員中的廣泛使用和讚賞。
OPSWAT 研究員計畫與關鍵弱點發現
OPSWAT 關鍵基礎設施網路安全研究生獎學金計畫以越南為基地,提供研究生保護關鍵基礎設施的實務經驗。作為該計畫的一部分,研究員有機會分析並處理網路安全漏洞,與OPSWAT 專家合作解決惡意軟體偵測、檔案安全和威脅預防等領域的實際挑戰。
在OPSWAT Fellowship 計畫中,參與者有系統地調查和重現各種產品、程式庫和作業系統中已知的 CVE。作為這項計畫的一部分,我們其中一位傑出的研究員 Dat Phung 選擇研究 Mongoose,因為它在生產環境中被廣泛採用。2024 年 11 月,他在對 Mongoose 的函式庫進行深入分析時,發現了該函式庫中的一個重要漏洞。該漏洞允許攻擊者利用$where值,可能導致 Node.js 應用程式伺服器上的遠端程式碼執行 (RCE)。在及時向 Mongoose 報告此問題後,Mongoose 發布了修補程式作為版本 8.8.3 的一部分,並在國家漏洞資料庫(NVD)中披露了 CVE-2024-53900。
CVE-2024-53900 & CVE-2025-23061 時程表
- 2024 年 11 月 7 日: Dat Phung 在 Mongoose 中發現了一個重要漏洞,並向 Snyk 提交了一份安全報告。
- 2024 年 11 月 26 日: Mongoose 發布 8.8.3 版,以處理及修復此漏洞。
- 2024 年 12 月 2 日: 國家漏洞資料庫(NVD)揭露此漏洞的 CVE-2024-53900。
- 2024 年 12 月 17 日:在分析 Mongoose 的 8.8.3 修補程式時,Dat Phung 發現了一個旁路,仍然可以啟用 RCE (遠端執行程式碼)。一份詳細的安全報告已提交給 Tidelift。
- 2025 年 1 月 13 日:Mongoose 發布 8.9.5 版,推出增強修補程式,有效解決繞道問題。
- 2025 年 1 月 15 日:國家漏洞資料庫(NVD)正式揭露 CVE-2025-23061,強調新發現漏洞的嚴重性。
Mongoose 的 Populate() 方法
Mongoose 還提供了一個叫做 populate() 的有用功能,它增強了處理檔案之間關係的能力。雖然 MongoDB ≥ 3.2 版本有 $lookup 彙集運算符用於連接,但 Mongoose 的 populate() 提供了更強大的替代功能,可將引用自動替換為相關檔案中的相應資料。這對於管理不同 MongoDB 集合之間的關係特別有用,例如當一個檔案透過 _id 來引用另一個檔案時。[2]
在 Mongoose 中定義模式時,可以使用 ref 選項設定欄位參考另一個模型。然後,populate()方法會用相關模型的完整檔案來取代被引用的欄位(ObjectId)。例如,在書店應用程式中,bookSchema中的 author 欄位會參考Author檔案,而review 欄位則會參考Reviews檔案。populate() 方法可讓開發人員在查詢書籍模型時,以完整的Author檔案取代author欄位(它是一個 ObjectId)。
populate() 允許開發人員在查詢書籍模型時,以完整的Author檔案取代author欄位 (這是一個 ObjectId):
此外,Mongoose 的 populate() 方法支援自訂查詢,以定義擷取哪些相關檔案以及擷取的方式。匹配和選項等屬性允許開發人員過濾、排序、限制和跳過相關檔案,提供靈活的資料擷取功能。
CVE-2024-53900 分析
作為OPSWAT 網路安全研究生獎學金計畫的一部分,Dat Phung 在分析 Mongoose 以重現已知 CVE 的同時,對 populate() 方法的內部運作進行了全面的檢閱,該方法在處理 MongoDB 檔案之間的關係時扮演了關鍵的角色。populate() 方法支援字串和物件參數,開發人員可以使用 match 選項,對擷取的資料套用特定的篩選條件:
在上面的範例中,match 選項是一個可以包含 MongoDB 查詢運算符的過濾器物件,詳情請參閱Query and Projection Operators - MongoDB Manual v8.0。其中一個值得注意的操作符是$where,它可以讓 JavaScript 直接在 MongoDB 伺服器上執行。但是,這種在 MongoDB 伺服器上的執行是受限制的,僅支援基本的操作和函式。
Dat Phung 對 Mongoose 原始程式碼進行了深入分析,以瞭解populate()方法的工作流程。他確定應用程式在模型上呼叫 populate()方法後,會觸發 populate() 函式。在此函式中,Mongoose 會呼叫 _execPopulateQuery() 函式,該函式會在 MongoDB 伺服器上以$where運算子執行查詢。隨後,所有來自外部集合的檔案都會被擷取,以便在接下來的步驟中進行填充。
從 MongoDB 擷取資料後,Mongoose 會執行回呼函式_done(),該函式會呼叫_assign()來準備資料,然後透過呼叫assignVals()函式「結合」兩個模型。
當 Mongoose 的assignVals() 函式處理擷取的資料時,可能會產生此漏洞。此函式會檢查匹配選項是否為陣列,若是,則會將每個運算符號傳給sift()函式。sift() 函數是從同名的外部函式庫匯入,在應用程式伺服器的本機處理這些查詢。本機處理會帶來安全風險,尤其是在處理使用者控制的輸入時。
為了進一步研究這一點,Dat Phung 修改了 match 選項中的值,以確保滿足條件,從而調用sift() 函數對資料流進行額外分析。
條件就緒後,$where運算符隨後被傳給sift()函式。
sift 函式庫是一個輕量級的 JavaScript 工具程式,設計用來使用類似 MongoDB 的語法過濾和查詢資料集合,例如陣列或 JSON 物件。根據官方檔案,「Sift 是一個用於在 JavaScript 中使用 MongoDB 查詢的微小函式庫」。sift()函式會在應用程式伺服器上評估類似 MongoDB 的篩選操作,而非在資料庫伺服器上評估,因此在處理不受信任的輸入時,系統可能會曝露在重大的安全風險中。
繼續分析之後,我們的研究員在 sift 函式庫的createDefaultQueryTester()函式中發現了一個問題。這個函式會將 match 陣列中的每個操作轉換成可執行的 JavaScript 函式,然後用來在本機過濾和處理 MongoDB 檔案資料。為了達到這個目的,createDefaultQueryTester()會呼叫createNamedOperation()函式,並傳入 match 陣列中的$where等操作作為參數。
對於匹配陣列中的每個操作,createNamedOperation 會檢查是否支援該操作,然後將其傳給對應的函式。
如果操作為$where,則會使用原始「params」值產生 JavaScript 函式,該函式來自 match 陣列中的$where運算符,且可由使用者控制。
CVE-2024-53900:攻擊細節
雖然 MongoDB 透過$where操作限制 JavaScript 函式的執行,但如先前所分析的,sift()函式允許這些函式在沒有這些限制的情況下執行。這種缺乏輸入驗證及限制的情況會引發重大的安全漏洞,因為「params」值直接由使用者輸入所控制,因此可能會被利用,導致程式碼注入攻擊。為了更徹底地檢查這個問題,Dat Phung 建立了以下查詢:
起初,查詢無法執行另一個程序,導致以下錯誤:
此錯誤表示 Mongoose 嘗試在將控制權傳遞給 sift() 函式之前,在 MongoDB 伺服器上執行$where操作。但是,由於 MongoDB 的$where子句對 JavaScript 函式有限制,因此發生錯誤,導致查詢無法執行。因此,Mongoose 會在到達sift() 函式之前停止處理。
為了繞過這個限制,我們的研究員利用了應用程式伺服器上的 "global "變數,而這個變數在 MongoDB 伺服器上並不存在。這種方法讓他繞過了 MongoDB 伺服器上的限制,並使查詢能夠到達sift()函式:
使用此值,當 Mongoose 在 MongoDB 上執行$where操作時,由於沒有 "global「 變數,三元運算符號(typeof global != 」undefined" ? global.process.mainModule.constructor._load("child_process").exec("calc") :1)返回 1,防止 MongoDB 拋出錯誤。因此,查詢可以在 MongoDB 伺服器上順利執行。
但是,當相同的值到達在應用程式伺服器上執行的 sift()函式(該函式在 "global "變數可用的地方執行)時,會觸發以下函式的建立:
遠端執行程式碼 (RCE) 概念驗證
在文章開頭提供的應用程式範例中,如果攻擊者傳送以下要求,他們就可以成功執行遠端執行程式碼 (RCE) 攻擊:
該視訊示範了 CVE-2024-53900 的概念驗證,此 CVE-2024-53900 會影響 8.8.3 之前的 Mongoose 版本,該版本缺乏適當的輸入驗證以防止與sift函式庫一起濫用$where運算符。
不完整修復與 CVE-2025-23061
根據 Dat Phung 的安全報告,Mongoose 在公開揭露之前,已推出修補程式,以解決先前發現的漏洞 (CVE-2024-53900)。相關修補程式(Automattic/mongoose@33679bc) 新增檢查,禁止在傳給populate() 的 match 屬性中使用$where。
此片段檢查傳入 populate() 的 match 屬性是否為陣列。如果是,程式碼會遍歷陣列中的每個物件,看看它是否包含 $where運算符號。如果偵測到$where,就會產生錯誤,以防止惡意的 payload 傳播到有風險的 sift() 函式。
因此,利用 CVE-2024-53900 的有效負載無法通過此檢查,因為匹配陣列中的物件包含$where,因此有效地阻止它到達sift()。
雖然這個更新正確地阻止了$where在單一嵌套層級內的直接使用,但卻無法偵測到嵌入在 $or運算符內的$where - 這是 MongoDB 和 sift 函式庫都完全支援的結構。
因此,攻擊者可以將$where嵌套在$or 之下,以逃避修補程式的單層檢查。由於 Mongoose 只會檢查匹配陣列中每個物件的頂層屬性,因此繞過的有效負載仍未被偵測到,並最終到達 sift 函式庫,使惡意 RCE 得以實現。
CVE-2025-23061 的概念驗證
為了說明修正的不完整性,Dat Phung 使用 Mongoose 8.9.4 (比 8.8.3 遲) 版本重建範例應用程式。透過將$where嵌套在 $or子句內,攻擊者可成功繞過檢查並達成 RCE。
此概念驗證漏洞利用示範了如何在 8.9.5 之前的 Mongoose 版本中觸發 CVE-2025-23061,允許攻擊者在伺服器上執行任意程式碼:
緩解與指導
為了減緩我們上面討論的漏洞,請確保您的系統已更新至最新版本的 Mongoose。
使用 SBOM 引擎的MetaDefender Core 可偵測此漏洞
OPSWAT MetaDefender CoreMetaDefender Core 配備先進的SBOM軟體物料清單)功能,可讓組織採取主動的方式來處理安全風險。透過掃描軟體應用程式及其相依性,MetaDefender Core 可辨識列出元件中的已知漏洞,例如 CVE-2024-53900 和 CVE-2025-23061。這有助於開發和安全團隊優先進行修補工作,在惡意行為者利用這些漏洞之前減輕潛在的安全風險。
以下是MetaDefender Core 使用 SBOM 檢測到的 CVE-2024-53900 和 CVE-2025-23061 的截圖:
此外,CVE 也可以透過 MetaDefender Software Supply Chain,利用MetaDefender Core 與 SBOM 識別這些漏洞。