Résumé

  • CGI pouvait convertir un en-tête HTTP distant en variable d’environnement Unix ; Bash vulnérable pouvait interpréter une valeur ressemblant à une fonction et poursuivre avec les commandes qui la suivaient.
  • L’exposition distante dépendait d’un chemin d’appel complet : donnée contrôlée, environnement transmis, puis lancement direct ou indirect de Bash.
  • La première correction était incomplète ; il fallait mettre à jour, réduire les héritages d’environnement, supprimer les passages par le shell inutiles et renouveler les processus persistants.

Dans le vocabulaire du Web, un en-tête décrit une requête. Dans celui d’un processus Unix, une variable d’environnement décrit le contexte d’exécution. Dans Bash, pourtant, une forme particulière de cette variable pouvait désigner une fonction. Shellshock a soudé ces trois sens et transformé une description distante en autorisation locale.

La première étape était normale et documentée. RFC 3875 indique que CGI peut présenter les champs d’en-tête HTTP sous forme de méta-variables préfixées par HTTP_. Sur Unix, ces méta-variables sont livrées au script comme variables d’environnement de même nom. Cette passerelle n’exécutait rien par elle-même.

Le changement de nature survenait au démarrage de Bash. Le shell savait exporter une fonction dans l’environnement afin qu’un nouveau processus Bash puisse la récupérer. Les versions vulnérables reconnaissaient la forme d’une définition de fonction, mais ne s’arrêtaient pas toujours à sa fermeture. Le texte ajouté après celle-ci pouvait être analysé comme une commande.

Le chemin réel était donc : requête distante, méta-variable CGI, environnement du processus, import de fonction, exécution. Il ne suffit pas de dire « Bash est installé ». Il fallait qu’un service accepte une valeur influençable par l’attaquant et appelle Bash. CERT/CC et Red Hat ont cité les scripts CGI, certaines restrictions de commandes SSH et des traitements DHCP. Deux serveurs avec le même paquet pouvaient ainsi avoir des risques radicalement différents.

La publication de CVE-2014-6271 le 24 septembre 2014 n’a pas produit une frontière nette entre avant et après. CERT/CC a signalé l’exploitation active. Le 26 septembre, Red Hat expliquait que le premier correctif ne couvrait pas tout ; CVE-2014-7169 a décrit un comportement restant, puis d’autres défauts voisins ont reçu leurs propres identifiants. Une étiquette « corrigé » n’était fiable qu’avec la version exacte et un test du chemin concerné.

La réponse la plus robuste a resserré l’interface d’import. Les paquets corrigés ont placé les fonctions exportées dans un espace de noms reconnaissable, du type BASH_FUNC_nom(). Ce choix a eu un coût de compatibilité, mais il a retiré à une variable ordinaire l’ambiguïté qui lui permettait de devenir silencieusement une déclaration exécutable.

Installer le paquet ne renouvelait pas nécessairement l’état vivant. Red Hat recommandait de redémarrer les services concernés ; certaines sessions utilisateur, screen ou tmux pouvaient aussi conserver d’anciennes définitions. La preuve devait porter sur le Bash réellement lancé, son ascendance de processus et le résultat d’un test inoffensif traversant la même interface.

Une organisation disciplinée travaillait donc depuis le graphe d’appel. Quels services exposés construisent un environnement ? Quel script appelle Bash ? Sous quel compte ? Quel parent persistant transmet encore l’ancien contrat ? Pendant la correction, un responsable local devait pouvoir couper un gestionnaire CGI, filtrer un passage précis ou remplacer un appel au shell par une exécution directe.

Shellshock ne démontre pas que les variables d’environnement sont mauvaises. Il démontre qu’une couche ne contrôle pas le sens que la suivante donnera à ses données. L’autorité apparaît souvent dans cet écart.

Sources