Skip to content
KitploitKITPLOIT
ToolsBlog
Einreichen
ToolsBlog
Einreichen

Hacking-, PenTest- und Cybersicherheits-Tools für Ihr Sicherheitsarsenal!

Kitploit ist ein Verzeichnis von Hacking-, Cybersicherheits- und Pentesting-Tools. Entdecken Sie die neuesten Projekt-Updates, um Schwachstellen zu finden, Systeme zu analysieren, Tests zu automatisieren und Ihre Sicherheit zu stärken.

··Feeds·Kontakt·Datenschutz·© 2026 Kitploit

Tool-Verzeichnis

Kategorien

Alle Kategorien anzeigen
Loading categories
cve-2023-5217-poc — Ein PoC zur Auslösung von CVE-2023-5217 aus der Browser-WebCodecs- oder MediaRecorder-Schnittstelle. | Kitploit
Tools/GitHubGitHub/ut-security/cve-2023-5217-poc
SchwachstellenanalyseExploitationWebanwendungs-ExploitationFuzzingLernen & BildungBinary-Exploitation
GitHubut-security/cve-2023-5217-poc

cve-2023-5217-poc

Ein PoC zur Auslösung von CVE-2023-5217 aus der Browser-WebCodecs- oder MediaRecorder-Schnittstelle.

Repository anzeigen
163vor 2 JahrenNoch nicht geprüft

Beliebteste

Alle anzeigen →

Entdecken Sie die meistgenutzten Tools unserer Community.

Alle Tools erkunden

Durchsuchen Sie unsere Tool-Sammlung

Alle Tools anzeigen →
Teilen

CVE-2023-5217: libvpx VP8 Encoding Heap Overflow PoC

CVE-2023-5217 ist eine in-the-wild ausgenutzte libvpx-Schwachstelle, die von Clément Lecigne von Googles Threat Analysis Group entdeckt wurde und auf Chrome abzielt.

Dieses Repository zeigt, wie man CVE-2023-5217 im Browser mit den WebCodecs- und MediaRecorder-APIs auslöst. CVE-2023-5217 ermöglicht einen Heap-Pufferüberlauf mit kontrollierter Überlauflänge und Überschreiben eines wiederholten kleinen 4-Byte-Werts. Es ist derzeit nicht bekannt, wie CVE-2023-5217 in freier Wildbahn ausgenutzt wurde.

Zum Zeitpunkt der öffentlichen Offenlegung gab es zwei Patches in libvpx und einen in Chromium, die CVE-2023-5217 behoben. Die libvpx-Patches umfassten das Deaktivieren von VP8-Thread-Nummern-Änderungen und einen Test für Multithread-Kodierung. Der Chromium-Patch deaktivierte das Anpassen der Thread-Anzahl in WebCodecs.

Grundlegendes Problem in libvpx v1.13.0 Ugly Duckling

Zusammenfassung

libvpx ist eine Bibliothek, die VP8/VP9-Kodierung und -Dekodierung übernimmt.

Das Hauptproblem bei CVE-2023-5217 ist, dass die Reduzierung der Thread-Anzahl bei gleichzeitiger Vergrößerung der Bildhöhe in einer libvpx-VP8-Kodierungssitzung einen linearen Heap-Überlauf mit kontrollierter Länge und kontrolliertem Überschreiben eines wiederholten kleinen 4-Byte-Werts verursacht. Der Unterschied in der Bildhöhe steuert die Länge des Überschreibens, und die neue Bildbreite steuert den 4-Byte-Wert, der wiederholt geschrieben wird. Diese Schwachstelle kann mehrfach ausgenutzt werden, um durch Verringern der Höhe in jeder nachfolgenden Konfiguration kontinuierlich verschiedene kleine 4-Byte-Werte zu schreiben.

Details

Der libvpx-VP8-Kodierer verwaltet ein Array namens mt_current_mb_col, das die aktuelle Spalte speichert, an der ein Codierungs-Thread arbeitet. Dieses Array wird nur zugewiesen, wenn mehr als ein Thread vorhanden ist, und seine Größe ist eine Funktion von mb_rows, wobei mb_rows = frame_height >> 4 und die frame_height auf das nächste Vielfache von 16 aufgerundet wird.

root@kitploit:~
// https://github.com/webmproject/libvpx/blob/6512f994da13e2f27e6a7bd449efee0a374b55b7/vp8/common/alloccommon.c#L85
// Die Breite und Höhe werden auf ein Vielfaches von 16 aufgerundet und dann `mb_rows` und `mb_cols` zugewiesen.
int vp8_alloc_frame_buffers(VP8_COMMON *oci, int width, int height) {
    ...
    // Runde die Breite/Höhe auf das nächste Vielfache von 16 auf
    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
// Dieser Ausschnitt zeigt die Zuweisung von `mt_current_mb_col`
void vp8_alloc_compressor_data(VP8_COMP *cpi) {
  ...
  // Nur zuweisen, wenn wir mehr als 1 Thread haben
  if (cpi->oxcf.multi_threaded > 1) {
    int i;

    vpx_free(cpi->mt_current_mb_col);
    // sizeof(*cpi->mt_current_mb_col) ist 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);
  }
  ...
}

Sobald libvpx die Kodierung eines Bildes abgeschlossen hat, speichert es die Anzahl der kodierten Spalten plus mt_sync_range in mt_current_mb_col.

root@kitploit:~
// https://github.com/webmproject/libvpx/blob/6512f994da13e2f27e6a7bd449efee0a374b55b7/vp8/encoder/onyx_if.c#L1212
// Ausschnitt, in dem der Wert von mt_sync_range basierend auf der Breite gesetzt wird.
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
// Funktion, in der der vom Angreifer gewählte Wert geschrieben wird
static void encode_mb_row(...) {
  ...
  const int nsync = cpi->mt_sync_range; // Dieser Wert wird in vp8_alloc_compressor_data gesetzt
  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 ist eine Referenz auf mt_current_mb_col
    vpx_atomic_store_release(current_mb_col,
                             vpx_atomic_load_acquire(&rightmost_col));
  }
  ...
}

Um mt_current_mb_col zum Überlaufen zu bringen, benötigen wir drei Codierungskonfigurationen:

  1. configinit: Während der Initialisierung setzt libvpx initial_width und initial_height. Dies sind die maximal möglichen Grenzen späterer Konfigurationen. Die Anzahl der Threads spielt hier keine Rolle. Wir brauchen die Zwischenkonfiguration, da keine späteren Breiten-/Höhenkombinationen größer sein können als das, womit wir begonnen haben.
  2. configvuln: Während der Neukonfiguration wird libvpx bei Verwendung von mehr als einem Thread die anfällige mt_current_mb_col-Zuweisung basierend auf configvuln.height erstellen. Diese neue Höhe muss kleiner sein als configinit.initial_height, sonst erhalten wir einen Fehler.
  3. configattack: Während der Neukonfiguration wird libvpx bei Verwendung von nur einem Thread mt_current_mb_col nicht neu zuweisen und sie in einem anfälligen Zustand belassen. libvpx wird wiederholt den Wert (configattack.width >> 4) + 1 (wobei 1 die Variable mt_sync_range ist und die Breite auf das nächste Vielfache von 16 aufgerundet wird) außerhalb der zuvor zugewiesenen Grenzen schreiben, wenn die folgende Bedingung erfüllt ist:
root@kitploit:~
\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

Konkreter: Angenommen, wir initialisieren eine VP8-Kodierungskonfiguration mit configinit mit width = 1200, height = 1200, threads = 4. Der Angriff läuft wie folgt ab:

  1. configvuln konfiguriert den Kodierer neu mit width = 500 (512 aufgerundet), height = 700 (704 aufgerundet) und threads = 2. Die Variable mb_rows wird auf 704/16 = 44 gesetzt, und das Array mt_current_mb_col wird mit (44)*4 = 176 Bytes zugewiesen. Der geschriebene Wert in mt_current_mb_col ist 512/16 + 1 = 33.
  2. configattack konfiguriert den Kodierer neu mit width = 18 (32 aufgerundet), height = 1000 (1008 aufgerundet) und threads = 1. Da mt_current_mb_col nur neu zugewiesen wird, wenn mehr als ein Thread vorhanden ist, bleibt es gleich groß, aber mb_rows wird nun auf 1008/16 = 63 gesetzt. Wenn libvpx encode_mb_row aufruft, werden (63-44)*4 = 68 Bytes über die mt_current_mb_col-Zuweisung hinaus überschrieben, wobei wiederholt der Wert 32/16 + 1 = 3 geschrieben wird (32 ist die aufgerundete Breite, 1 der mt_sync_range-Wert).
  3. Ein Angreifer könnte diese Schwachstelle erneut ausnutzen, indem er eine Höhe verwendet, die kleiner als die in configattack, aber immer noch größer als configvuln ist, um einen anderen Wert zu schreiben. Beispielsweise könnte ein Angreifer configattack' mit width = 34 und height = 990 erstellen, mb_rows = 992/16 = 62 und mb_cols = 48/16 = 3 setzen und (62-44)*4 = 64 Bytes über die ursprüngliche Zuweisung hinaus den Wert 4 schreiben.

Ausnutzung

Um diese Schwachstelle auszunutzen, muss ein Angreifer in der Lage sein, die Kodierungshöhe, -breite und die Anzahl der Threads zu kontrollieren. Die ersten beiden sind einfach, aber letzteres erfordert das Auffinden von Stellen, an denen die Anzahl der Kodierungs-Threads neu konfiguriert wird.

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

In Firefox können wir die Anzahl der Threads steuern, indem wir den Bildbereich anpassen, den wir im VP8TrackEncoder kodieren. Wenn der Bildbereich größer als 307.200 (ein 640x480-Bild) ist und der Rechner mehr als 2 Kerne hat, wird mehr als ein Thread verwendet.

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 für > 1080p.
  } else if (aWidth * aHeight > 1280 * 960 && number_of_cores >= 6) {
    config->g_threads = 3;  // 3 threads für 1080p.
  } else if (aWidth * aHeight > 640 * 480 && number_of_cores >= 3) {
    config->g_threads = 2;  // 2 threads für qHD/HD.
  } else {
    config->g_threads = 1;  // 1 thread für VGA oder weniger.
  }
  ...

Wir haben festgestellt, dass die MediaRecorder-API auf dem VP8TrackEncoder basiert, und wir können Breite und Höhe anpassen, indem wir die Größe der aufgenommenen Canvas ändern. Siehe Abschnitt MediaRecorder unten, um zu erfahren, wie man dies aufruft.

Chrome

Chrome passt die Anzahl der Threads ebenfalls basierend auf dem zu kodierenden Bildbereich an, korrigiert um die Anzahl der Kerne.

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);
  // Standardmäßig 1 Thread für weniger als 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;
  }

  // Begrenzung auf die Anzahl der verfügbaren logischen Prozessoren/Kerne.
  desired_threads =
      std::min(desired_threads, base::SysInfo::NumberOfProcessors());

  return desired_threads;
}

Dieser Pfad wird von der WebCodecs VideoEncoding-API genutzt, bei der wir die Kodierungsbreite/-höhe direkt ändern können. Siehe Abschnitt WebCodecs, um zu sehen, wie dies funktioniert.

MediaRecorder

Die Datei mediarecorder.html zeigt, wie man eine MediaRecorder-Sitzung aus einer Canvas erstellt und die Breite/Höhe anpasst, um eine VP8-Kodierungsneukonfiguration auszulösen, die CVE-2023-5217 in einem anfälligen Browser auslöst. Beim Anpassen der Canvas-Breiten- und -Höhenparameter verwenden wir ein setTimeout, um sicherzustellen, dass die VP8-Kodierungssitzung genügend Zeit für die Neukonfiguration hat. Der Timeout-Parameter kann für die Zuverlässigkeit angepasst werden.

Status

  • ✅ Firefox: Löst einen Absturz im Firefox-Renderer aus.
  • ❌ Chromium-basierte Browser: Chromium-basierte Browser ändern die Anzahl der Threads nicht, wenn der Kodierer in einer MediaRecorder-Sitzung neu konfiguriert wird [Code].
  • ❌ Safari: WebKit unterstützt VP8 für MediaRecorder-Sitzungen nicht [Code].

Firefox Demo

Um auf Firefox zu testen, kannst du fuzzfetch verwenden, um einen ASAN-Build vor der Behebung dieser CVE zu erhalten, mit dem Befehl fuzzfetch --build 2023-09-27 -a und dann mediarecorder.html direkt öffnen.

Firefox demo

WebCodecs

Die Dateien webcodecs.html und webcodecs.js zeigen, wie man die WebCodecs-API in einem Worker verwendet, um CVE-2023-5217 in einem anfälligen Browser auszulösen. Wir haben mehr Kontrolle über die Aufrufe zum Kodieren eines Bildes in WebCodecs als bei MediaRecorder, verlassen uns aber dennoch auf einen Timeout, um die drei Schritte durchzuführen.

Status

  • ✅ Chromium-basierte Browser: Löst einen Tab-Absturz aus. Dieser Chromium-Patch für WebCodecs war in der ersten Untersuchung enthalten.
  • ❌ Firefox: Firefox unterstützt keine WebCodecs-Kodierung (Dekodierung ist hinter einer Konfigurations-Flag aktiviert).
  • 🚧 Safari: Safari unterstützt WebCodecs-Kodierung, aber ich konnte keine Abstürze erzeugen.

Chromium Demo

Um auf Chromium zu testen, kannst du get_asan_chrome.py verwenden, um eine anfällige Version von Chrome mit dem Befehl python get_asan_chrome.py --version 117.0.5938.131 zu erhalten. Du musst dann einen lokalen HTTP-Server mit SSL starten. Siehe gen_server_key.sh und server.py um einen Serverschlüssel zu generieren und einen Server zu starten. Dann öffne einfach die Seite im anfälligen Chromium, um das Ergebnis zu sehen.

Chromium demo

WebCodecs + MediaRecorder kombiniert

Siehe combined.html, das MediaRecorder als Fallback verwendet, wenn WebCodecs nicht gefunden wird. Diese kombinierte Datei würde verwendet, um sowohl Chrome als auch Firefox mit derselben Seite anzugreifen.

Fazit

Diese Schwachstelle zeigt die Herausforderungen und Gefahren, die mit der Offenlegung komplexer Medienbibliotheken für einen entfernten Angreifer verbunden sind. Mit Tools wie RLBox können Browser potenzielle Schwachstellen in Medienbibliotheken isolieren. Firefox liefert dies bereits in ausgewählten Bibliotheken aus.

Danke fürs Lesen! Beiträge sind willkommen. Sie können gerne ein Issue einreichen oder einen PR mit weiteren Erkenntnissen öffnen. Es bleibt zu erforschen, wie diese kleine 4-Byte-Überschreibung zu Codeausführung führen kann.

Dank an Anand Balaji für Feedback zu einem früheren Entwurf.

Tool herunterladen