什麼是中毒管道執行 (PPE)?

中毒管道執行 (Poisoned pipeline execution, PPE) 是 OWASP CI/CD 安全風險之一,是濫用原始碼管理 (SCM) 系統存取權限的攻擊媒介,目的是導致 CI 管道執行惡意指令。雖然 PPE 攻擊者無法存取建立環境,但他們已取得 SCM 的存取權,這使他們能夠將惡意程式碼注入建立管道組態,以操控建立程序。

 

CICD-SEC-4:中毒管道執行說明

中毒式管道執行 (Poisoned pipeline execution,PPE) 在 OWASP 的十大 CI/CD 安全風險中被列為 CICD-SEC-4,代表著針對持續整合與持續部署 (CI/CD) 系統的複雜攻擊策略。

客戶可能有多種選擇:

在 PPE 策略中,攻擊者會在 CI/CD 管道的 CI 部分中執行惡意程式碼,繞過直接存取 CI/CD 系統的需要。此方法涉及針對程式碼管理 (SCM) 儲存庫操作權限。透過變更 CI 設定檔案或 CI 管道作業所依賴的其他檔案,攻擊者可注入惡意指令,有效毒化 CI 管道,並使未經授權的程式碼得以執行。

成功的 PPE 攻擊可以實現廣泛的作業,所有作業都是在管道的身分範圍內執行。惡意作業可能包括存取 CI 作業可用的機密、存取作業節點有權限的外部資產、將看似合法的程式碼和工件運送至管道,以及存取作業節點網路或環境中的其他主機和資產。

鑑於其重要影響、低可偵測性,以及存在多種威脅偵測技術,PPE 攻擊構成了廣泛的威脅。對於安全性團隊、工程師和紅隊人員而言,瞭解 PPE 及其對策對 CI/CD 安全性至關重要

定義管道執行

在持續整合 (CI) 的情境中,管道執行流程是指由管道建置的儲存庫中託管的 CI 配置檔案所定義的作業順序。此檔案概述執行工作的順序,並詳細說明會影響流程的建立環境設定和條件。當觸發時,管道作業會從選取的來源 (例如 commit/分支) 抓取程式碼,並針對該程式碼執行 CI 配置檔中指定的指令。

管道中的指令可直接由 CI 配置檔案啟用,或間接由 CI 配置檔案中引用的獨立檔案中的腳本、程式碼測試或線程啟用。CI 設定檔案通常具有一致的名稱和格式,例如 Jenkinsfile (Jenkins)、.gitlab-ci.yml (GitLab)、.circleci/config.yml (CircleCI) 以及位於 .github/workflows 下的 GitHub Actions YAML 檔案。

攻擊者可以直接或間接利用管道執行指令的操控能力,在 CI 中執行惡意程式碼。

如何利用 CICD-SEC-4

要使 PPE 攻擊成功,必須符合幾項嚴重性標準:

  1. 攻擊者必須取得 SCM 儲存庫的權限。這可以是透過使用者憑證、存取權限、SSH 金鑰、OAuth 權限或其他方法。在某些情況下,匿名存取公共儲存庫可能就足夠了。
  2. 對相關儲存庫的變更必須觸發 CI 管道,而無需額外的核准或審查。這可能是透過直接推送到遠端分支,或是透過遠端分支或分叉的拉取請求所建議的變更。
  3. 攻擊者取得的權限必須允許觸發事件,導致執行管道。
  4. 攻擊者可以變更的檔案必須定義管道執行(直接或間接)的指令。
  5. 管道節點必須能存取非公開資源,例如機密、其他節點或計算資源。

執行未審核程式碼的管道,例如由拉取請求或提交至任意程式庫分支所引發的管道,較容易受到 PPE 的影響。一旦攻擊者可以在 CI 管道中執行惡意程式碼,他們就可以在管道的身分上下文中執行惡意作業。

三種中毒管道執行方式

中毒管道執行有三種不同的表現形式:直接 PPE (D-PPE)、間接 PPE (I-PPE) 及公共 PPE (3PE)。

直接 PPE

在直接 PPE 的情況下,攻擊者會修改他們可以存取的儲存庫中的 CI 設定檔,方法是直接將變更推送到儲存庫上未受保護的遠端分支,或是從分支或分叉提交包含變更的拉取請求。管道執行由推送或拉取請求事件觸發,由修改過的 CI 設定檔中的指令定義,一旦觸發建立管道,就會在建立節點中執行惡意指令。

直接中毒管道執行攻擊流程

圖 1:直接中毒管道執行攻擊流程

圖 1 所示的 D-PPE 攻擊範例依序經過以下步驟:

  1. 攻擊者在儲存庫中啟動一個新的遠端分支,以有害的指令變更管道組態檔案,以擷取儲存在 GitHub 組織中的 AWS 認證,並將其傳輸至攻擊者控制的外部伺服器。
  2. 程式碼推送會啟動一個管道,從程式碼儲存庫中拉取程式碼,包括惡意管道組態檔案。
  3. 管道根據配置檔案運作,現在已被攻擊者玷污。惡意指令會命令 AWS 認證(儲存為儲存庫機密)載入記憶體。
  4. 依照攻擊者的指示,管道會執行將 AWS 認證傳輸至攻擊者控制下的伺服器的任務。
  5. 竊取憑證後,攻擊者就有能力滲透生產環境。

間接 PPE

當敵人無法存取 SCM 儲存庫時,就會發生間接 PPE:

  • 如果管道被設定為從同一套件庫中的另一個受保護分支拉取 CI 設定檔案。
  • 如果 CI 設定檔儲存在與原始碼不同的程式碼儲存庫中,而使用者無法直接編輯。
  • 如果 CI 建立是在 CI 系統本身中定義 - 而不是儲存在原始碼中的檔案。

在這些情況下,攻擊者仍可透過將惡意程式碼注入管道組態檔所引用的檔案,例如從管道組態檔內部引用的指令碼、程式碼測試,或 CI 中使用的自動工具 (如內嵌程式和安全掃描程式) 來毒害管道。例如:

  • make 工具會執行 Makefile 檔案中定義的指令。
  • 從管道配置檔內引用的程式碼,這些程式碼與原始碼本身儲存在相同的儲存庫 (例如:python myscript.py - 其中 myscript.py 將會被攻擊者操控)。
  • 代碼測試:在建立過程中,在程式碼上執行的測試 Framework 依賴於專用檔案,與原始碼儲存在同一個程式碼儲存庫中。攻擊者若能操控負責測試的程式碼,就能在建立過程內執行惡意指令。
  • 自動化工具:CI 中使用的 Linters 和安全掃描程式通常依賴駐留在程式碼儲存庫中的組態檔,該組態檔通常會從組態檔內定義的位置載入並執行外部程式碼。

發動間接 PPE 攻擊的攻擊者不是透過直接 PPE 來使管道中毒,而是將惡意程式碼注入組態檔案所引用的檔案中。惡意程式碼最終會在管道節點上執行,並執行檔案中宣告的指令。

間接中毒管道執行攻擊流程

圖 2:間接中毒管道執行攻擊流程

在這個 I-PPE 攻擊範例中,一連串的事件展開如下:

  1. 攻擊者在套件庫中建立拉取請求,將惡意指令附加到 Makefile 檔案。
  2. 由於管道已設定為在針對程式碼儲存庫的任何 PR 時觸發,因此 Jenkins 管道會被觸發,從程式碼儲存庫取得程式碼 - 包括惡意的 Makefile。
  3. 管道會根據儲存在主分支中的設定檔執行。它會進入建立階段,並將 AWS 認證載入原始 Jenkinsfile 中定義的環境變數。然後執行 make build 指令,執行加入 Makefile 的惡意指令。
  4. Makefile 中定義的惡意建立函式會被執行,將 AWS 認證傳送至攻擊者控制的伺服器。
  5. 攻擊者就可以使用竊取的憑證存取 AWS 生產環境。

公共個人防護裝備

Public PPE 是匿名攻擊者在網際網路上執行的一種 PPE 攻擊。公共儲存庫通常允許任何使用者貢獻,通常是透過建立拉取請求。如果公共程式碼儲存庫的 CI 管道執行匿名使用者建議的未審核程式碼,就很容易遭受公共 PPE 攻擊。在易受攻击的公共存储库的管道与私有存储库在相同的 CI 实例上运行的情况下,公共 PPE 还可能暴露内部资产,例如私有项目的机密。

 

CI/CD 中安全管道執行的重要性

透過成功的 PPE 攻擊在 CI 中執行未審查的惡意程式碼,可為攻擊者提供與建立工作相同等級的存取權限和能力:

  • 存取 CI 作業可用的機密,例如注入為環境變數的機密或儲存於 CI 的其他機密。由於 CI/CD 系統負責建立程式碼和部署工件,因此通常包含數十個高價值憑證和令牌,例如到雲端提供商、到工件註冊處,以及到 SCM 本身的憑證和令牌。
  • 存取工作節點有權限的外部資產,例如儲存於節點檔案系統中的檔案,或透過底層主機存取雲端環境的憑證。
  • 能夠以建立程序所建立的合法程式碼為幌子,將程式碼和工件運送至更遠的管道。
  • 能夠存取工作節點網路/環境中的其他主機和資產。

但 組織可以透過安全的管道執行來保護其軟體產品和基礎架構,確保所有編譯、測試和部署的程式碼都是合法且未被竄改的。

與中毒管道執行相關的風險

個人防護裝置可能會造成嚴重性的影響,從未經授權的資料存取、軟體完整性受損、系統中斷,到資料外洩,甚至完全接管系統。這些風險對企業及其客戶都構成重大威脅,突顯出個人防護裝備的重要性。

中毒 CI 管道的下游影響

圖 3:中毒 CI 管道的下游影響

在圖 3 所示的八步供給鏈入侵作業中,攻擊者取得 CI 管道的存取權,並毒害 SaaS 應用程式的元件。透過中毒的元件,攻擊者會在應用程式中建立後門功能,並將中毒的外掛程式傳送至下游用戶端。由於下游組織可能認為中毒套件是合法的,因此他們會將其建構在雲端或內部部署基礎架構中。

從一個中毒的 CI 輸送管道,攻擊者就能創造出進入無數組織的後門存取,從而達到指數級的附帶損害。 SolarWinds 的攻擊就是這種情況。

閱讀更多: CI/CD 管道攻擊剖析

 

預防中毒管道執行

預防和減緩 PPE 攻擊向量涉及跨越 SCM 和 CI 系統的多重措施:

  • 確保執行未審閱程式碼的管道是在隔離的節點上執行,而不是暴露在機密和敏感的環境中。
  • 評估在外部貢獻者的公共儲存庫上觸發管道的需求。在可能的情況下,避免執行源自於 fork 的管道,並考慮加入控制措施,例如要求管道執行必須經過手動核准。
  • 對於敏感的管道,例如暴露於機密的管道,請確保在 CI 系統中設定為觸發管道的每個分支,在 SCM 中都有相關性的分支保護規則。
  • 為了防止竄改 CI 設定檔在管道中執行惡意程式碼,必須在管道執行前審查每個 CI 設定檔。另外,也可以在遠端分支中管理 CI 設定檔案,與包含管道中正在建立的程式碼的分支分開。遠端分支應設定為受保護。
  • 移除不需要的使用者在 SCM 儲存庫上授予的權限。
  • 每條管道都只能存取完成其目的所需的憑證。憑證應具有最低需求的權限。

 

中毒管道執行常見問題集

建立伺服器是執行專案建立程序的機器。它可將原始碼編譯為可執行代碼。
暫存環境是用於測試的生產環境的複製品。它有助於在潛在的錯誤或問題影響到最終使用者之前,將其捕捉到。
線結器是一種分析原始碼的工具,可以標示程式錯誤、Bug、文體錯誤和可疑的結構。如果燒錄器標記出問題,可以設定管道失敗,阻止程式碼進入下一個階段。這有助於組織只部署符合定義的品質標準的程式碼。
Blue/green 部署是一種發行管理策略,透過執行兩個相同的生產環境(命名為 Blue 和 Green)來減少停機時間和風險。在任何時候,只有一個是即時的,即時環境為所有生產流量提供服務。
回滾是在新版本出現問題時,返回軟體應用程式先前版本的過程。這是一項安全措施,可在部署出現問題時確保系統的穩定性。
煙霧測試 (smoke test) 也稱為建立驗證測試 (build verification test),是一種軟體測試類型,包含一組非完整的測試,目的在於確保最重要的功能能正常運作。
金絲雀發行版是一種技術,透過在整個基礎架構推出之前,先慢慢將變更推出給使用者子集,以降低在生產中導入新軟體版本的風險。
基礎架構即程式碼是 透過機器可讀定義檔案,而非實體硬體組態或互動式組態工具,來管理和佈建電腦資料中心的過程。
持續整合是一種開發實務,開發人員會定期將程式碼變更合併到中央儲存庫,然後進行自動化建置和測試。
持續交付是將整個軟體釋出流程自動化的做法。在通過自動化測試後,程式碼變更會自動部署到類似生產環境中,以進一步進行測試和驗證。
部署管道是代碼變更從版本控制到生產環境的路徑。它涉及到建立、測試和部署等階段。
上一頁 什麼是軟體組成分析 (SCA)?