Skip to content
KitploitKITPLOIT
OutilsBlog
Log in
Soumettre
OutilsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

FluxContactConfidentialité© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
CVE-2023-6702 — Chrome Renderer RCE 1-day via confusion de type dans la trace de pile asynchrone (soumission v8ctf) | Kitploit
Outils/GitHubGitHub/kaist-hacking/cve-2023-6702
Analyse des VulnérabilitésExploitationExploitation d'Applications WebCTFApprentissage et ÉducationExploitation de Binaires
GitHubkaist-hacking/cve-2023-6702

CVE-2023-6702

Chrome Renderer RCE 1-day via confusion de type dans la trace de pile asynchrone (soumission v8ctf)

Voir le dépôt
8697il y a 2 ansVérifié par Kitploit

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →
Partager

RCE 1day du Renderer Chrome via une confusion de type dans la trace de pile asynchrone (CVE-2023-6702)

Résumé

Cette vulnérabilité permettait à un attaquant distant d'exécuter du code arbitraire dans le processus de rendu Chrome.

Il y avait une vérification de type insuffisante dans le code de gestion des traces de pile asynchrones. Cela conduit à une confusion de type entre FunctionContext et NativeContext, provoquant un accès illégal à la valeur JSGlobalProxy->hash. Avec du heap spraying, l'attaquant a pu injecter une fausse trame de pile asynchrone et construire le primitif fakeobj. En utilisant le primitif fakeobj, l'attaquant a pu réaliser une exécution de code arbitraire dans le processus de rendu Chrome.

Vous pouvez consulter nos slides TyphoonCon 2024.

Fournisseur / Produit / Version

  • Google Chrome
  • Versions affectées : pre 120.0.6099.109
  • Version corrigée : 120.0.6099.109

Chronologie

  • 2020-05-13 : Bogue introduit - [Promise.any] Implémenter les traces de pile asynchrones pour Promise.any
  • 2023-11-10 : Rapport de bogue - Security: V8 Debug check failed: LAST_TYPE >= value
  • 2023-11-15 : Correctif - [promises, async stack traces] Fix the case when the closure has run
  • 2023-12-12 : Avis - https://chromereleases.googleblog.com/2023/12/stable-channel-update-for-desktop_12.html
  • 2024-01-12 : Soumission v8CTF <-- La période où nous avons travaillé sur cette vulnérabilité
  • 2024-02-23 : Rapport de bogue divulgué

Contexte

Trace de pile asynchrone

L'asynchrone est l'une des fonctionnalités les plus importantes de JavaScript. Dans le passé, il était difficile de déboguer du code asynchrone avec la pile d'erreur car les fonctions asynchrones ne sont pas capturées dans la pile d'erreur. Les fonctions asynchrones suspendues sont stockées dans la file d'attente de rappels de la boucle d'événements, pas dans la pile d'appels, donc la pile d'erreur ne contient pas la fonction asynchrone. Pour résoudre ce problème, V8 fournit la fonctionnalité "trace de pile asynchrone" (par défaut depuis V8 v7.3) pour capturer les fonctions asynchrones dans la pile d'erreur. ([v8 blog], [v8 docs])

Fermeture de résolution d'élément Promise.all

"Fermeture de résolution d'élément Promise.all" est une fonction auxiliaire pour résoudre les promesses d'entrée dans la fonction Promise.all. La fonction Promise.all prend un tableau de promesses et retourne une promesse qui se résout lorsque toutes les promesses d'entrée sont résolues. "Fermeture de résolution d'élément Promise.all" est un gestionnaire de résolution de chaque promesse d'entrée dans la fonction Promise.all. Son rôle est de résoudre la promesse d'entrée et de stocker la valeur d'accomplissement dans le tableau de résultats.

Il y a 2 points à noter à propos de cette fonction :

  1. C'est une fonction native intrinsèque et elle n'est pas directement accessible depuis le code JavaScript.
  2. Le contexte de la fonction est utilisé comme marqueur pour vérifier si la fonction a déjà été exécutée ou non. Elle a FunctionContext jusqu'à ce qu'elle soit appelée, puis elle a NativeContext après avoir été appelée. (code v8)

La vulnérabilité

Classe de bogue : Confusion de type entre FunctionContext et NativeContext

Détails de la vulnérabilité :

La vulnérabilité peut être déclenchée en capturant une trace de pile asynchrone avec la fonction "Fermeture de résolution d'élément Promise.all" déjà exécutée ou une fonction native intrinsèque similaire. Dans cet exploit, j'ai utilisé la fonction "Fermeture de résolution d'élément Promise.all" comme exemple.

Lorsqu'une erreur est levée dans le code JavaScript, V8 capture la pile d'erreur depuis la pile et ajoute les trames de pile asynchrones depuis la microtâche courante [1].

CallSiteBuilder builder(isolate, mode, limit, caller);
VisitStack(isolate, &builder);

// If --async-stack-traces are enabled and the "current microtask" is a
// PromiseReactionJobTask, we try to enrich the stack trace with async
// frames.
if (v8_flags.async_stack_traces) {
    CaptureAsyncStackTrace(isolate, &builder);
}

La fonction CaptureAsyncStackTrace [[2]] parcourt la chaîne de promesses et ajoute la trame de pile asynchrone en fonction du type d'appel asynchrone (par exemple, await, Promise.all, Promise.any).

Voici l'extrait de la fonction CaptureAsyncStackTrace qui gère le cas Promise.all :

} else if (IsBuiltinFunction(isolate, reaction->fulfill_handler(),
                                Builtin::kPromiseAllResolveElementClosure)) {
    Handle<JSFunction> function(JSFunction::cast(reaction->fulfill_handler()),
                                isolate);
    Handle<Context> context(function->context(), isolate);
    Handle<JSFunction> combinator(context->native_context()->promise_all(),
                                isolate);
    builder->AppendPromiseCombinatorFrame(function, combinator);

    // Now peak into the Promise.all() resolve element context to
    // find the promise capability that's being resolved when all
    // the concurrent promises resolve.
    int const index =
        PromiseBuiltins::kPromiseAllResolveElementCapabilitySlot;
    Handle<PromiseCapability> capability(
        PromiseCapability::cast(context->get(index)), isolate);
    if (!IsJSPromise(capability->promise())) return;
    promise = handle(JSPromise::cast(capability->promise()), isolate);
} else if (

En parcourant la chaîne de promesses, si reaction->fulfill_handler est la fonction native "Fermeture de résolution d'élément Promise.all", elle ajoute la trame de combinaison de promesses asynchrones à la pile d'erreur. Ensuite, elle passe à la promesse suivante en accédant à function->context->capability->promise.

Le problème est que la fonction suppose que la fonction "Fermeture de résolution d'élément Promise.all" n'a pas encore été exécutée. Si la fonction "Fermeture de résolution d'élément Promise.all" a déjà été exécutée, le contexte passe de FunctionContext à NativeContext. Cela conduit à une confusion de type entre FunctionContext et NativeContext dans la fonction CaptureAsyncStackTrace.

Réalisation du PoC :

La stratégie pour déclencher la vulnérabilité est la suivante :

  1. Obtenir la fonction "Fermeture de résolution d'élément Promise.all" qui est une fonction native intrinsèque.
  2. Appeler explicitement la fonction "Fermeture de résolution d'élément Promise.all" pour changer le contexte de FunctionContext à NativeContext.
  3. Définir la fonction "Fermeture de résolution d'élément Promise.all" comme gestionnaire d'accomplissement d'une promesse avec une nouvelle chaîne de promesses.
  4. Lever une erreur dans la chaîne de promesses et capturer la trace de pile asynchrone.

J'ai utilisé le motif de résolution synchrone de promesses pour Promise.all afin d'obtenir la fonction "Fermeture de résolution d'élément Promise.all" au niveau du script JS. J'ai emprunté le motif des cas de test test262.

Après avoir appelé explicitement la fonction, pour déclencher la vulnérabilité, j'ai utilisé l'exemple de code dans le [document sur la trace de pile asynchrone à coût zéro][v8 docs] pour préparer une nouvelle chaîne de promesses et définir la fonction native intrinsèque comme gestionnaire d'accomplissement de l'une des promesses.

Télécharger l’outil