Skip to content
KitploitKITPLOIT
ИнструментыБлог
Отправить
ИнструментыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

··Ленты·Контакты·Конфиденциальность·© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
cve-2023-5217-poc — PoC для запуска CVE-2023-5217 через интерфейс WebCodecs или MediaRecorder браузера. | Kitploit
Инструменты/GitHubGitHub/ut-security/cve-2023-5217-poc
Анализ уязвимостейЭксплуатацияЭксплуатация веб-приложенийФаззингОбучение и ОбразованиеЭксплуатация Бинарных Файлов
GitHubut-security/cve-2023-5217-poc

cve-2023-5217-poc

PoC для запуска CVE-2023-5217 через интерфейс WebCodecs или MediaRecorder браузера.

Репозиторий
1632 лет назадЕщё не проверено

Популярное

Смотреть все →

Откройте для себя самые используемые инструменты нашего сообщества.

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →
Поделиться

CVE-2023-5217: Эксплойт переполнения кучи при кодировании VP8 в libvpx

CVE-2023-5217 — это эксплуатируемая в реальных условиях уязвимость libvpx, обнаруженная Клеманом Лесинем из Группы анализа угроз Google (Threat Analysis Group), нацеленная на Chrome.

Этот репозиторий показывает, как вызвать CVE-2023-5217 в браузере с помощью API WebCodecs и MediaRecorder. CVE-2023-5217 позволяет выполнить переполнение буфера кучи с контролируемой длиной переполнения и перезаписью повторяющегося малого 4-байтового значения. В настоящее время неизвестно, как CVE-2023-5217 эксплуатировалась в реальных условиях.

Примерно на момент публичного раскрытия было выпущено два патча для libvpx и один для Chromium, которые устраняли CVE-2023-5217. Патчи для libvpx включали отключение изменений количества потоков VP8 и тест для многопоточного кодирования. Патч Chromium отключил регулировку количества потоков в WebCodecs.

Основная проблема в libvpx v1.13.0 «Гадкий утёнок»

Summary

libvpx — это библиотека для кодирования и декодирования VP8/VP9.

Ключевая проблема CVE-2023-5217 заключается в том, что уменьшение количества потоков при одновременном увеличении высоты кадра в сеансе кодирования VP8 в libvpx вызывает линейное переполнение кучи с контролируемой длиной и контролируемой перезаписью повторяющегося малого 4-байтового значения. Разница в высоте кадра контролирует длину перезаписи, а новая ширина кадра контролирует 4-байтовое значение, которое повторно записывается. Эта уязвимость может быть использована несколько раз для последовательной записи различных малых 4-байтовых значений путём уменьшения высоты в каждой последующей конфигурации.

Details

Кодировщик VP8 в libvpx поддерживает массив mt_current_mb_col, который хранит текущий столбец, обрабатываемый потоком кодировщика. Этот массив выделяется только в том случае, если потоков больше одного, и его размер зависит от mb_rows, где mb_rows = frame_height >> 4, а frame_height округляется вверх до ближайшего кратного 16.

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);
  }
  ...
}

После завершения кодирования кадра libvpx сохраняет количество закодированных столбцов плюс mt_sync_range в 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));
  }
  ...
}

Для переполнения mt_current_mb_col требуются три конфигурации кодирования:

  1. configinit: Во время инициализации libvpx устанавливает initial_width и initial_height. Это максимально возможные границы для последующих конфигураций. Количество потоков здесь не имеет значения. Нам нужна промежуточная конфигурация, потому что никакие последующие комбинации ширины/высоты не могут быть больше исходных.

  2. configvuln: При перенастройке, если используется более одного потока, libvpx создаёт уязвимое выделение mt_current_mb_col на основе configvuln.height. Эта новая высота должна быть меньше configinit.initial_height, иначе мы получим ошибку.

  3. configattack: При перенастройке, если используется только один поток, libvpx не будет перераспределять mt_current_mb_col, оставляя его в уязвимом состоянии. libvpx будет многократно записывать значение (configattack.width >> 4) + 1 (где 1 — это переменная mt_sync_range, а ширина округляется вверх до ближайшего кратного 16) за пределы ранее выделенной области, если выполняется следующее условие:

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

Более конкретно: предположим, мы инициализируем конфигурацию кодирования VP8 с configinit с шириной = 1200, высотой = 1200, потоками = 4. Атака выглядит следующим образом:

  1. configvuln перенастраивает кодировщик с шириной = 500 (округлено до 512), высотой = 700 (округлено до 704) и потоками = 2. Переменная mb_rows устанавливается в 704/16=44, массив mt_current_mb_col выделяется размером (44)*4 = 176 байт. Записанное значение, хранящееся в mt_current_mb_col, равно 512/16 + 1 = 33.

  2. configattack перенастраивает кодировщик с шириной = 18 (округлено до 32), высотой = 1000 (округлено до 1008) и потоками = 1. Поскольку mt_current_mb_col перераспределяется только при наличии более одного потока, он остаётся того же размера, но mb_rows теперь устанавливается в 1008/16 = 63. Когда libvpx вызывает encode_mb_row, он перезаписывает (63-44)*4 = 68 байт после выделения mt_current_mb_col, многократно записывая значение 32/16 + 1 = 3, где 32 — округлённая ширина, а 1 — значение mt_sync_range.

  3. Злоумышленник может повторно использовать эту уязвимость с высотой, меньшей, чем в configattack, но всё же большей, чем в configvuln, чтобы записать другое значение. Например, злоумышленник может создать configattack' с шириной = 34 и высотой = 990, установив mb_rows = 992/16 = 62 и mb_cols = 48/16 = 3, записав только (62-44)*4 = 64 байта после исходного выделения значением 4.

Эксплуатация

Для эксплуатации этой уязвимости злоумышленник должен иметь возможность контролировать высоту, ширину и количество потоков кодирования. Первые два параметра контролировать просто, но для последнего требуется найти места, где количество потоков кодирования перенастраивается.

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

В Firefox мы можем контролировать количество потоков, регулируя площадь кадра, который мы кодируем в VP8TrackEncoder. Если площадь кадра больше 307 200 (кадр 640x480) и на машине более 2 ядер, то будет использоваться более одного потока.

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
  }
  ...

Мы обнаружили, что API MediaRecorder использует VP8TrackEncoder, и мы можем изменять ширину и высоту, меняя размер записываемого холста. См. раздел MediaRecorder ниже о том, как это вызвать.

Chrome

Chrome аналогичным образом регулирует количество потоков на основе площади кодируемого кадра с учётом количества ядер.

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;
}

Этот путь используется API WebCodecs VideoEncoding, где мы можем напрямую изменять ширину/высоту кодирования. См. раздел WebCodecs, чтобы узнать, как это работает.

MediaRecorder

Файл mediarecorder.html показывает, как создать сеанс MediaRecorder из холста и изменить ширину/высоту, чтобы вызвать перенастройку кодирования VP8 и тем самым спровоцировать CVE-2023-5217 в уязвимом браузере. При изменении параметров ширины и высоты холста мы используем setTimeout, чтобы гарантировать, что сеанс кодирования VP8 успеет перенастроиться. Параметр таймаута можно настроить для повышения надёжности.

Статус

  • ✅ Firefox: Вызывает крах рендерера Firefox.
  • ❌ Браузеры на Chromium: Браузеры на основе Chromium не изменяют количество потоков при перенастройке кодировщика в сеансе MediaRecorder [code].
  • ❌ Safari: WebKit не поддерживает VP8 для сеансов MediaRecorder [code].

Firefox Demo

Для тестирования в Firefox вы можете использовать fuzzfetch, чтобы получить сборку ASAN до исправления этой CVE, выполнив команду fuzzfetch --build 2023-09-27 -a, а затем открыть mediarecorder.html напрямую.

Firefox demo

WebCodecs

Файлы webcodecs.html и webcodecs.js показывают, как использовать API WebCodecs в Worker для запуска CVE-2023-5217 в уязвимом браузере. У нас больше контроля над вызовами для кодирования кадра в WebCodecs, чем в MediaRecorder, но мы всё ещё полагаемся на таймаут для выполнения каждого из трёх шагов.

Статус

  • ✅ Браузеры на Chromium: Вызывает крах вкладки. Этот патч Chromium для WebCodecs был включён в первоначальный триаж.
  • ❌ Firefox: Firefox не поддерживает кодирование WebCodecs (декодирование включено за конфигурационным флагом).
  • 🚧 Safari: Safari поддерживает кодирование WebCodecs, но мне не удалось вызвать крахи.

Chromium Demo

Для тестирования в Chromium вы можете использовать get_asan_chrome.py, чтобы получить уязвимую версию Chrome с помощью команды python get_asan_chrome.py --version 117.0.5938.131. Затем вам нужно будет запустить локальный HTTP-сервер с SSL. См. gen_server_key.sh и server.py для генерации ключа сервера и запуска сервера. После этого вы можете просто открыть страницу в уязвимом Chromium, чтобы увидеть результат.

Chromium demo

WebCodecs + MediaRecorder Combined

См. combined.html, который использует MediaRecorder как запасной вариант, если WebCodecs не найден. Этот комбинированный файл можно использовать для атаки как на Chrome, так и на Firefox с одной и той же страницы.

Заключение

Эта уязвимость демонстрирует проблемы и опасности предоставления удалённому злоумышленнику доступа к сложным медиа-библиотекам. Используя такие инструменты, как RLBox, браузеры могут изолировать потенциальные уязвимости в медиа-библиотеках. Firefox уже поставляет эту функцию в отдельных библиотеках.

Спасибо за чтение! Приветствуются любые вклады. Не стесняйтесь создавать Issue или открывать PR с любыми другими идеями. Что остаётся изучить — это то, как эта небольшая 4-байтовая перезапись может привести к выполнению кода.

Спасибо Ананду Баладжи за отзывы о предыдущей версии.

Скачать инструмент