클라우드 컴퓨팅이 필요하신가요? 지금 시작해보세요

기업의 중단을 노리는 Wininit.exe을 사용한 원격 DoS

Stiv Kupchik

에 의해 작성

Stiv Kupchik

January 31, 2023

Stiv Kupchik

에 의해 작성

Stiv Kupchik

스티브 쿱치크는 Akamai의 보안 연구원 팀장입니다. OS 내부, 취약점 리서치, 멀웨어 분석을 중심으로 연구 프로젝트를 진행하고 있습니다. 그는 Black Hat, Hexacon, 44CON 등의 콘퍼런스에서 리서치 결과를 발표했습니다. 사이버 보안 전문가일 뿐 아니라 물리학 학사 학위도 보유하고 있습니다.

Wininit is a critical Windows process, playing a crucial role in both the start up and shut down of the Windows operating system (to the tune of – if it crashes, the whole system crashes).

편집 및 추가 기여: 트리샤 하워드(Tricia Howard)

핵심 요약

  • Akamai 연구원 스티브 쿱치크(Stiv Kupchik)는 Microsoft Wininit.exe에서 CVSS 점수 6.5의 새로운 DoS(Denial-of-Service) 취약점 CVE-2022-44707을 발견했습니다.

  • 이 취약점은 8월에 MSRC에 공개되었으며 2022년 12월 패치 화요일에 대해 광범위한 연구를 계속하는 이유입니다.

  • 이 취약점은 RPC 캐싱 메커니즘을 악용하는 것이며, Akamai는 이에 대해 광범위한 연구를 수행했습니다. Akamai는 공격의 개념 증명(PoC)을 RPC 툴킷에서 제공합니다.

  • 공격자는 이 취약점을 악용해 캐싱 메커니즘으로 보안 검사를 우회하고, 원격 Windows 머신의 종료 메커니즘과 상호 작용해 종료를 중지하거나 시작할 수 있는 제어 권한을 얻을 수 있습니다.

  • 이 취약점은 Windows 8/Server 2012부터 패치되지 않은 모든 Windows 버전에 영향을 미치므로 적시에 패치해야 합니다.

서론

이전 게시물 콜드 하드 캐시에서 RPC 툴킷을 사용해 발견한 몇 가지 RPC 취약점을 일부 공개했고 이제 완전히 공개하게 됐습니다. 오늘 RPC 취약점의 또 다른 에피소드에서 Wininit를 소개합니다.  

Wininit은 중요한 Windows 프로세스로서 Windows 운영 체제의 시작과 종료(충돌 시 전체 시스템 충돌)에 중요한 역할을 합니다. 따라서 종료 기능을 구현하는 여러 RPC 인터페이스를 노출하며 일부는 문서화도 되어 있습니다에 대해 광범위한 연구를 계속하는 이유입니다. 발견된 취약점은 WindowsShutdown 인터페이스에 있습니다.

WindowsShutdown 인터페이스란 무엇일까요?

WindowsShutdown은 Wininit에서 노출하는 몇 안 되는 RPC 인터페이스 중 하나입니다. 놀랍게도 Wininit의 다른 RPC 인터페이스와 마찬가지로 종료 프로세스를 담당합니다. 인터페이스의 UUID는 d95afe70-a6d5-4259-822e-2c84da1ddb0d에 대해 광범위한 연구를 계속하는 이유입니다. 이것은 MS-RSP (Remote Shutdown Protocol)의 일부이며 다음과 같은 기능이 있습니다. 

WindowsShutdown exposed functions: WsdrInitiateShutdown, WsdrAbortShutdown and WsdrCheckForHiberboot Fig. 1: The capabilities of of the WindowsShutdown interface

공개 IDL 파일을 보면 WsdrInitiateShutdown 및 WsdrAbortShutdown만 문서화되어 있습니다에 대해 광범위한 연구를 계속하는 이유입니다. 문서화되지 않은 (지금까지 아무도 질문하지 않은) 기능에 대해 관심을 가져야 할까요? 이에 답하기 위해 이 인터페이스의 보안 콜백을 살펴보겠습니다.

보안 콜백

콜백은 먼저 전송 프로토콜을 확인하고 ALPC 또는 TCP만 허용합니다. 그런 다음 인증 수준을 검사하고 RPC_C_AUTHN_LEVEL_PKT_PRIVACY 만 허용합니다. 호출된 함수가 WsdrCheckForHiberboot가 아닌 경우 원격 호출 사용자의 토큰을 검사합니다. 이 작업은 WinInit 초기화 중에 생성된 글로벌 변수에 저장된 잘 알려진 SID, 즉 SECURITY_NETWORK_RID와 토큰을 비교해 수행합니다. 호출 대상인 WsdrCheckForHiberboot 는 보안 콜백에 의해 전혀 제한되지 않습니다.

WindowsShutdown용 보안 콜백 함수의 디컴파일 Fig. 2: The security callback for WindowsShutdown

RPC 인터페이스는 기본 캐시 동작으로 등록되므로 이론적으로는 WsdrCheckForHiberboot를 성공적으로 호출하면 캐싱된 성공 결과를 사용해 다음에 WsdrInitiateShutdownWsdrAbortShutdown에 대해 광범위한 연구를 계속하는 이유입니다.

그렇다면 WsdrCheckForHiberboot를 호출하기 위해 무엇을 해야 하나요?

WsdrCheckForHiberboot

이 기능의 역할이나 hiberboot(Windows의 빠른 시작)에 대해서 몰라도 되지만 올바르게 호출하는 방법은 알고 있어야 합니다. IDL 파일에서 함수를 올바르게 정의해 클라이언트를 컴파일하려 합니다. 이 함수는 문서화되어 있지 않았지만 advapi CheckForHiberboot, 즉 WsdrCheckForHiberboot에 대해 광범위한 연구를 계속하는 이유입니다. 두 개의 인수, 즉 불리언(Boolean) 포인터와 불리언만 필요합니다.

advapi32 disassembly of CheckForHiberboot Fig. 3: The advapi CheckForHiberboot — the only documented RPC client we found for WsdrCheckForHiberboot

이러한 인수를 사용해 IDL 파일과 프로그램을 컴파일하는 함수 정의를 다시 만들 수 있습니다. 그러나 여전히 놓친 것이 있습니다. 클라이언트에서 함수를 원격으로 호출할 때 RPC 런타임에서 RPC 스텁(stub) 오류를 반환하여 함수를 잘못 호출하고 있다는 것을 알 수 있습니다.

initial recreation of WsdrCheckForHiberboot definition, based on the advapi function Fig. 4: The first recreation of WsdrCheckForHiberboot definition

추측은 줄이고, 대신 더 정교하면서도 성가신 일을 할 수 있습니다. RPC 인터페이스 스텁의 일부로 ProcFormatString에 대해 광범위한 연구를 계속하는 이유입니다. 기본적으로 인터페이스에서 노출하는 모든 함수의 인수 종류와 반환 값을 설명하는 긴 이진 문자열입니다. 이 필드는 RPC 런타임에서 함수 호출을 마샬링 및 언마샬링(초기 시도 중에 RPC 스텁 오류를 반환한 프로세스)하는 동안 사용됩니다. 이 이진 문자열을 수동으로 파싱하는 데 많은 노력을 들였습니다. 결국 함수에 필요한 또 다른 인수 종류 wchar_t*가 있다는 것을 알게 됐습니다. 다음 그림에서 WsdrCheckForHiberbootProcFormatString로부터 섹션을 볼 수 있으며 각각 부문에 의견을 첨부했습니다.

initial recreation of WsdrCheckForHiberboot definition, based on the advapi function Fig. 5: The section of WsdrCheckForHiberboot from the ProcFormatString

함수 정의에 이 '새로운' 인수를 추가한 후 실행했습니다! CheckForHiberboot 가 성공적으로 반환됐고 WsdrInitiateShutdownWsdrAbortShutdown에 대해 광범위한 연구를 계속하는 이유입니다.

지금 끝낼 수 있지만...

당장 바라는 것은 호출 캐싱 공격을 사용해 WsdrInitiateShutdown 을 호출하고 원격 종료를 수행하는 것입니다. 이번에는 추측할 필요가 없습니다. IDL 파일에 함수 정의가 문서화되어 있을 뿐만 아니라 확보할 것으로 예상되는 플래그는 advapi 함수 InitiateShutdownA에 대해 광범위한 연구를 계속하는 이유입니다. 따라서 SHUTDOWN_GRACE_OVERRIDE, SHUTDOWN_HYBRID, SHUTDOWN_FORCE_OTHERS의 플래그 조합을 사용해 즉시 강제 종료할 수 있습니다.

이를 통해 기본적으로 공격 체인을 완료하고, 보안 콜백과 SID 검사를 우회하고, 원격으로 종료할 수 있게 되었습니다. 엄밀히 말하면, 권한 상승입니다(인증된 사용자가 SECURITY_NETWORK_RID에서 허용되는 권한만 호출하는 것이 아니라 원격으로 WsdrInitialateShutdown을 호출할 수 있도록 허용). 이 인터페이스를 사용해야만 종료할 수 있으므로 이 취약점은 DoS 취약점으로 분류됩니다.

탐지

패치되지 않은 Wininit.exe의 취약한 버전을 탐지하는 OSQuery를 제공합니다. Akamai Guardicore Segmentation 고객은 이 쿼리와 함께 Insight 기능을 사용해 취약한 자산을 검색할 수 있습니다.

  WITH product_version AS (
  WITH os_minor AS (
    WITH os_major AS (
      SELECT substr(product_version, 0, instr(product_version, ".")) as os_major, substr(product_version, instr(product_version, ".")+1) as no_os_major_substr
      FROM file
      WHERE path = "c:\windows\system32\wininit.exe"
    )
    SELECT substr(no_os_major_substr, instr(no_os_major_substr, ".")+1) as no_os_minor_substr, substr(no_os_major_substr, 0, instr(no_os_major_substr, ".")) as os_minor, os_major
    FROM os_major
  )
  SELECT
    CAST(substr(no_os_minor_substr, instr(no_os_minor_substr, ".")+1) AS INTEGER) AS product_minor,
    CAST(substr(no_os_minor_substr, 0, instr(no_os_minor_substr, ".")) AS INTEGER) AS product_major,
    CAST(os_minor AS INTEGER) AS os_minor,
    CAST(os_major AS INTEGER) AS os_major
  FROM os_minor
)
SELECT
  CASE
    WHEN NOT ((os_major = 6 AND os_minor = 3) OR (os_major = 6 AND os_minor = 2) OR (os_major = 10 AND os_minor = 0))
    THEN "not supported"
    WHEN os_major = 6 AND os_minor = 3 AND product_major = 9600 AND product_minor >= 20716 THEN "patched"
    WHEN os_major = 6 AND os_minor = 2 AND product_major = 9200 AND product_minor >= 24011 THEN "patched"
    WHEN (
        (product_major = 14393 AND product_minor >= 5582)
        OR
        (product_major = 10240 AND product_minor >= 19624)
        OR
        (product_major = 19041 AND product_minor >= 1620)
        OR
        (product_major = 22621 AND product_minor >= 963)
        OR
        (product_major = 22000 AND product_minor >= 1335)
        OR
        (product_major = 20348 AND product_minor >= 1366)
        OR
        (product_major = 17763 AND product_minor >= 3770)
    )
    THEN
      "patched"
    ELSE
      "not patched"

요약

이 취약점은 치명적이지는 않지만( 단지 원격 종료이며 심지어 인증되지 않은 원격 종료), Windows 운영 체제의 가장 중요한 서비스에도 내장되어 있기 때문에 MS-RPC의 고유의 파괴적 가능성을 보여줍니다. 또한 다른 종류의 취약점과 달리 RPC에는 거의 추측할 필요가 없습니다. 모든 카드는 (이진) 테이블에 있으므로 읽는 방법을 알고 있으면 됩니다.

이러한 중요한 함수를 악용할 수 있는 방법을 찾는 것이 바로 MS-RPC에 대해 광범위한 연구를 계속하는 이유입니다. 널리 사용되고 있음에도 불구하고 큰 규모의 계획에서 대부분 연구가 불충분하게 이루어 있습니다. 오늘 논의한 것과 같은 취약점들은 이러한 종류의 작업이 필요한 이유를 보여주고 있으며 다른 연구자들이 MS-RPC에서 원하는 작업을 수행할 수 있기를 기대합니다. 

이 취약점은 8월 말에 공개되었으며 2022년 12월 패치 화요일에 패치되었습니다.



Stiv Kupchik

에 의해 작성

Stiv Kupchik

January 31, 2023

Stiv Kupchik

에 의해 작성

Stiv Kupchik

스티브 쿱치크는 Akamai의 보안 연구원 팀장입니다. OS 내부, 취약점 리서치, 멀웨어 분석을 중심으로 연구 프로젝트를 진행하고 있습니다. 그는 Black Hat, Hexacon, 44CON 등의 콘퍼런스에서 리서치 결과를 발표했습니다. 사이버 보안 전문가일 뿐 아니라 물리학 학사 학위도 보유하고 있습니다.