[하루한줄] CVE-2025-2783 : Chrome의 Mojo IPC 내 핸들 검증 미흡으로 인한 샌드박스 탈출

URL

https://blog.securelayer7.net/cve-2025-2783-chrome-mojo-ipc-sandbox/

Target

  • Chrome on Windows < 134.0.6998.177

Explain

Background

이 취약점은 Kaspersky 연구원(Boris Larin, Igor Kuznetsov)이 러시아의 미디어, 교육, 정부 기관을 대상으로 한 “Operation ForumTroll” 공격 캠페인을 분석하던 중 발견된 제로데이 취약점입니다. 공격자는 피해자가 악성 링크를 클릭하는 것만으로(User Interaction 필요) Chrome의 샌드박스 환경을 탈출하여 호스트 시스템에서 임의 코드를 실행하고 시스템을 장악할 수 있었습니다.

Chrome은 보안을 위해 권한이 낮은 Renderer Process와 시스템 접근 권한이 있는 Browser Process로 나뉘어 있으며, 이 둘은 Mojo IPC를 통해 통신합니다. 이 취약점은 Renderer가 조작된 IPC 메시지를 보내 Broker가 의도치 않은 Windows API(DuplicateHandle)를 호출하게 만드는 것이 핵심입니다.

정리하면 공격 흐름은 이렇습니다.

  1. 공격자는 악의적인 파일이나 사이트를 만들어서 크롬 Mojo의 가짜 핸들로 보냅니다.
  2. 이게 열리면, 낮은 권한의 프로세스에서 핸들을 통해 높은 프로세스로 전달됩니다.
  3. 크롬은 핸들을 체크하지 않아서 높은 프로세스는 그 메시지를 허용합니다.
  4. 공격자는 이를 통해 샌드박스를 우회하고 임의 코드를 실행합니다.

Root Cause

Phase 1: 취약한 IPC 인터페이스 (ipcz 레이어)

Chrome은 최근 Mojo의 백엔드로 ipcz(IPCZ: Inter-Process Communication Zero-copy)를 도입했습니다. 공격자는 이 레이어의 NodeLink::RelayMessage 함수를 타겟팅했습니다.

  • 정상적인 흐름:
    IPC 메시지는 MessagePipe를 통해 직렬화되어 전송됩니다. 이때 핸들과 같은 리소스는 OS 레벨에서 복제되어 전달되는데, 수신 측은 메시지 헤더(Message ID)를 보고 어떤 데이터를 기대해야 할지 알고 검증해야 합니다.
  • 취약점 트리거 (Bug):
    공격자는 정의되지 않은 Message ID (0x69)를 포함한 RelayMessage를 생성합니다.

    // 공격자 코드 (Renderer 내부) // ID: 0x69 (Undefined)
    ipcz::Message::Message_unsigned_char__unsigned_long_long_(v23, 0x69, ...); 
    // ... 핸들 데이터 조작 ...
    ipcz::NodeLink::RelayMessage(...); // 메시지 전송

Phase 2: Broker의 검증 부재 및 DuplicateHandle 오용

Browser Process가 이 메시지를 수신했을 때, 핸들러는 0x69 ID를 가진 메시지를 처리하면서 치명적인 실수를 범합니다.

  1. Blind Unmarshalling: 수신 측 함수(0x18001E350)는 메시지 페이로드의 오프셋 0xC8 위치에 있는 값을 WrappedPlatformHandle 객체로 간주하고 읽어들입니다.
  2. 검증 없는 핸들 복제: 읽어들인 값(공격자가 보낸 핸들 값)이 유효한지, 혹은 샌드박스된 프로세스가 접근해서는 안 되는 핸들인지 검증하지 않고 DuplicateHandle API를 호출합니다.

    // Browser Process (취약한 핸들러 의사 코드)
    HANDLE from_message = ExtractHandleFromMsg(message + 0xC8); // 검증 없음
    HANDLE TargetHandle;
    
    // 현재 프로세스(Browser)의 권한으로 핸들을 복제해버림
    if (DuplicateHandle(GetCurrentProcess(), from_message, GetCurrentProcess(), &TargetHandle, ...)) {
        // 성공 시, 공격자가 원하는 핸들이 Browser 프로세스 내에서 유효해짐
    }

이 정에서 공격자는 Broker(Browser) 프로세스가 소유한 강력한 핸들이나, Broker 자신의 프로세스 핸들을 획득하거나 조작할 수 있는 Primitive를 얻게 됩니다.

Exploitation: Code Execution

DuplicateHandle을 통해 Broker 프로세스(혹은 상위 권한 프로세스)에 대한 제어권(Handle)을 얻은 공격자는 다음과 같은 절차로 코드를 실행합니다.

  1. Thread Hijacking: 공격자는 획득한 상위 프로세스의 핸들을 이용해 해당 프로세스 내의 thread contect을 제어합니다.
    • SuspendThread(TargetThread): 타겟 스레드 멈춤
    • GetThreadContext(...): 현재 레지스터 상태 백업
    • SetThreadContext(...): RIP를 ROP 가젯이나 쉘코드가 있는 주소로 변경
  2. Shellcode Injection:
    • WriteProcessMemory: 샌드박스 밖의 메모리 영역에 악성 쉘코드를 씁니다.
    • 가젯(EBFE 등)을 이용해 스레드를 무한루프에 빠뜨리거나 특정 흐름으로 유도한 뒤, 최종적으로 ResumeThread를 호출하여 쉘코드를 실행합니다.

Outro

일반적인 샌드박스 탈출은 커널(Win32k.sys 등) 취약점을 이용하거나, 복잡한 로직 버그를 연쇄적으로 이용해야 합니다. 하지만 이 취약점은 “Mojo IPC 메시지 하나”로 논리적인 권한 상승이 가능했습니다. 따라서 이 취약점은 핸들 유효성에 대해 검증 도입이 되었고

if (!IsValidMojoHandle(handle)) return; // Invalid 메시지 차단

기능 실행 조건 강화는 식으로 패치가 되었습니다.

bool IsEscapeCodeAllowed(const std::string& code) {
    return code == "safe_mode" || code == "internal_debug";
}

Reference

https://nvd.nist.gov/vuln/detail/CVE-2025-2783

https://securelist.com/operation-forumtroll/115989/

https://www.kaspersky.com/blog/forum-troll-apt-with-zero-day-vulnerability/53215/