À propos de CVE-2024-0517
CVE-2024-0517 est une vulnérabilité d'écriture hors limites dans le moteur JavaScript V8 de Google Chrome avant la version 120.0.6099.224, qui permet à des attaquants distants d'exploiter la corruption du tas via une page HTML conçue. La vulnérabilité a été signalée pour la première fois par Toan (Suto) Pham de Qrious Secure.
Cette vulnérabilité résulte d'une confusion de type, qui se produit lorsqu'une application alloue ou initialise une ressource telle qu'un pointeur, un objet ou une variable en utilisant un type, mais accède ensuite à cette ressource en utilisant un type incompatible avec le type d'origine (CWE-843). Dans ce cas, la confusion de type est déclenchée au cours d'un processus d'allocation de mémoire appelé "folded allocation", qui est utilisé pour l'optimisation de la mémoire par Maglev, un compilateur d'optimisation pour le moteur JavaScript V8.
En exploitant la confusion de type et en écrivant des shellcodes arbitraires par WebAssembly, un attaquant peut exécuter des commandes sur la machine de la victime.
Phases d'attaque
Les attaquants peuvent héberger un site web contenant une page HTML élaborée et inciter les utilisateurs à y accéder par le biais de courriels d'hameçonnage ou de réseaux sociaux. Lorsque les utilisateurs visitent le site à l'aide d'une version vulnérable de Google Chrome, le code malveillant intégré exécute des commandes arbitraires.
Moteur JavaScript V8
Les attaquants peuvent héberger un site web contenant une page HTML élaborée et inciter les utilisateurs à y accéder par le biais de courriels d'hameçonnage ou de réseaux sociaux. Lorsque les utilisateurs visitent le site à l'aide d'une version vulnérable de Google Chrome, le code malveillant intégré exécute des commandes arbitraires.
Maglev et Allocation pliée
Maglev, un compilateur optimisant la V8, améliore l'exécution du code et l'allocation de la mémoire. Maglev ne s'exécute que lorsque le code est fréquemment exécuté et marqué comme "chaud", ce qui indique la nécessité d'une exécution plus rapide par la compilation plutôt que par une interprétation ligne par ligne plus lente.
Généralement, les allocations se produisent dans des régions de mémoire non contiguës, ce qui conduit à une utilisation éparse et inefficace de la mémoire. Pour remédier à ce problème, V8 utilise une technique appelée "folded allocation", qui alloue plusieurs variables de manière continue et simultanée. Maglev optimise également les allocations en utilisant l'allocation repliée dans sa progression.
Collecte d'ordures générationnelle
Pour nettoyer les zones de mémoire inutilisées, V8 utilise une technique de ramassage générationnel des ordures (GC), divisant la mémoire en deux espaces : la jeune génération et l'ancienne génération. En outre, il existe deux collecteurs d'ordures : le collecteur d'ordures mineur, qui est responsable du nettoyage de l'espace jeune, et le collecteur d'ordures majeur, qui s'occupe du nettoyage de l'espace ancien. La jeune génération est la zone de la mémoire où les objets nouvellement créés sont initialement alloués et l'ancienne génération est une région de la mémoire où les objets de longue durée sont stockés. Les objets qui ont survécu à plusieurs cycles de GC mineurs dans la jeune génération sont finalement transférés dans l'ancienne génération.
Analyse de la vulnérabilité
Vue d'ensemble
La vulnérabilité survient lorsqu'un objet est créé à partir d'une classe héritée d'une classe de base sans constructeur explicitement défini (constructeur par défaut de la base), et qu'un autre objet est ensuite créé. En raison de l'allocation repliée, l'allocation du premier objet peut être suivie de l'allocation du second objet. Si un événement tel que le ramassage des ordures se produit entre ces deux allocations, une vulnérabilité de confusion de type peut survenir.
Analyse des causes profondes
Les diplômés d'OPSWAT ont effectué une analyse détaillée du flux de travail V8 pendant le processus d'allocation et ont déterminé que les fonctions suivantes sont invoquées au cours de ce processus :
Au cours de ce processus, un problème a été identifié dans la fonction TryBuildFindNonDefaultConstructorOrConstruct : La fonction BuildAllocateFastObject étend current_raw_allocation_ (un pointeur sur la région de mémoire allouée à plusieurs variables simultanément) pour construire l'instance de la classe enfant, mais ne parvient pas à l'effacer en lui attribuant la valeur null.
Par conséquent, le prochain objet créé est toujours alloué immédiatement après la mémoire indiquée par current_raw_allocation_, indépendamment de tout événement antérieur à la deuxième allocation.
Si le GC est invoqué, la région de mémoire adjacente à la mémoire adjacente à current_raw_allocation_ peut être affectée à d'autres objets. Cela peut conduire à une situation où, après le déclenchement de GC et la création d'un autre objet, deux pointeurs référencent la même région de mémoire mais ont des types de données différents, ce qui entraîne une vulnérabilité de confusion de type.
Exploitation
Pour exploiter cette vulnérabilité, les boursiers diplômés de OPSWAT ont créé des instances de WebAssembly contenant du shellcode et ont tenté de déclencher une confusion de type par GC afin de contrôler la mémoire et d'exécuter le shellcode :
Confusion des types de déclencheurs
Lors de l'initialisation, nous définissons d'abord un tableau (_arrayObject) contenant des objets vides. Ensuite, nous construisons une instance de la classe enfant ainsi qu'un ramasse-miettes (garbage collector). Enfin, nous définissons un autre tableau contenant un nombre à virgule flottante, nommé _arrayDouble.
Ces constructions doivent être répétées afin que le code soit exécuté plusieurs fois, ce qui permet à V8 de le marquer comme "chaud" et de déclencher le compilateur Maglev. Nous y parvenons en invoquant le constructeur de la classe enfant à l'intérieur d'une boucle comme suit :
Une confusion de type sera déclenchée après l'initialisation répétée de ces objets dans une boucle.
Créer des primitives de lecture et d'écriture
Après avoir réussi à déclencher la confusion de type, l'exécution du shellcode nécessite la lecture de la mémoire et l'écrasement de la mémoire à une adresse contrôlée. Pour ce faire, nous avons créé des primitives de lecture et d'écriture. Les primitives d'exploitation tireront parti des métadonnées des objets pour nous donner des régions de mémoire arbitraires en lecture/écriture et les utiliser pour exécuter du code arbitraire.
Les primitives de lecture et d'écriture de cette étape nous permettront de contrôler le pointeur de la table Jump de l'instance WebAssembly dans l'étape suivante.
Créer des instances de WebAssembly
Ensuite, nous avons créé deux instances WebAssembly : l'une pour stocker le shellcode et l'autre pour le déclencher. Pour éviter d'écrire directement le shellcode dans la mémoire de l'instance WebAssembly via les primitives de lecture et d'écriture, nous définissons des valeurs constantes en virgule flottante dans l'instance WebAssembly.
Pointeur de table de saut de contrôle de l'instance WebAssembly
En utilisant des primitives de lecture et d'écriture, nous ajustons le pointeur de la table de saut de la deuxième instance de WebAssembly pour sauter quelques octets du code compilé des constantes de la première instance de WebAssembly afin que les constantes en virgule flottante soient interprétées comme notre shellcode prévu :
Exécuter l'instance de WebAssembly pour exécuter le Shellcode
Enfin, après avoir déclenché une confusion de type et utilisé des primitives de lecture/écriture pour contrôler les pointeurs de la table de saut des instances WebAssembly, nous avons invoqué la fonction exportée de la deuxième instance WebAssembly, ce qui a entraîné l'exécution du shellcode dans la première instance WebAssembly.
Le shellcode que nous utilisons est conçu pour mettre fin à tous les processus sur une machine Linux, comme le montre la commande suivante :
Le code d'assemblage pour exécuter cette commande, converti à partir des nombres à virgule flottante, sera le suivant :
Simuler la vulnérabilité de la sécurité
Pour simuler cette exploitation dans un scénario réel, les boursiers diplômés d'OPSWAT ont créé une page HTML malveillante.
Un courriel d'hameçonnage contenant un lien vers le domaine hébergeant cette page HTML est envoyé à la victime.
Si la victime accède au lien en utilisant la version vulnérable de Google Chrome, le shellcode est exécuté, ce qui entraîne l'arrêt de tous les processus. L'utilisateur est alors déconnecté, comme indiqué ci-dessous :
Remédiation
MetaDefender Endpoint™ a été employé pour atténuer de manière proactive ce CVE en tirant parti de sa capacité "Application vulnérable". La solution localise et affiche efficacement toutes les CVE associées aux applications Google Chrome dans l'environnement du terminal. Pour neutraliser la menace, les utilisateurs peuvent rapidement désinstaller Chrome ou appliquer le dernier correctif de sécurité. En mettant en œuvre l'une ou l'autre de ces contre-mesures, la CVE est entièrement contenue, ce qui réduit considérablement le risque d'une cyberattaque réussie sur le poste de travail.
Sécurité des Endpoint niveau supérieur
Découvrez pourquoi les organisations, les institutions et les entités du monde entier font confiance à MetaDefender Endpoint pour protéger leurs points d'accès critiques. Parlez à un expert dès aujourd'hui pour en savoir plus et voyez par vous-même avec une démonstration gratuite.
Références
https://nvd.nist.gov/vuln/detail/CVE-2024-0517
https://cwe.mitre.org/data/definitions/843.html
https://blog.exodusintel.com/2024/01/19/google-chrome-v8-cve-2024-0517-out-of-bounds-write-code-execution/
https://jhalon.github.io/chrome-browser-exploitation-1/
https://whenderson.dev/blog/webgl-garbage-collection/
https://v8.dev/
https://github.com/Uniguri/CVE-nday/tree/master/Chrome/V8/CVE-2024-0517