<p>kubeadm peut enregistrer les jetons d'amorçage avant de tenter de les supprimer</p>

Créé le 11 sept. 2020  ·  3Commentaires  ·  Source: kubernetes/kubeadm

Quels mots clés avez-vous recherchés dans les problèmes de kubeadm avant de déposer celui-ci ?

token , error

S'agit-il d'un rapport de bogue ou d'une demande de fonctionnalité ?

RAPPORT _SÉCURITÉ_

Sommaire:

kubeadm de delete prend en entrée soit un ID de jeton d'amorçage, soit un jeton complet. Avant de déterminer si l'entrée est juste un identifiant ou un jeton complet, kubeadm enregistre l'entrée à l'aide de klog . Si la suppression échoue, le jeton resterait valide. Un attaquant ayant accès aux journaux pourrait l'utiliser pour effectuer des actions nécessitant un jeton d'amorçage, telles que la création d'un cluster ou la jonction de nœuds à un cluster existant.

Version Kubernetes :

Le code vulnérable est présent dans kubernetes 1.19. La ligne spécifique qui contient l'appel à klog été modifiée pour la dernière fois le 2019-03-24.

Des détails:

Le code vulnérable se trouve dans le référentiel github.com/kubernetes , dans le fichier kubernetes/cmd/kubeadm/app/cmd/token.go , à la ligne 423. Voici la fonction complète :

// RunDeleteTokens removes a bootstrap tokens from the server.
func RunDeleteTokens(out io.Writer, client clientset.Interface, tokenIDsOrTokens []string) error {
    for _, tokenIDOrToken := range tokenIDsOrTokens {
        // Assume this is a token id and try to parse it
        tokenID := tokenIDOrToken
        klog.V(1).Infof("[token] parsing token %q", tokenIDOrToken) // POTENTIAL LEAK HERE
        if !bootstraputil.IsValidBootstrapTokenID(tokenIDOrToken) {
            // Okay, the full token with both id and secret was probably passed. Parse it and extract the ID only
            bts, err := kubeadmapiv1beta2.NewBootstrapTokenString(tokenIDOrToken)
            if err != nil {
                return errors.Errorf("given token %q didn't match pattern %q or %q",
                    tokenIDOrToken, bootstrapapi.BootstrapTokenIDPattern, bootstrapapi.BootstrapTokenIDPattern)
            }
            tokenID = bts.ID
        }

        tokenSecretName := bootstraputil.BootstrapTokenSecretName(tokenID)
        klog.V(1).Infof("[token] deleting token %q", tokenID)
        if err := client.CoreV1().Secrets(metav1.NamespaceSystem).Delete(context.TODO(), tokenSecretName, metav1.DeleteOptions{}); err != nil {
            return errors.Wrapf(err, "failed to delete bootstrap token %q", tokenID)
        }
        fmt.Fprintf(out, "bootstrap token %q deleted\n", tokenID)
    }
    return nil
}

Et voici la définition de la commande kubeadm qui appelle cette fonction (dans le même fichier) :

    deleteCmd := &cobra.Command{
        Use:                   "delete [token-value] ...",
        DisableFlagsInUseLine: true,
        Short:                 "Delete bootstrap tokens on the server",
        Long: dedent.Dedent(`
            This command will delete a list of bootstrap tokens for you.

            The [token-value] is the full Token of the form "[a-z0-9]{6}.[a-z0-9]{16}" or the
            Token ID of the form "[a-z0-9]{6}" to delete.
        `),
        RunE: func(tokenCmd *cobra.Command, args []string) error {
            if len(args) < 1 {
                return errors.Errorf("missing subcommand; 'token delete' is missing token of form %q", bootstrapapi.BootstrapTokenIDPattern)
            }
            kubeConfigFile = cmdutil.GetKubeConfigPath(kubeConfigFile)
            client, err := getClientset(kubeConfigFile, dryRun)
            if err != nil {
                return err
            }

            return RunDeleteTokens(out, client, args)
        },
    }

Impacter:

Un attaquant qui obtient un jeton d'amorçage à partir des journaux pourrait l'utiliser pour s'authentifier avec kubeadm et créer un nouveau cluster ou joindre des nœuds à un cluster existant, par exemple pour utiliser des ressources informatiques. Un attaquant pourrait également effectuer d'autres actions en utilisant kubeadm , par exemple lister ou supprimer d'autres jetons.

Information additionnelle:

J'ai signalé cette vulnérabilité à HackerOne et ils m'ont informé qu'en raison de la complexité élevée de l'attaque et de la faible gravité, ils pensent que cela peut être signalé et corrigé publiquement.

J'ai ouvert un PR sur kubernetes en implémentant un correctif : https://github.com/kubernetes/kubernetes/pull/94727

aresecurity kincleanup prioritbacklog

Tous les 3 commentaires

La commande delete de kubeadm prend en entrée soit un ID de jeton d'amorçage, soit un jeton complet. Avant de déterminer si l'entrée est juste un identifiant ou un jeton complet, kubeadm enregistre l'entrée à l'aide de klog. Si la suppression échoue, le jeton resterait valide. Un attaquant ayant accès aux journaux pourrait l'utiliser pour effectuer des actions nécessitant un jeton d'amorçage, telles que la création d'un cluster ou la jonction de nœuds à un cluster existant.

salut, et merci d'avoir signalé le problème. pour pouvoir lire de tels journaux, il faudrait avoir les bons privilèges et je suppose que les journaux seraient soit sous accès root, soit donnés à un groupe spécifique qui a déjà un accès plus élevé que les jetons d'amorçage.

aussi:

  • --v=>1 doit être activé pendant l'exécution de kubeadm token delete si le jeton est dans un format valide
  • les jetons expirent après 24 heures par défaut

Je pense que l'amélioration du PR est plutôt bonne, mais je ne pense pas que nous devrions rétroporter vers des versions plus anciennes (<1.20) en raison de la complexité d'une telle attaque.

Je suis d'accord avec @neolit123 pour ne pas rétroporter (sauf s'il y a des besoins vraiment spécifiques)
WRT au correctif, je suis +1 pour supprimer le TokenID des journaux

fermeture en tant que https://github.com/kubernetes/kubernetes/pull/94727 fusionné.
Merci

Cette page vous a été utile?
0 / 5 - 0 notes