十個(gè)關(guān)于攻擊CI/CD通道的場(chǎng)景
對(duì)于針對(duì)持續(xù)集成和持續(xù)交付/持續(xù)部署(CI/CD)通道的網(wǎng)絡(luò)攻擊,攻擊者和防御者都越來越明白,構(gòu)建通道是具有重大攻擊面的高權(quán)限目標(biāo)。
但是CI/CD通道的潛在攻擊面是什么呢?這種類型的攻擊實(shí)際是什么樣的呢?NCC 組織通過不同的安全評(píng)估發(fā)現(xiàn)了許多攻擊路徑,這些路徑可能導(dǎo)致大型和小型企業(yè)的CI/CD通道遭到攻擊。
在這篇文章中,我們通過展示可能的被利用通道上的許多不同類型的攻擊,強(qiáng)調(diào)保護(hù)軟件供應(yīng)鏈的重要性。
Jenkins潛藏多個(gè)攻擊面
從S3桶開始發(fā)起攻擊
S3桶中常見的錯(cuò)誤配置經(jīng)常會(huì)導(dǎo)致整個(gè)DevOps環(huán)境的攻擊。最初的攻擊途徑是通過一個(gè)web應(yīng)用程序。該攻擊方案的攻擊流程包括:
Web應(yīng)用-> S3桶上的目錄列表->腳本文件中的硬編碼Git憑據(jù)-> Git訪問->使用相同的硬編碼Git憑據(jù)訪問Jenkins -> Dump憑據(jù)從Jenkins ->橫向移動(dòng)->游戲結(jié)束->事件->內(nèi)部調(diào)查
NCC組織對(duì)一個(gè)面向網(wǎng)絡(luò)的web應(yīng)用程序進(jìn)行了匿名訪問的黑盒web應(yīng)用程序評(píng)估。在測(cè)試開始時(shí),在一個(gè)網(wǎng)站地圖文件夾中發(fā)現(xiàn)了一個(gè)網(wǎng)站地圖文件。sitemap文件夾是一個(gè)S3桶,啟用了目錄列表。在查看S3存儲(chǔ)桶中的文件時(shí),發(fā)現(xiàn)了一個(gè)bash shell腳本。經(jīng)過仔細(xì)檢查,我們發(fā)現(xiàn)了一個(gè)帶有證書的硬編碼的git命令。該證書允許NCC集團(tuán)顧問作為受限用戶訪問Jenkins Master web登錄界面,該界面只能在內(nèi)部訪問,而不能從互聯(lián)網(wǎng)訪問。在點(diǎn)擊幾下鼠標(biāo)并在其中四處查看之后,他們能夠切換到一個(gè)管理員帳戶。憑借管理員權(quán)限,該顧問在腳本控制臺(tái)中使用了 Groovy 單行代碼,并轉(zhuǎn)儲(chǔ)了大約 200 個(gè)不同的憑據(jù),例如 AWS 訪問令牌、SAST/DAST 令牌、EC2 SSH 證書、Jenkins 用戶和其他 Jenkins 憑據(jù)。評(píng)估結(jié)束時(shí),客戶與顧問密切合作進(jìn)行事件響應(yīng)以進(jìn)行補(bǔ)救。
NCC 為客戶提供了一份詳細(xì)的報(bào)告,其中包含修復(fù)和強(qiáng)化步驟,其中一些推薦步驟如下:
1.刪除S3的目錄列表;
2.刪除shell腳本文件和硬編碼憑據(jù);
3.刪除允許任何擁有 GitHub 訪問權(quán)限的人都可以訪問 Jenkins 的連接;
4.安裝和審查審計(jì)跟蹤和作業(yè)配置歷史插件;
5.在我們現(xiàn)場(chǎng)測(cè)試的情況下,不應(yīng)該通過互聯(lián)網(wǎng)訪問Jenkins;
6.更改和降低Jenkins帳戶擁有的權(quán)限;
7.為管理員帳戶部署和使用MFA;
強(qiáng)化環(huán)境中的權(quán)限升級(jí)
顧問在不同評(píng)估中發(fā)現(xiàn)的另一條權(quán)限升級(jí)路徑的步驟如下:
使用 SSO 憑據(jù)登錄 -> 測(cè)試分離、鎖定和記錄的角色 -> 一個(gè)具有構(gòu)建/重播代碼執(zhí)行的角色 -> 憑據(jù)轉(zhuǎn)儲(chǔ)
評(píng)估的目的是審查一個(gè)新實(shí)現(xiàn)的強(qiáng)化Jenkins環(huán)境,該環(huán)境包含使用最小權(quán)限原則創(chuàng)建的記錄用戶角色。Jenkins在非root用戶下運(yùn)行,最新版本的核心和插件,具有SSL認(rèn)證和SSO,使用MFA進(jìn)行登錄。NCC 組織顧問每天訪問一個(gè)具有特定角色的用戶,并測(cè)試是否存在任何權(quán)限升級(jí)路徑。
構(gòu)建器角色也具有構(gòu)建/重播權(quán)限,這允許使用修改過的腳本或額外的Groovy代碼重播Pipeline構(gòu)建,而不僅僅是構(gòu)建作業(yè)的構(gòu)建權(quán)限。這允許NCC 組織顧問運(yùn)行Groovy代碼并轉(zhuǎn)儲(chǔ)Jenkins用戶的憑據(jù)和其他秘密。
插件中令人困惑的語言表達(dá)
最后一個(gè)途徑是在Jenkins插件中發(fā)現(xiàn)的一個(gè)令人困惑的選項(xiàng),它導(dǎo)致了完全開放的訪問:
GitHub 授權(quán) -> 具有讀取權(quán)限的經(jīng)過身份驗(yàn)證的 Git 用戶 -> 使用 Gmail 帳戶的 Jenkins 訪問權(quán)限
GitHub OAuth 插件部署在 Jenkins 中,提供身份驗(yàn)證和授權(quán)。勾選了“向所有經(jīng)過身份驗(yàn)證的用戶授予讀取權(quán)限”和“使用 GitHub 存儲(chǔ)庫權(quán)限”選項(xiàng),允許任何擁有 GitHub 帳戶的人(甚至是外部用戶)訪問 Jenkins Web 登錄 UI。 NCC 能夠注冊(cè)并使用他們自己的托管電子郵件帳戶來訪問他們的項(xiàng)目。
GitLab CI/CD通道攻擊
NCC集團(tuán)已經(jīng)做了很多工作,研究了另一個(gè)眾所周知的被使用的工具GitLab。因此,NCC 組織顧問發(fā)現(xiàn)了一些有趣的攻擊路徑。
利用受保護(hù)的分支
在一項(xiàng)特定的工作中,GitLab runner的設(shè)置存在多個(gè)主要漏洞。第一個(gè)主要漏洞是,runner使用了權(quán)限容器,這意味著它們被配置為使用“-privileged”標(biāo)志,這將允許它們啟動(dòng)其他可以輕易逃逸到主機(jī)的特權(quán)容器。這是一個(gè)非常簡(jiǎn)單的攻擊媒介,可以讓你到達(dá)主機(jī)。但有趣的是,這些GitLab runner也共享runner,而不是孤立的。一位只應(yīng)該將代碼推送到某個(gè)存儲(chǔ)庫的開發(fā)人員也可以訪問機(jī)密和高權(quán)限存儲(chǔ)庫。此外,這些共享運(yùn)行程序使用的是存儲(chǔ)高度敏感秘密(如身份驗(yàn)證令牌和密碼)的普通環(huán)境變量。對(duì)存儲(chǔ)庫具有有限的推送訪問權(quán)限的用戶可以獲得高度權(quán)限的機(jī)密。
受保護(hù)的分支是可以由GitLab中具有維護(hù)者角色的人維護(hù)的分支,只有這些人具有推送這些源代碼存儲(chǔ)庫或分支的權(quán)限,并且有一個(gè)與之關(guān)聯(lián)的更改請(qǐng)求 (CR) 鏈。這些受保護(hù)的分支可以與受保護(hù)的運(yùn)行程序相關(guān)聯(lián)。你可以將其鎖定,因此開發(fā)人員必須獲得 CR 批準(zhǔn)才能推送代碼。但在這種情況下,沒有實(shí)施和執(zhí)行 CR 和受保護(hù)的分支。任何人都可以推送到未受保護(hù)的分支,然后鏈接以前的漏洞利用。這 4-5 個(gè)漏洞的鏈接提供了所有訪問權(quán)限。
也有很多不同的路徑。即使使用了“-privileged”標(biāo)志,也有另一條路徑可以訪問特權(quán)容器。操作人員需要能夠運(yùn)行docker命令。主機(jī)的docker守護(hù)進(jìn)程與GitLab共享Runner共享。這導(dǎo)致了對(duì)主機(jī)的訪問和在容器之間的切換。
顧問要求客戶了解并幫助糾正這些問題,但很想了解導(dǎo)致作出這些選擇的根本原因。他們?yōu)槭裁醋龀鲞@些配置選擇,他們考慮了哪些權(quán)衡?除了這些選擇,還有什么更安全的選擇呢?他們知道這些選項(xiàng)嗎?如果知道,為什么不選擇他們?
公司想要權(quán)限容器的原因是對(duì)被推送的代碼進(jìn)行靜態(tài)分析,顧問解釋說,他們應(yīng)該使用隔離的runner,而不是使用共享的runner,并且應(yīng)該有進(jìn)一步的訪問控制限制。要注意的是,可以運(yùn)行權(quán)限容器,但仍然可以在一定程度上限制暴露的敏感信息的數(shù)量。
GitLab執(zhí)行作業(yè)的許多CI/CD安全機(jī)制依賴于這樣一個(gè)前提,即受保護(hù)的分支只包含受信任的構(gòu)建作業(yè)和由項(xiàng)目維護(hù)者管理的內(nèi)容。項(xiàng)目維護(hù)者權(quán)限級(jí)別或更高級(jí)別的用戶可以委托其他用戶管理和推送到特定的受保護(hù)分支。這些有權(quán)限的用戶是表示項(xiàng)目中什么是可信的,什么是不可信的網(wǎng)關(guān)。進(jìn)行這種區(qū)分對(duì)于緩解對(duì)不可信構(gòu)建作業(yè)的權(quán)限暴露非常重要。
使用權(quán)限容器的GitLab runner
在另一個(gè)操作中,GitLab runner被配置為使用Docker的“—privileged”標(biāo)志執(zhí)行CI/CD作業(yè)。這個(gè)標(biāo)志將否定Docker提供的任何安全隔離,以保護(hù)主機(jī)免受潛在的不安全容器的攻擊。通過禁用這些安全功能,容器進(jìn)程可以通過各種功能將其權(quán)限升級(jí)到主機(jī)上的root權(quán)限。一些工具被打包成Docker映像,為了支持這一點(diǎn),客戶端在Docker (DIND)中使用一個(gè)權(quán)限容器中的Docker來執(zhí)行嵌套的容器。
如果有權(quán)限的CI/CD作業(yè)是必要的,那么相應(yīng)的runner應(yīng)該配置為只在已知合法的受保護(hù)的項(xiàng)目分支上執(zhí)行。這將防止任意攻擊人員提交可能導(dǎo)致主機(jī)被攻擊的未經(jīng)審查的腳本。維護(hù)者角色管理項(xiàng)目受保護(hù)分支的能力意味著他們控制由相關(guān)受保護(hù)的Runner提供的任何權(quán)限。
高權(quán)限共享Runner可能會(huì)請(qǐng)求與敏感環(huán)境變量和權(quán)限Kubernetes環(huán)境相關(guān)的工作
權(quán)限運(yùn)行程序不應(yīng)配置為共享運(yùn)行程序或廣泛作用域組,相反,它們應(yīng)該根據(jù)特定項(xiàng)目或組的需要進(jìn)行配置,這些項(xiàng)目或組被認(rèn)為在維護(hù)者級(jí)別或更高級(jí)別的用戶之間具有相同的權(quán)限級(jí)別。
Runner將秘密暴露給不可信的CI/CD作業(yè)
運(yùn)行程序調(diào)用API終端,這些終端使用各種令牌和密碼進(jìn)行身份驗(yàn)證。因?yàn)檫@些是共享Runner,任何有權(quán)限向Gitlab提交源代碼的用戶都可以輕松地訪問身份驗(yàn)證令牌和密碼。Runner被配置為通過環(huán)境變量公開秘密。秘密管理,特別是CI/CD通道的秘密管理是一個(gè)難以解決的問題。
要緩解這些類型的風(fēng)險(xiǎn),請(qǐng)確保由runner在所有構(gòu)建作業(yè)中配置的環(huán)境變量不包含任何權(quán)限憑據(jù)。可以使用適當(dāng)作用域的GitLab變量作為替換。環(huán)境變量應(yīng)該只包含信息配置值,應(yīng)該認(rèn)為相關(guān)項(xiàng)目和組中的任何被利用人員都可以訪問這些配置值。
如果 Runner 必須通過環(huán)境變量或掛載的卷為其作業(yè)提供憑據(jù),那么Runner應(yīng)該限制它們所暴露的工作負(fù)載。為此,此類 Runner應(yīng)僅與最具體的可能項(xiàng)目/組相關(guān)聯(lián)。此外,它們應(yīng)該被標(biāo)記為“受保護(hù)的”,以便它們只能處理受保護(hù)的分支上的作業(yè)。
主機(jī)Docker守護(hù)進(jìn)程暴露給共享的GitLab Runner
在一次操作中,Gitlab共享Runner在運(yùn)行時(shí)將主機(jī)的Docker套接字掛載到CI/CD作業(yè)容器中。雖然這允許合法的開發(fā)人員為了構(gòu)建目的在主機(jī)上運(yùn)行任意Docker命令,但它也允許構(gòu)建作業(yè)在主機(jī)上部署權(quán)限容器,以逃避它們的約束。這也為攻擊者提供了一個(gè)窗口,通過這個(gè)窗口他們可以攻擊在主機(jī)上運(yùn)行的其他構(gòu)建作業(yè)。本質(zhì)上,這否定了Docker所提供的所有隔離,阻止被包含的進(jìn)程訪問其他容器和主機(jī)。在這種情況下,建議采取以下緩解措施:
1.不允許開發(fā)人員直接與不受其控制的主機(jī)上的 Docker 守護(hù)進(jìn)程交互??紤]使用支持無根 Docker 構(gòu)建的工具(例如 kaniko)運(yùn)行 Docker 構(gòu)建作業(yè)。
2.開發(fā)一個(gè)進(jìn)程,在源代碼存儲(chǔ)庫上運(yùn)行一組靜態(tài) Docker 命令來構(gòu)建它們。此過程不應(yīng)在 CI/CD 作業(yè)本身內(nèi)執(zhí)行,因?yàn)樽鳂I(yè)腳本是用戶定義的,并且可以覆蓋命令。
3.如果這必須通過 CI/CD 作業(yè)來實(shí)現(xiàn),那么在這些 Runner上執(zhí)行的構(gòu)建作業(yè)應(yīng)該被視為特權(quán),因此應(yīng)該限制 Docker Runner接受提交了保護(hù)和已知的安全存儲(chǔ)庫以確保任何用戶定義的CI / CD工作已經(jīng)通過了正式的審批程序。
Kubernetes
運(yùn)行特定功能的pod有時(shí)會(huì)使用不同的pod身份驗(yàn)證機(jī)制,這些機(jī)制可以連接到各種服務(wù),AWS憑據(jù)就是一個(gè)例子。很多時(shí)候,人們使用插件,并不限制插件周圍的API路徑。例如,Kube2IAM是一個(gè)經(jīng)常看到的插件,如果你沒有從pod中正確地配置它,你可以獲得權(quán)限容器,它可以導(dǎo)致具有特權(quán)API憑據(jù),讓你看到底層主機(jī)正在做什么。
Kube2IAM
Kube2IAM 使用 pod 注釋。它攔截來自容器 pod 對(duì) AWS API (169254) 的調(diào)用。 NCC 組織的一位顧問發(fā)現(xiàn)了一個(gè)有趣的情況,每個(gè)開發(fā)人員都可以對(duì) pod 進(jìn)行注釋。在 Kube2IAM 使用的 AWS 角色中,有一個(gè)使用“sts assume-role *”行配置的設(shè)置。這使得任何能夠創(chuàng)建/注釋pod的被利用人員都繼承了AWS的管理員角色。這意味著任何可以創(chuàng)建任意pod 并指定注釋的人都可以獲得一家銀行的AWS主工具帳戶的管理權(quán)限。此帳戶配置了 VPC 對(duì)等互連,可以查看任何 pod 和非 pod 環(huán)境。你可以使用該訪問權(quán)限到達(dá)任何地方。這是一個(gè)構(gòu)建 pod 的通道,攻擊者所要做的就是在最后輸出一些東西的注釋中添加一個(gè)注釋。
NCC組織的一位顧問還進(jìn)行了另一項(xiàng)類似的工作,在這種情況下,他們無法對(duì) pod 進(jìn)行注釋。相反,在 Kube2IAM 中有標(biāo)記“白名單路由正則表達(dá)式”,你可以提及 AWS API 路徑。你可以指定你想去或不去的路徑,DevOps管理員已經(jīng)將其配置為一個(gè)白色字符,允許某人訪問權(quán)限路徑,從而導(dǎo)致底層節(jié)點(diǎn)憑據(jù)。
利用筆記本電腦發(fā)起攻擊
NCC 組織顧問進(jìn)行了基于場(chǎng)景的評(píng)估——利用開發(fā)人員的筆記本電腦。
顧問所能做的就是將代碼提交到使用 Maven 項(xiàng)目的單個(gè) Java 庫中。他們將一個(gè)前置需求文件設(shè)置為一個(gè)任意文件,該文件將提供來自構(gòu)建環(huán)境的 shell。他們將其更改為反向 Meterpreter shell 有效負(fù)載。他們發(fā)現(xiàn) pod 有一個(gè) SSH 密鑰位于磁盤上,該密鑰進(jìn)入 Jenkins 主節(jié)點(diǎn),然后從 Jenkins 中轉(zhuǎn)儲(chǔ)了所有變量。然后他們發(fā)現(xiàn)這是一個(gè)真正的部署通道,它擁有寫入權(quán)限和集群管理到Kubernetes工作負(fù)載中。因此,他們現(xiàn)在可以訪問完整的生產(chǎn)環(huán)境。
在另一項(xiàng)操作中,NCC 組織顧問成功攻擊了一個(gè)用戶帳戶,并訪問了經(jīng)過驗(yàn)證的通往被利用團(tuán)隊(duì)的通道。在通道中運(yùn)行自定義代碼是不可能的,但是他們可以告訴通道構(gòu)建一個(gè)不同的分支,即使它不存在。通道崩潰并轉(zhuǎn)儲(chǔ)環(huán)境變量。其中一個(gè)環(huán)境變量是Windows域管理員帳戶。在該攻擊場(chǎng)景中,他們能夠?qū)A(chǔ)設(shè)施進(jìn)行端口掃描,最終形成一個(gè)構(gòu)建通道。他們發(fā)現(xiàn)了許多功能未知的應(yīng)用程序。其中一個(gè)應(yīng)用程序容易受到服務(wù)器端請(qǐng)求偽造(SSRF)的攻擊,它們運(yùn)行在AWS EC2實(shí)例上。AWS節(jié)點(diǎn)能夠編輯配置映射,允許AWS用戶帳戶和集群內(nèi)角色之間的映射。結(jié)果,這并沒有檢查集群和帳戶是否在同一個(gè)用戶帳戶中。因此,顧問可以指定另一個(gè)AWS帳戶來控制集群,并在Elastic Kubernetes服務(wù)集群(EKS)上擁有管理權(quán)限。
本文翻譯自:https://research.nccgroup.com/2022/01/13/10-real-world-stories-of-how-weve-compromised-ci-cd-pipelines/如若轉(zhuǎn)載,請(qǐng)注明原文地址。