本篇内容主要讲解“Docker SYS_ADMIN容器逃逸原理举例分析”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Docker SYS_ADMIN容器逃逸原理举例分析”吧!Docker容器的不安全配置可能导致应用存在容器逃逸漏洞。本文将详细介绍利用SYS_ADMIN Capability进行容器逃逸的原理。Docker容器不同于虚拟机,它共享宿主机操作系统内核。宿主机和容器之间通过内核命名空间(namespaces)、内核Capabilities、CGroups(control groups)等技术进行隔离。Linux内核在2.2版本之后,将root权限细分成了多个被称为Capability的单元。比如,Docker容器里可能需要把Web server绑定到值小于1024的端口上,这个操作需要的Capability是“CAP_NET_BIND_SERVICE”,如果给执行Web server的用户授予这个Capability,那么在绑定端口的时候,Web server就不需要以root用户运行了。在大部分情况下,容器里的进程不需要以“完整”的root用户运行,Docker给容器内root账号只授予了几个默认的Capabilities,其他的禁用。这意味着容器里的root用户权限比宿主机上真正的root用户权限要小的多。而在实际的使用过程中,很多用户会违背Docker的这些安全防护配置原则。比如为了方便,容器以root用户启动,同时为了执行一些特权操作,给root用户额外授权一些Capability,例如SYS_ADMIN。如果一个Docker容器的启动方式满足以下条件,攻击者在容器中就可以逃逸到宿主机上。以root用户的身份在容器内运行;容器启用SYS_ADMIN Capability;容器没有启用Docker默认的AppArmor配置文件docker-default,或者AppArmor允许运行mount syscall;其中,条件1和2是必需的,而条件3在某些宿主机上比较容易满足,比如CentOS等Red Hat系的Linux操作系统上默认没有安装AppArmor。例如以下面的命令开启一个Ubuntu容器:其中,”–cap-add=SYS_ADMIN“表示给Docker容器SYS_ADMIN的Capability。“–security-opt apparmor=unconfined”表示去除Docker默认的AppArmor配置。攻击者可以在容器内通过挂载宿主机cgroup,并利用cgroup notify_on_release的特性在宿主机执行shell,从而实现容器逃逸。执行步骤如下:容器内挂载宿主机cgroup,并自定义一个cgroup;配置该cgroup的notify_no_release和release_agent;这里使用了sh tcp的反弹shell来逃逸容器,也可以执行其他任意linux shell命令。触发release_agent执行。下面详细说明一下各个步骤的操作和原理。漏洞利用第一步是挂载宿主机的memory cgroup。cgroup(control group、控制群组)是 Linux kernel一项进行资源分配(如 CPU 时间、系统内存、网络带宽或者这些资源的组合)的功能。使用mount -t cgroup
命令可以查看宿主机当前的cgroup。进到要挂载的memory cgroup里。该文件夹包含了系统管理员对memory资源的配置,其中docker文件夹里包含了docker针对容器memory资源的默认cgroup配置。默认情况下,容器在启动时会在/sys/fs/cgroup
目录各个subsystem目录的docker子目录里,生成以容器 ID 为名字的子目录查看宿主机里的memory cgroup目录,可以看到docker目录里多了一个目录9d14bc4987d5807f691b988464e167653603b13faf805a559c8a08cb36e3251a
,这一串字符是容器ID,这个目录里的内容就是用户在容器里查看/sys/fs/cgroup/memory
的内容。mount命令是一个系统调用(syscall)命令,系统调用号为165。执行syscall需要用户具备CAP_SYS_ADMIN的Capability。如果在宿主机启动时,添加了--cap-add SYS_ADMIN
参数,那root用户就能在容器内部就能执行mount挂载cgroup。(docker默认情况下不会开启SYS_ADMIN Capability)漏洞利用的第一步是在容器里创建一个临时目录/tmp/cgrp
,并使用mount
命令将系统默认的memory类型的cgroup重新挂载到/tmp/cgrp
上。其中,-t
参数表示mount的类别为cgroup,-o
表示挂载的选项。对于cgroup,挂载选项就是cgroup的subsystem,每个subsystem代表一种资源类型,比如cpu、memory。具体可以参考链接:cgroup subsystems。执行该命令之后,宿主机的memory cgroup被挂载到了容器中,对应目录/tmp/cgrp。需要注意的是,对cgroup进行重新挂载的操作时,只有当被挂载目标的hierarchy为空时才能成功。因此,如果这里memory的重新挂载不成功的话,可以换其他的subsystem。接着就是在这个cgroup类型里建一个子目录x。查看/tmp/cgrp/x
可以发现有很多和memory相关的配置。接下来将使用x
来作为POC操作的主要目标。漏洞利用的第二步和notify_no_release有关。cgroup的每一个subsystem都有参数notify_on_release,这个参数值是Boolean型,1或0。分别可以启动和禁用释放代理的指令。如果notify_on_release启用,当cgroup不再包含任何任务时(即,cgroup的tasks文件里的PID为空时),系统内核会执行release_agent参数指定的文件里的内容。需要注意的是release_agent文件并不在/tmp/cgrp/x
目录里,而是在memory cgroup的根目录/tmp/cgrp
里。这样的设计可以用来自动移除根cgroup里所有空的cgroup。将/tmp/cgrp/x的notify_no_release属性设置为1。接着将release_agent指定为容器在宿主机上的cmd文件。具体操作是先获取docker容器在宿主机上的存储路径。文件/etc/mtab存储了容器中实际挂载的文件系统。这里使用sed
命令匹配perdir=(
和)
之间的非逗号内容,从上图可以看出,host_path
就是docker的overlay存储驱动上的可写目录upperdir.在这个目录里创建一个cmd文件,并把它作为/tmp/cgrp/x/release_agent参数指定的文件。接下来,POC将要执行的shell写到cmd文件里,并赋予执行权限。最后,POC触发宿主机执行cmd文件中的shell。该命令启动一个sh进程,将sh进程的PID写入到/tmp/cgrp/x/cgroup.procs里,这里的$$
表示sh进程的PID。在执行完sh -c
之后,sh进程自动退出,这样cgroup /tmp/cgrp/x
里不再包含任何任务,/tmp/cgrp/release_agent文件里的shell将被操作系统内核执行。免费云主机域名利用SYS_ADMIN权限逃逸Docker容器的关键在于容器要能够挂载宿主机的cgroup。为禁止容器执行mount syscall,Docker在限制用户Capabilities的基础上,会默认开启AppArmor和seccomp这两个安全防护工具。但关于这两个工具的配置,Docker给出的默认配置有一些值得注意的“瑕疵”。关于AppArmor,CentOS等Red Hat系的Linux操作系统上默认没有安装AppArmor。这样文章开头提到的漏洞利用条件第3条,“容器必须没有启用Docker默认的AppArmor配置文件docker-default,或者AppArmor允许运行mount syscall”,将很容易满足,不需要显式地添加“–security-opt apparmor=unconfined”参数。AppArmor(Application Armor)是Linux内核的一个安全模块,AppArmor允许系统管理员将每个程序与一个安全配置文件关联,从而限制程序的功能。简单的说,AppArmor是与SELinux类似的一个访问控制系统,通过它用户可以指定程序可以读、写或运行哪些文件,是否可以打开网络端口等。比如,Docker官网给出了一个Nginx加固的例子。其中,deny /bin/** wl表示阻止/bin目录下及任意层子目录下的写权限,w:写,l:创建硬链接。Docker采用的默认配置文件是docker-default。它具有适度的保护性,同时提供广泛的应用程序兼容性。查看该配置文件生成模板,可以发现在第43行配置了禁止容器调用mount。这里也可以发现,该配置文件并没有禁止对/sys/fs/cgroup目录的读写。如果在实际利用过程中,发现容器里无法读写cgroup目录,可以检查容器是否在AppArmor配置里禁止了对cgroup目录的读写。Docker默认情况下使用docker-default策略启动容器。此时,即使使用SYS_ADMIN Capbility运行该容器,它也会阻止容器执行mount系统调用。除非在容器启动时用参数--security-opt apparmor=unconfined
覆盖配置。虽然Docker默认的AppArmor配置能很好地阻止容器调用mount,但并不是所有的宿主机都支持AppArmor。对于Debian系的linux,比如Ubuntu,默认安装了AppArmor和SeLinux。而对于Red hat系的linux,比如CentOS,默认使用SeLinux,没有安装AppArmor。这就导致在Red hat系linux宿主机上,有可能不需要容器启用--security-opt apparmor=unconfined
参数也能执行mount系统调用。在某个CentOS测试机上进行测试,结果如下:查看docker info,可以发现安全选项“Security Options”里没有开启AppArmor,只开启了seccomp。因此,在仅添加“–cap-add=SYS_ADMIN”参数的情况下CentOS宿主机仍然能成功执行POC。在上一节的docker info输出中,可以看到Docker也会有一个默认的seccomp配置。那为什么seccomp没有能阻止容器调用mount?这得从Docker默认的seccomp配置说起,在配置模板里,关于mount的配置从第600行开始。可以看到,Docker seccomp默认配置仅依靠SYS_ADMIN来限制执行mount系统调用。如果容器启动时使用了“–cap-add=SYS_ADMIN”参数,那么seccomp就不能很好地防护容器了。到此,相信大家对“Docker SYS_ADMIN容器逃逸原理举例分析”有了更深的了解,不妨来实际操作一番吧!这里是云编程开发博客网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!
H3CNEH3C Certified Network EngineerH3CH3CNEH3CNEH3CV6.0H3CTCP/IPIPH3CTCP/IPIP1.TCP/IP2.3.4.IP5.6.HL-001 HL-002 H3C HL-003 HL-004 T…
免责声明:本站发布的图片视频文字,以转载和分享为主,文章观点不代表本站立场,本站不承担相关法律责任;如果涉及侵权请联系邮箱:360163164@qq.com举报,并提供相关证据,经查实将立刻删除涉嫌侵权内容。