Skip to content
KitploitKITPLOIT
OutilsBlog
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é.

··Flux·Contact·Confidentialité·© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
cve-2023-5217-poc — Un PoC pour déclencher CVE-2023-5217 depuis l'interface WebCodecs ou MediaRecorder du navigateur. | Kitploit
Outils/GitHubGitHub/ut-security/cve-2023-5217-poc
Analyse des VulnérabilitésExploitationExploitation d'Applications WebFuzzingApprentissage et ÉducationExploitation de Binaires
GitHubut-security/cve-2023-5217-poc

cve-2023-5217-poc

Un PoC pour déclencher CVE-2023-5217 depuis l'interface WebCodecs ou MediaRecorder du navigateur.

Voir le dépôt
1631il y a 2 ansPas encore vérifié

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

CVE-2023-5217: Preuve de concept de débordement de tas dans l'encodage VP8 de libvpx

CVE-2023-5217 est une vulnérabilité libvpx exploitée in-the-wild qui a été découverte par Clément Lecigne du Google Threat Analysis Group comme ciblant Chrome.

Ce dépôt montre comment déclencher CVE-2023-5217 dans le navigateur en utilisant les API WebCodecs et MediaRecorder. CVE-2023-5217 permet un débordement de tampon de tas avec une longueur de débordement contrôlée et une réécriture d'une petite valeur répétée de 4 octets. On ne sait pas actuellement comment CVE-2023-5217 a été exploitée in-the-wild.

Au moment de la divulgation publique, il y avait deux correctifs dans libvpx et un dans Chromium qui ont corrigé CVE-2023-5217. Les correctifs libvpx incluaient la désactivation des changements du nombre de threads VP8 et un test pour l'encodage multithread. Le correctif Chromium a désactivé l'ajustement du nombre de threads dans WebCodecs.

Problème sous-jacent dans libvpx v1.13.0 Ugly Duckling

Résumé

libvpx est une bibliothèque qui gère l'encodage et le décodage VP8/VP9.

Le problème clé de CVE-2023-5217 est que réduire le nombre de threads tout en augmentant la hauteur de l'image dans une session d'encodage VP8 de libvpx provoque un débordement linéaire du tas d'une longueur contrôlée et une réécriture contrôlée d'une petite valeur répétée de 4 octets. La différence de hauteur d'image contrôle la longueur de la réécriture, et la nouvelle largeur d'image contrôle la valeur de 4 octets qui est écrite de manière répétée. Cette vulnérabilité peut être exploitée plusieurs fois pour écrire continuellement différentes petites valeurs de 4 octets en réduisant la hauteur dans chaque configuration suivante.

Détails

L'encodeur VP8 de libvpx maintient un tableau appelé mt_current_mb_col qui stocke la colonne actuelle en cours de traitement par un thread d'encodeur. Ce tableau n'est alloué que s'il y a plus d'un thread, et sa taille est fonction de mb_rows, où mb_rows = frame_height >> 4 et frame_height est arrondi au multiple de 16 supérieur.

root@kitploit:~
// https://github.com/webmproject/libvpx/blob/6512f994da13e2f27e6a7bd449efee0a374b55b7/vp8/common/alloccommon.c#L85
// The width and height are rounded up to a multiple of 16 and then assigned to `mb_rows` and `mb_cols`
int vp8_alloc_frame_buffers(VP8_COMMON *oci, int width, int height) {
    ...
    // Round up the width/height up to the nearest multiple of 16
    if ((width & 0xf) != 0) width += 16 - (width & 0xf);
    if ((height & 0xf) != 0) height += 16 - (height & 0xf);
    ...
    oci->mb_rows = height >> 4;
    oci->mb_cols = width >> 4;
    ...
}
// https://github.com/webmproject/libvpx/blob/6512f994da13e2f27e6a7bd449efee0a374b55b7/vp8/encoder/onyx_if.c#L1232
// This snippet shows the allocation of `mt_current_mb_col`
void vp8_alloc_compressor_data(VP8_COMP *cpi) {
  ...
  // Only allocate if we have more than 1 thread
  if (cpi->oxcf.multi_threaded > 1) {
    int i;

    vpx_free(cpi->mt_current_mb_col);
    // sizeof(*cpi->mt_current_mb_col) is 4
    CHECK_MEM_ERROR(&cpi->common.error, cpi->mt_current_mb_col,
                    vpx_malloc(sizeof(*cpi->mt_current_mb_col) * cm->mb_rows));
    for (i = 0; i < cm->mb_rows; ++i)
      vpx_atomic_init(&cpi->mt_current_mb_col[i], 0);
  }
  ...
}

Une fois que libvpx a fini d'encoder une image, il stocke le nombre de colonnes encodées plus mt_sync_range dans mt_current_mb_col.

root@kitploit:~
// https://github.com/webmproject/libvpx/blob/6512f994da13e2f27e6a7bd449efee0a374b55b7/vp8/encoder/onyx_if.c#L1212
// Snippet where the mt_sync_range value is set, based on the width.
void vp8_alloc_compressor_data(VP8_COMP *cpi) {
    ...
#if CONFIG_MULTITHREAD
  if (width < 640) {
    cpi->mt_sync_range = 1;
  } else if (width <= 1280) {
    cpi->mt_sync_range = 4;
  } else if (width <= 2560) {
    cpi->mt_sync_range = 8;
  } else {
    cpi->mt_sync_range = 16;
  }
#endif
  ...
}
// https://github.com/webmproject/libvpx/blob/6512f994da13e2f27e6a7bd449efee0a374b55b7/vp8/encoder/encodeframe.c#L560
// Function where the attacker chosen value is written
static void encode_mb_row(...) {
  ...
  const int nsync = cpi->mt_sync_range; // This value is set in vp8_alloc_compressor_data
  vpx_atomic_int rightmost_col = VPX_ATOMIC_INIT(cm->mb_cols + nsync);
  ...
  if (vpx_atomic_load_acquire(&cpi->b_multi_threaded) != 0) {
    current_mb_col = &cpi->mt_current_mb_col[mb_row];
  }
  ...
  if (vpx_atomic_load_acquire(&cpi->b_multi_threaded) != 0) {
    // current_mb_col is a reference to mt_current_mb_col
    vpx_atomic_store_release(current_mb_col,
                             vpx_atomic_load_acquire(&rightmost_col));
  }
  ...
}

Pour faire déborder mt_current_mb_col, nous avons besoin de trois configurations d'encodage :

  1. configinit : Lors de l'initialisation, libvpx définit initial_width et initial_height. Ce sont les limites maximales possibles des configurations ultérieures. Le nombre de threads ici n'a pas d'importance. Nous avons besoin de la configuration intermédiaire car aucune combinaison largeur/hauteur ultérieure ne peut être plus grande que celle avec laquelle nous avons commencé.
  2. configvuln : Lors de la reconfiguration, si plus d'un thread est utilisé, alors libvpx crée l'allocation vulnérable mt_current_mb_col basée sur configvuln.height. Cette nouvelle hauteur doit être inférieure à configinit.initial_height sinon nous obtiendrons une erreur.
  3. configattack : Lors de la reconfiguration, si un seul thread est utilisé, alors libvpx ne réallouera pas mt_current_mb_col le laissant dans un état vulnérable. libvpx écrira de manière répétée la valeur (configattack.width >> 4) + 1 (où 1 est la variable mt_sync_range et la largeur est arrondie au multiple de 16 supérieur) en dehors des limites précédemment allouées lorsque la condition suivante est vérifiée : $$\text{ceil}(\text{config}{\text{init}}.\text{height}/16) \geq \text{ceil}(\text{config}{\text{attack}}.\text{height}/16) \gt \text{ceil}(\text{config}_{\text{vuln}}.\text{height}/16)$$

mt_current_mb_col overflow

Plus concrètement, supposons que nous initialisons une configuration d'encodage VP8 avec configinit avec width = 1200, height = 1200, threads = 4. L'attaque est la suivante :

  1. configvuln reconfigure l'encodeur avec width = 500 (512 arrondi), height = 700 (704 arrondi), et threads = 2. La variable mb_rows est définie à 704/16=44, et le tableau mt_current_mb_col est alloué à (44)*4 = 176 octets. La valeur écrite stockée dans mt_current_mb_col est 512/16 + 1 = 33.
  2. configattack reconfigure l'encodeur avec width = 18 (32 arrondi), height = 1000 (1008 arrondi), et threads = 1. Parce que mt_current_mb_col n'est réalloué que lorsqu'il y a plus d'un thread, il reste de la même taille, mais mb_rows est maintenant défini à 1008/16 = 63. Lorsque libvpx appelle encode_mb_row, il écrasera (63-44)*4 = 68 octets au-delà de l'allocation de mt_current_mb_col, en écrivant de manière répétée la valeur 32/16 + 1 = 3, où 32 est la largeur arrondie, et 1 est la valeur de mt_sync_range.
  3. Un attaquant pourrait ré-exploiter cette vulnérabilité avec une hauteur inférieure à celle de configattack mais toujours supérieure à configvuln pour écrire une autre valeur. Par exemple, un attaquant pourrait créer configattack' avec width = 34 et height = 990, définissant mb_rows = 992/16 = 62 et mb_cols = 48/16 = 3, écrivant seulement (62-44)*4 = 64 octets au-delà de l'allocation originale la valeur 4.

Exploitation

Pour exploiter cette vulnérabilité, un attaquant doit être capable de contrôler la hauteur, la largeur et le nombre de threads d'encodage. Les deux premiers sont simples, mais le dernier nécessite de trouver des endroits où le nombre de threads d'encodage est reconfiguré.

root@kitploit:~
// https://github.com/webmproject/libvpx/blob/67bfb41ed8598edfb25bd6f245f9c39a68808548/vp8/vp8_cx_iface.c#L301
static vpx_codec_err_t set_vp8e_config(VP8_CONFIG *oxcf,
 ...
  oxcf->multi_threaded = cfg.g_threads;

Firefox

Dans Firefox, nous pouvons contrôler le nombre de threads en ajustant la zone d'image que nous encodons dans le VP8TrackEncoder. Si la zone d'image est plus grande que 307 200 (une image 640x480) et que la machine a plus de 2 cœurs, alors plus d'un thread sera utilisé.

root@kitploit:~
// https://searchfox.org/mozilla-central/source/dom/media/encoder/VP8TrackEncoder.cpp#97
nsresult CreateEncoderConfig(...) {
  ...
  int32_t number_of_cores = PR_GetNumberOfProcessors();
  if (aWidth * aHeight > 1920 * 1080 && number_of_cores >= 8) {
    config->g_threads = 4;  // 4 threads for > 1080p.
  } else if (aWidth * aHeight > 1280 * 960 && number_of_cores >= 6) {
    config->g_threads = 3;  // 3 threads for 1080p.
  } else if (aWidth * aHeight > 640 * 480 && number_of_cores >= 3) {
    config->g_threads = 2;  // 2 threads for qHD/HD.
  } else {
    config->g_threads = 1;  // 1 thread for VGA or less
  }
  ...

Nous avons constaté que l'API MediaRecorder repose sur le VP8TrackEncoder, et nous pouvons ajuster la largeur et la hauteur en modifiant la taille du canvas enregistré. Voir la section MediaRecorder ci-dessous pour savoir comment appeler cela.

Chrome

Chrome ajuste de la même manière le nombre de threads en fonction de la zone d'image encodée, ajusté pour le nombre de cœurs.

root@kitploit:~
// https://source.chromium.org/chromium/chromium/src/+/main:media/video/vpx_video_encoder.cc;l=84
EncoderStatus SetUpVpxConfig(...) {
  ...
  // Set the number of threads based on the image width and num of cores.
  config->g_threads = GetNumberOfThreadsForSoftwareEncoding(opts.frame_size);
}

// https://source.chromium.org/chromium/chromium/src/+/main:media/base/video_encoder.cc;drc=f5bdc89c7395ed24f1b8d196a3bdd6232d5bf771;l=33
int GetNumberOfThreadsForSoftwareEncoding(gfx::Size frame_size) {
  int area = frame_size.GetCheckedArea().ValueOrDefault(1);
  // Default to 1 thread for less than VGA.
  int desired_threads = 1;

  if (area >= 3840 * 2160) {
    desired_threads = 16;
  } else if (area >= 2560 * 1080) {
    desired_threads = 8;
  } else if (area >= 1280 * 720) {
    desired_threads = 4;
  } else if (area >= 640 * 480) {
    desired_threads = 2;
  }

  // Clamp to the number of available logical processors/cores.
  desired_threads =
      std::min(desired_threads, base::SysInfo::NumberOfProcessors());

  return desired_threads;
}

Ce chemin est exercé par l'API WebCodecs VideoEncoding, où nous pouvons modifier directement la largeur/hauteur d'encodage. Voir la section WebCodecs pour voir comment cela fonctionne.

MediaRecorder

Le fichier mediarecorder.html montre comment créer une session MediaRecorder à partir d'un canvas et ajuster la largeur/hauteur pour déclencher une reconfiguration d'encodage VP8 afin de déclencher CVE-2023-5217 dans un navigateur vulnérable. Lors du réglage des paramètres de largeur et de hauteur du canvas, nous utilisons un setTimeout pour garantir que la session d'encodage VP8 a suffisamment de temps pour se reconfigurer. Le paramètre de délai d'attente peut être ajusté pour la fiabilité.

Statut

  • ✅ Firefox : Déclenche un crash dans le rendu Firefox.
  • ❌ Navigateurs Chromium : Les navigateurs basés sur Chromium ne changent pas le nombre de threads lors de la reconfiguration de l'encodeur dans une session MediaRecorder [code].
  • ❌ Safari : WebKit ne prend pas en charge VP8 pour les sessions MediaRecorder [code].

Démonstration Firefox

Pour tester sur Firefox, vous pouvez utiliser fuzzfetch pour obtenir une version ASAN avant que cette CVE ne soit corrigée avec la commande fuzzfetch --build 2023-09-27 -a puis ouvrir mediarecorder.html directement.

Firefox demo

WebCodecs

Les fichiers webcodecs.html et webcodecs.js montrent comment utiliser l'API WebCodecs dans un Worker pour déclencher CVE-2023-5217 dans un navigateur vulnérable. Nous avons plus de contrôle sur les appels pour encoder une image dans WebCodecs que dans MediaRecorder, mais nous nous appuyons toujours sur un timeout pour effectuer chacune des trois étapes.

Statut

  • ✅ Navigateurs Chromium : Déclenche un crash de l'onglet. Ce correctif Chromium pour WebCodecs a été inclus dans le triage initial.
  • ❌ Firefox : Firefox ne prend pas en charge l'encodage WebCodecs (le décodage est activé derrière un indicateur de configuration).
  • 🚧 Safari : Safari prend en charge l'encodage WebCodecs, mais je n'ai pas réussi à obtenir de crash.

Démonstration Chromium

Pour tester sur Chromium, vous pouvez utiliser get_asan_chrome.py pour obtenir une version vulnérable de Chrome avec la commande python get_asan_chrome.py --version 117.0.5938.131. Vous devrez ensuite démarrer un serveur HTTP local avec SSL. Voir gen_server_key.sh et server.py pour générer une clé serveur et démarrer un serveur. Ensuite, vous pouvez simplement ouvrir la page dans le Chromium vulnérable pour voir le résultat.

Chromium demo

WebCodecs + MediaRecorder Combined

Voir combined.html qui utilise MediaRecorder comme solution de repli lorsque WebCodecs n'est pas trouvé. Ce fichier combiné serait utilisé pour cibler à la fois Chrome et Firefox avec la même page.

Conclusion

Cette vulnérabilité démontre les défis et les dangers d'exposer des bibliothèques multimédia complexes à un attaquant distant. En utilisant des outils comme RLBox, les navigateurs peuvent isoler les vulnérabilités potentielles dans les bibliothèques multimédia. Firefox propose déjà cela dans certaines bibliothèques.

Merci d'avoir lu ! Les contributions sont les bienvenues. N'hésitez pas à soumettre un Issue ou à ouvrir une PR avec d'autres informations. Ce qu'il reste à explorer est de voir comment cette petite réécriture de 4 octets peut conduire à une exécution de code.

Merci à Anand Balaji pour ses commentaires sur une version antérieure.

Télécharger l’outil