1. 什麼是雲原生安全#
雲計算 -> 雲原生 -> 雲原生安全
了解雲原生安全前首先了解一下雲計算
在雲計算出現之前,軟體的用戶量和數據量較少,可以直接放置到公司的機房中,但是在現在的大數據環境下,傳統的軟體架構已經不適合了,軟體重構和數據遷移又很麻煩,所以就產生了雲計算。
雲計算允許用戶根據需求來獲取資源
雲原生沒有確切的定義,雲原生一直在發展變化之中,解釋權不歸某個人或組織所有
雲原生(CloudNative)是一種構建和運行應用程序的方法,是一套技術體系和方法論
符合雲原生架構的應用程序應該是:採用開源堆棧(K8S+Docker)進行容器化,基於微服務架構提高靈活性和可維護性,借助敏捷方法、DevOps 支持持續迭代和運維自動化,利用雲平台設施實現彈性伸縮,動態調度,優化資源利用率
雲原生四要素:
- 微服務
- 容器化
- DevOps
- 持續交付
簡單理解雲原生:軟體應用服務在上雲的過程中為了適應雲的一種技術架構
對於雲原生,依舊存在傳統的安全問題,如:DDOS 攻擊,web 入侵等
除此之外,雲原生還處在以下問題:
- API 安全
- 容器安全
- 缺乏集中管理
- 排查困難
2. 什麼是容器安全#
在雲原生生態中有很多不同的容器,下面以 Docker 為例進行分析
2.1 Docker 自身安全漏洞#
- 在 CVE 官方記錄中 Docker 的歷史版本中已存在 20 + 漏洞,包括代碼執行,權限提升,信息洩露等
- Docker 源碼安全
- Docker hub 安全
2.2 Docker 架構缺陷#
- 容器間的局域網攻擊
- DDOS 攻擊耗盡資源
- 有漏洞的系統調用
- 共享 root 用戶權限
3. 容器安全#
3.1 針對容器化開發測試過程中的攻擊#
背景
- docker cp 命令
docker cp 命令用於在 Docker 創建的容器與宿主機文件系統間進行文件或目錄複製
- 符號鏈接
符號鏈接(軟鏈接),類似於 Windows 上的快捷鍵
CVE-2018-15664 - 符號鏈接替換漏洞
影響版本:Docker 17.06.0-ce~17.12.1-ce:rc2
,18.01.0-ce~18.06.1-ce:rc2
漏洞原理:CVE-2018-15664 實際上是一個 TOCTOU (time-of-check to time-of-use) 的問題,屬於競態條件漏洞。
簡單來說,程序在對某對象進行安全檢查(如:用戶執行 docker cp 命令後,Docker 守護進程會對給出的複製路徑進行檢查)和使用該對象的步驟之間存在間隙,攻擊者可以先構造一個能夠通過安全檢查的對象,然後立即使用惡意對象替換之前的合法對象,這樣,目標程序真正使用的是替換後的惡意對象(在用 docker cp 命令的時候,替換符號鏈接,可導致目錄穿越)
漏洞復現:利用 metarget 快速搭建 CVE-2018-15664 環境
CVE-2019-14271 - 加載不受信任的動態鏈接庫
影響版本:Docker 19.03.x before 19.03.1
漏洞原理:docker cp 命令依賴 docker-tar 組件會加載容器內部的 nsswitch 動態鏈接庫,攻擊者可以通過劫持容器內部的 nsswitch 來實現代碼注入,獲得宿主機上的 root 權限的代碼執行能力
漏洞利用過程如下:
- 找出 docker-tar 具體會加載那些容器內的動態鏈接庫
- 下載對應的動態鏈接庫源碼,增加
__attribute
__屬性的函數 run_at_link (該函數在動態鏈接庫被加載時首先執行) - 等待 docker cp 觸發漏洞
3.2 針對容器軟體供應鏈的攻擊#
隨著容器技術的普及,容器鏡像成為了軟體供應鏈中非常重要的一部分,我們可以從 公共倉庫中獲取鏡像,也可以從 私有倉庫中獲取鏡像。
從公共倉庫中獲取鏡像存在兩個脆弱性問題:
- 鏡像中軟體的安全漏洞問題
- 鏡像內的挖礦程序、後門程序、病毒等惡意程序
鏡像漏洞利用
鏡像漏洞利用指的是:鏡像本地存在漏洞時,使用鏡像創建並運行的容器通常也會存在相同的漏洞
例如:Alpine 是一個輕量化的 Linux 發行版,基於 musl libc 和 busybox 構建而成。由於其體積較小,因此以 Alpine 為基礎鏡像構建軟體是非常流行的。但 Alpine 鏡像曾曝出一個漏洞:CVE-2019-5021。在 3.3 ~ 3.9 版本的 Alpine 鏡像中,root 用戶密碼被設置為空,攻擊者可能在攻入容器後借此提升到容器內部 root 權限
鏡像投毒
鏡像投毒是一個寬泛的話題,指的是:攻擊者通過某些方式,如上傳惡意鏡像到公開倉庫、入侵系統後上傳鏡像到受害者本地倉庫,以及修改鏡像名稱並假冒正常鏡像等,欺騙、誘導受害者使用攻擊者指定的惡意鏡像創建並運行容器,從而實現入侵或利用受害者的主機進行惡意活動的行為
根據目的不同,常見的鏡像投毒有三種類型:
- 投放惡意挖礦鏡像
- 投放惡意後門鏡像
- 投放惡意 exploit 鏡像
3.3 針對容器運行時的攻擊#
不安全配置導致的容器逃逸
這些年的迭代,容器社區一直在努力將縱深防禦、最小權限等理念和原則落地。
Docker 已經將容器運行時的 Capabilities 黑名單機制改為如今的默認禁止所有 Capabilities,再以白名單方式賦予容器運行所需的最小權限。Docker 默認賦予容器近 40 項權限中的 14 項:
func DefaultCapabilities() []string {
return []string{
"CAP_CHOWN",
"CAP_DAC_OVERRIDE",
"CAP_FSETID",
"CAP_FOWNER",
"CAP_MKNOD",
"CAP_NET_RAW",
"CAP_SETGID",
"CAP_SETUID",
"CAP_SETFCAP",
"CAP_SETPCAP",
"CAP_NET_BIND_SERVICE",
"CAP_SYS_CHROOT",
"CAP_KILL",
"CAP_AUDIT_WRITE",
}
}
無論是細粒度權限控制還是其他安全機制,用戶都可以通過修改容器環境配置或在運行容器時指定參數來縮小或擴大約束。如果用戶為不完全受控的容器提供了某些危險的配置參數,就為攻擊者提供了一定程度的逃逸可能性
危險掛載導致的容器逃逸
為了方便宿主機與虛擬機進行數據交換,虛擬化解決方案都會提供掛載宿主機目錄到虛擬機的功能。容器同樣如此。然而,將宿主機上的敏感文件或目錄掛載到容器內部 - 當受控容器存在不安全的掛載時,會造成嚴重的問題。
3.4 程序漏洞導致的容器逃逸#
CVE-2019-5736
影響版本:Docker version <= 18.09.2
& RunC version <= 1.0-rc6
漏洞原理:CVE-2019-5736 是一個能夠覆蓋宿主機 runc 程序的容器逃逸漏洞。在執行功能類似於 docker exec
等命令時,底層實際上是容器運行時在操作。例如 runC,相應地,runc exec
命令會被執行。它的最終效果是在容器內部執行用戶指定的程序。進一步講,就是在容器的各種命名空間內,受到各種限制(如 Cgroups)的情況下,啟動一個進程。除此以外,這個操作與在宿主機上執行一個程序並無二致。
攻擊步驟:
- 將容器內的
/bin/sh
程序覆蓋為#!/proc/self/exe
。 - 持續遍歷容器內
/proc
目錄,讀取每一個/proc/[PID]/cmdline
,對 runc 做字符串 匹配,直到找到 runc 進程號。 - 以只讀方式打開
/proc/[runc-PID]/exe
,拿到文件描述符 fd。 - 持續嘗試以寫方式打開第 3 步中獲得的只讀 fd (
/proc/self/fd/[fd]
),一開始總是返回失敗,直到 runc 結束佔用後寫方式打開成功,立即通過該 fd 向宿主機上的/usr/bin/runc
,(名字也可能是/usr/bin/docker/runc
)寫入攻擊載荷 - runc 最後將執行用戶通過
docker exec
指定的/bin/sh
,它的內容在第 1 步中已經被替換成#/proc/self/exe
,因此實際上將執行宿主機上的 runc,而 runc 也已經在第 4 步中被覆蓋掉了
3.5 內核漏洞導致的容器逃逸#
從操作系統層面來看,容器進程只是一種受到各種安全機制約束的進程,因此從攻防兩端來看,容器逃逸都遵循傳統的權限提升流程。攻擊者可以憑藉此特點拓展容器逃逸的思路,一旦有新的內核漏洞產生,就可以考慮它是否能夠用於容器逃逸;而防守者則能夠針對該特徵進行防護和檢測,如宿主機內核打補丁,或檢查該內核漏洞利用有什麼特點。
CVE-2016-5195
影響版本:Linux kernel >= 2.6.22(2007 年發行,到 2016 年 10 月 18 日才修復)
漏洞原理:Linux 內核的內存子系統在處理寫時拷貝(Copy-on-Write) 時存在條件競爭漏洞,導致可以破壞私有只讀內存映射
使用 PoC 來完成容器逃逸。該利用的核心思路是向 vDSO 內寫入 shellcode 並劫持正常函數的調用過程