Aller au contenu

POODLE CVE-2014-3566 oracle de padding SSL 3.0

En octobre 2014, trois chercheurs de Google publient POODLE (CVE-2014-3566). La cible n’est pas un bug d’implémentation mais un défaut de conception de SSL 3.0 (Secure Sockets Layer version 3) : le remplissage des blocs n’est pas authentifié. Un seul bit d’information sur ce remplissage suffit à déchiffrer un cookie de session, octet par octet.

→ Lire l’explication complète de la marmotte

SSL 3.0 chiffre ses enregistrements en mode CBC (Cipher Block Chaining) avec un schéma MtE (MAC-then-Encrypt) : on calcule d’abord un MAC (Message Authentication Code) sur l’en-tête et le texte clair, puis on concatène texte clair, MAC et remplissage, et on chiffre le tout. Le remplissage sert à compléter le dernier bloc jusqu’à un multiple de la taille de bloc (8 octets pour 3DES, 16 pour AES).

Le défaut tient en une phrase, et elle coûte cher. En SSL 3.0, seul le dernier octet du remplissage, celui qui indique la longueur, a une valeur définie. Les octets précédents sont arbitraires, laissés au bon vouloir de l’émetteur, et surtout le MAC ne les couvre pas. Au déchiffrement, le serveur vérifie donc uniquement que le dernier octet est cohérent avec la longueur attendue ; il ne vérifie jamais le contenu des octets de bourrage. Comparer avec TLS (Transport Layer Security) 1.0 et au-dessus, qui imposent un remplissage dont chaque octet vaut la longueur et le valident : la différence paraît cosmétique sur une slide, elle est fatale en production.

Cette absence de vérification transforme le serveur en oracle. Un oracle, en cryptanalyse, c’est une boîte qui répond oui ou non à une question qu’on ne devrait pas pouvoir poser. Ici la question est : « ce remplissage trafiqué est-il accepté ? », et la réponse est un cadeau. Pour comprendre pourquoi un mode de chiffrement par blocs se prête à ce jeu, voir les bases du chiffrement par blocs, et pour la logique générale d’une attaque qui exploite une fuite d’information, ce que la cryptanalyse sait faire d’un détail.

En 2014, pratiquement plus personne n’a besoin de SSL 3.0 : TLS 1.0, 1.1 et 1.2 existent. Le problème, c’est la compatibilité. Pour tolérer les vieux serveurs, les navigateurs rejouaient la négociation en descendant d’une version à chaque échec. Et cette redescente ne s’appuyait sur aucune preuve : il suffisait qu’un attaquant en position d’intermédiaire, le fameux MITM (Man-In-The-Middle), coupe la poignée de main TLS 1.2 pour que le navigateur, docile, propose SSL 3.0 à l’essai suivant.

Autrement dit, la présence de SSL 3.0 dans la pile suffisait à l’imposer, même quand les deux extrémités savaient parler mieux. Garder un protocole obsolète « au cas où » revient à garder une serrure crochetable sur la porte blindée parce qu’un cousin a perdu le bon trousseau. Le compromis central est là : la rétrocompatibilité achetée par un fallback silencieux se paie en downgrade forcé. On gagne quelques clients antédiluviens, on offre à l’attaquant le choix de la version.

Le schéma suivant montre comment l’intermédiaire provoque la redescente ; à lire comme une négociation sabotée, pas comme un échange normal.

Diagramme de séquence entre trois acteurs, Navigateur, MITM et Serveur. Étape 1 : le navigateur envoie au MITM un ClientHello qui propose TLS 1.2. Étape 2 : le MITM coupe la connexion, sans aucune réponse. Étape 3 : le navigateur fait une nouvelle tentative avec un ClientHello qui propose SSL 3.0. Étape 4 : le MITM relaie SSL 3.0 au serveur. Étape 5 : le serveur répond au navigateur par un ServerHello qui accepte SSL 3.0. Étape 6 : le navigateur envoie au serveur du trafic chiffré CBC en SSL 3.0, marqué comme vulnérable.

L’attaque suppose deux capacités réunies : une position d’intermédiaire sur le réseau, et la possibilité de faire émettre au navigateur des requêtes choisies (typiquement via du JavaScript injecté sur une page quelconque, une pub par exemple). Avec ça, l’attaquant contrôle la longueur du chemin et du corps de la requête, donc l’alignement des octets dans les blocs CBC.

L’idée : placer un octet du cookie secret juste à la frontière d’un bloc, et faire en sorte que le dernier bloc de l’enregistrement soit entièrement du remplissage. En CBC, le déchiffrement d’un bloc donne P_n = Dec(C_n) XOR C_{n-1}. L’attaquant remplace le dernier bloc chiffré C_n par un bloc C_i contenant l’octet convoité, puis laisse passer l’enregistrement. Le serveur déchiffre, regarde le dernier octet du bloc trafiqué, et accepte si et seulement si cet octet vaut la longueur de remplissage attendue.

Cette acceptation est l’unique bit qui fuit, et il suffit. Quand le serveur accepte, l’attaquant sait que le dernier octet de Dec(C_i) vaut (taille_bloc - 1) XOR le dernier octet du bloc précédent original. Un XOR avec le bloc chaînant qui précède C_i dans le texte original, et l’octet clair du cookie tombe. La probabilité d’acceptation par tentative est de 1/256, donc en moyenne 256 requêtes par octet. On décale ensuite la cible d’un octet et on recommence. Un cookie de session de 16 caractères part en quelques milliers de requêtes, soit quelques secondes de pub malveillante. Un bit d’information par essai, et le secret entier au bout du fil.

Schéma de séquence de l'attaque POODLE entre quatre acteurs en colonnes : script attaquant, navigateur, MITM (intermédiaire) et serveur. 1, le script attaquant force le navigateur à envoyer une requête, avec le cookie aligné en fin de bloc. 2, le navigateur émet un enregistrement CBC chiffré, intercepté par le MITM. 3, le MITM remplace le dernier bloc chiffré C_n par le bloc cible C_i avant de l'envoyer au serveur. 4, le serveur accepte, avec une probabilité de 1 sur 256, ou rejette, avec une probabilité de 255 sur 256. 5, si le serveur accepte, le MITM transmet au script un octet du cookie déduit. 6, le script décale d'un octet et recommence.

La contre-mesure n’est pas un correctif de code applicatif, c’est une décision de configuration : retirer SSL 3.0 des protocoles négociables, côté serveur comme côté client. Sur un frontal Nginx, cela tient en une directive.

# Ne jamais laisser SSL 3.0 (ni TLS 1.0/1.1) dans la liste négociable.
# Seul le contenu de ssl_protocols compte : tout ce qui n'y figure pas est refusé.
ssl_protocols TLSv1.2 TLSv1.3;

Vérifier ensuite qu’un client ne peut plus forcer SSL 3.0, en le lui demandant explicitement avec OpenSSL :

Fenêtre de terminal
# -ssl3 force la tentative en SSL 3.0 ; un serveur sain doit la refuser.
openssl s_client -connect exemple.test:443 -ssl3
# Réponse attendue : "sslv3 alert handshake failure" ou "no protocols available".

Si la connexion aboutit, SSL 3.0 est encore vivant quelque part dans la chaîne (frontal, répartiteur, service interne mal configuré), et POODLE reste exploitable sur ce maillon.

Désactiver SSL 3.0 traite la cause ; encore faut-il traiter le downgrade pour les cas où un protocole faible reste présent. C’est le rôle de TLS_FALLBACK_SCSV (Signaling Cipher Suite Value), une pseudo-suite de chiffrement que le client insère quand il effectue une tentative de repli après un premier échec. Le message au serveur est : « je redescends volontairement, donc si je te propose moins bien que ce dont je suis capable, c’est louche ». Un serveur qui voit ce signal alors qu’il supporte une version supérieure refuse la connexion par une alerte inappropriate_fallback. Le downgrade silencieux devient un downgrade détecté.

Ce mécanisme ne garantit rien à lui seul : il protège uniquement les clients qui implémentent le fallback explicite, il n’efface pas le padding faible de SSL 3.0, et il suppose que serveur et client le gèrent tous les deux. La vraie réponse reste l’éradication du protocole, TLS_FALLBACK_SCSV n’étant qu’un filet pour la période de transition. TLS 1.3 clôt le débat en supprimant purement et simplement le CBC et le MAC-then-Encrypt au profit du chiffrement authentifié AEAD (Authenticated Encryption with Associated Data), où le remplissage n’existe plus sous cette forme et où toute altération fait échouer l’authentification avant de livrer le moindre bit.

La leçon dépasse POODLE et se retrouve dans toute la famille des oracles de padding, dont l’attaque de Bleichenbacher contre RSA est le cousin historique : authentifier les données, ce n’est pas authentifier une partie des données. Le remplissage fait partie du message, point. Sur ce principe et sur les autres pièges du chiffrement par blocs, voir sécuriser un canal TLS et la rubrique Failles.

Laisser SSL 3.0 négociable, c’est conserver un oracle de padding exploitable sur tout maillon qui l’accepte. Un intermédiaire réseau peut alors forcer la redescente d’un navigateur capable de TLS 1.2, puis déchiffrer octet par octet tout secret que le navigateur rejoue automatiquement : cookie de session, jeton d’authentification, en-tête d’autorisation. Le vol se fait sans casser le chiffrement ni voler de clé, en observant seulement des acceptations et des rejets, ce qui ne laisse aucune trace d’intrusion côté serveur. Sans TLS_FALLBACK_SCSV, le repli reste invisible, et l’attaque passe pour du trafic chiffré normal. Résultat : usurpation de session silencieuse, et aucune alerte à corréler après coup.

  • CVE-2014-3566, MITRE.
  • This POODLE Bites: Exploiting The SSL 3.0 Fallback, Bodo Möller, Thai Duong, Krzysztof Kotowicz, Google, septembre 2014.
  • RFC 6101, IETF.
  • RFC 7507, IETF.

Quand un navigateur et un site veulent discuter en secret, ils choisissent d’abord une version de langage de chiffrement. SSL 3.0 est une très vieille version. Pour rester compatible avec de vieux serveurs, les navigateurs redescendaient automatiquement vers cette version si la discussion moderne échouait. Un attaquant placé entre les deux n’avait qu’à couper la discussion moderne pour forcer tout le monde à parler ce vieux langage.

Or ce vieux langage découpe les messages en blocs de taille fixe. Quand le dernier bloc n’est pas plein, on ajoute du bourrage. Problème : le site vérifie que le message n’a pas été modifié, mais il oublie de vérifier ce bourrage. Il regarde seulement le tout dernier chiffre du bourrage.

L’attaquant exploite cet oubli. Il fait envoyer par le navigateur des requêtes contenant le mot de passe de session, en le plaçant pile à la fin d’un bloc. Puis il remplace ce bloc par un morceau qui l’intéresse. Le site répond « accepté » ou « refusé ». Une fois sur 256, c’est accepté, et cette acceptation révèle une lettre du secret. On recommence, décalé d’un cran, jusqu’à tout avoir. La parade : interdire le vieux langage partout. S’il traîne encore quelque part, l’attaque remarche sur ce maillon.

À lire aussi

Pages voisines

: les deux pages se citent l’une l’autre.