token
, error
RAPPORT _SÉCURITÉ_
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.
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.
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)
},
}
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.
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
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 valideJe 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