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

호출 및 등록 - WinReg RPC 클라이언트에 대한 릴레이 공격

Stiv Kupchik

에 의해 작성

Stiv Kupchik

October 19, 2024

Stiv Kupchik

에 의해 작성

Stiv Kupchik

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

Akamai의 연구원 스티브 쿱치크(Stiv Kupchik)는 Microsoft의 원격 레지스트리 클라이언트에서 새로운 EoP(Elevation of Privilege) 취약점을 발견했습니다.
Akamai의 연구원 스티브 쿱치크(Stiv Kupchik)는 Microsoft의 원격 레지스트리 클라이언트에서 새로운 EoP(Elevation of Privilege) 취약점을 발견했습니다.

핵심 요약

  • Akamai의 연구원 스티브 쿱치크는 Microsoft의 원격 레지스트리 클라이언트에서 새로운 EoP 취약점인 CVE-2024-43532를 발견했으며, CVSS 점수는 8.8점입니다.

  • 이 취약점은 SMB 전송을 사용할 수 없는 경우 안전하지 않은 구식 전송 프로토콜을 사용하는 WinReg 클라이언트 구축의 폴백 메커니즘을 악용합니다.

  • 공격자는 이 취약점을 악용해 클라이언트의 NTLM 인증 세부 정보를 ADCS(Active Directory Certificate Services)에 전달하고 도메인에서 추가 인증에 활용할 사용자 인증서를 요청할 수 있습니다. Akamai는 개념 증명(PoC)을 Github 리포지터리에 제공합니다.

  • 이 취약점은 2024년 2월에 Microsoft Security Resource Center에 공개되었으며, 2024년 10월 패치 화요일의 일부로 패치되었습니다.

  • 이 취약점은 패치가 적용되지 않은 모든 Windows 버전에 영향을 미칩니다.

  • 이번 연구 결과를 확인할 수 있는 곳으로는 No Hat 컴퓨터 보안 콘퍼런스도 있습니다.

서론

MS-RPC는 Microsoft가 구축한 RPC(Remote Procedure Call) 프로토콜 및 표준입니다. RPC는 프로세스 간 통신 메커니즘의 한 형태로, 프로세스가 다른 프로세스가 호출할 수 있는 기능을 노출할 수 있게 해줍니다. Windows 운영 체제의 핵심 구성요소이며, 의존하는 다수의 서비스에는 서비스 관리자부터 wininit의 종료까지 포함되어 있습니다.

Akamai 팀은 캐싱 공격의 형태로 대규모 공격 기법을 발견한 공격적 리서치와 이에 대한 보안 메커니즘을 분석한 방어적 리서치 등 MS-RPC에 대해 많은 리서치를 수행했습니다.

이번에는 다른 관점에서 RPC를 살펴보고자 했습니다. 서로 다른 컴퓨터 간의 통신 및 작업을 허용하는 모든 프로토콜은 사용자 인증과 관련되어야 하며, 실제로 RPC 프로토콜은 인증정보를 전달하고 그 바인딩 프로세스의 일부로서 인증을 지원합니다. 그러나 인증이 있는 곳에는 인증 릴레이 가능성이 있기 때문에 Akamai는 릴레이 기회를 찾기 시작했습니다.

RPC, 인증,

RPC 세션 사이의 작업은 바인딩으로 처리됩니다의 일부로서 인증을 지원합니다. 클라이언트 애플리케이션은 서버 애플리케이션에 연결해 필요한 RPC 인터페이스에 바인딩하고 특정 기능을 실행하도록 요청합니다(그림 1).

클라이언트 애플리케이션은 서버 애플리케이션에 연결해 필요한 RPC 인터페이스에 바인딩하고 특정 기능을 실행하도록 요청합니다(그림 1). 그림 1: 기본 RPC 호출 프로세스

바인드 요청과 응답은 연결에 필요한 여러 데이터 필드를 전달할 수 있습니다. 일반적으로 인증이 포함되지 않은 경우, RPC 바인딩은 단순히 후속 호출에서 함수 매개변수를 캡슐화하는 데 사용할 전송 구문 을 결정하는 데 사용됩니다.

이 상호 작용에서 빠진 것은 무엇일까요? 당연히 인증입니다! 서버는 클라이언트의 ID와 해당 클라이언트가 요청된 작업을 수행할 수 있는지 여부를 어떻게 알 수 있을까요? 정답: 클라이언트가 바인딩에 보안 맥락(인증)을 특별히 추가하지 않는 한 알 수 없습니다. 기본적으로 모든 RPC 연결은 인증되지 않으며, 모든 RPC 서버에 실제로 인증이 필요한 것은 아닙니다.

인증(또는 RPC 용어로 “보안 맥락 추가”)을 하려면 클라이언트가 바인딩 요청에 추가 데이터를 추가하고 인증 프로토콜(예: NTLM 또는 Kerberos)을 협상하고 인증 프로토콜에 필요한 추가 메타데이터(사용자 이름, 도메인 등, 그림 2 참조)를 삽입해야 합니다.

인증(또는 RPC 용어로 “보안 맥락 추가”)을 하려면 클라이언트가 바인딩 요청에 추가 데이터를 추가하고 인증 프로토콜(예: NTLM 또는 Kerberos)을 협상하고 인증 프로토콜에 필요한 추가 메타데이터(사용자 이름, 도메인 등, 그림 2 참조)를 삽입해야 합니다. 그림 2: RPC 바인딩 요청에 추가되는 인증 메타데이터

리서치 대상 찾기

가장 먼저 해야 할 일은 API 관점에서 인증이 어떤 모습이어야 하는지 이해하는 것입니다. 이는 바인딩 핸들을 생성한 후 클라이언트에서 RpcBindingSetAuthInfo* 함수 중 하나를 호출해 수행됩니다. 이 함수의 설명서를 보면 인증이 제공하는 보안 수준을 나타내는 AuthenticationLevel이라는 필드를 확인할 수 있습니다.

인증을 통한 보안은 단순히 사용자가 존재하고 권한이 있는지 확인하는 것뿐만 아니라 변조를 방지하는 데에도 사용할 수 있습니다. 인증 수준은 단순히 연결이 성공했는지 확인하는 수준(RPC_C_AUTHN_LEVEL_CONNECT)부터 모든 트래픽을 완전히 암호화하고 서명해 변조되지 않도록 하는 수준(RPC_C_AUTHN_LEVEL_PKT_PRIVACY)까지 다양합니다. 물론 공격자는 트래픽에 대한 방어가 없는 전자의 수준에 관심을 가질 것이고, 이는 변조가 가능하다는 것을 의미합니다.

하지만 이야기가 그렇게 간단하지 않습니다. RPC 릴레이 공격은 새로운 개념이 아니기 때문에 Windows의 많은 RPC 클라이언트와 서버는 이미 최고 수준의 인증을 사용하도록 패치되어 릴레이 공격이 성공할 수 없습니다. 어떤 이유에서인지 여전히 안전하지 않은 오래된 코드 덩어리를 찾기 위해 운영 체제를 샅샅이 뒤져야 합니다(그림 3).

어떤 이유에서인지 여전히 안전하지 않은 오래된 코드 덩어리를 찾기 위해 운영 체제를 샅샅이 뒤져야 합니다(그림 3). 그림 3: Windows 서버의 system32 폴더에서 IDAPython 스크립트를 실행해 RPC 안전하지 않은 인증의 인스턴스를 찾습니다. 스크립트는 GitHub 리포지토리에서 찾을 수 있습니다

WinReg - 유력한 후보

예상했던 대로, Akamai가 찾은 잠재적 표적 목록에는 전체 RPC 서버와 클라이언트의 5% 미만이 포함되어 있었고 대부분은 더 이상 안전하지 않은 인증을 사용하지 않습니다. 하지만 Akamai는 advapi32.dll에서 유력한 후보를 발견했습니다.

advapi32.dll 은 Windows API의 핵심 구성요소로, 이름에서 알 수 있듯이 Windows의 많은 “고급” 로직을 구축합니다. 이벤트 로깅, 암호화, WMI 등 다양한 분야에서 800개 이상의 함수를 내보냅니다.

목적상, 경우에 따라 내부 함수 BaseBindToMachine 이 인증 수준이 Akamai가 원하는 RPC_C_AUTHN_LEVEL_CONNECT인 RpcBindingSetAuthInfoA 를 호출한다는 것을 발견했습니다. BaseBindToMachine 은 (문서화되지는 않았지만) 내보낸 함수 RegConnectRegistryExW (그림 4)이 머신 이름에 대한 UNC 경로를 받으면 호출됩니다.

내보낸(문서화되어 있지는 않지만) 함수 RegConnectRegistryExW(그림 4)가 머신 이름에 대한 UNC 경로를 받으면 BaseBindToMachine이 호출됩니다. 그림 4: MSDN에 문서화되어 있지 않은 RegConnectRegistryExW에 대한 Rust 문서

BaseBindToMachine을 살펴보면 실제로 RpcBindingSetAuthInfoWRpcBindingSetAuthInfoA둘 다에 대한 호출을 포함하고 있습니다. 전자는 인증 수준 RPC_C_AUTHN_LEVEL_PKT_PRIVACY를 사용해 안전하게 사용되는 반면, 후자는 연결의 진위성이나 무결성을 확인하지 않으므로 릴레이될 수 있는 인증 수준 RPC_C_AUTHN_LEVEL_CONNECT를 사용합니다(그림 5).

전자는 인증 수준 RPC_C_AUTHN_LEVEL_PKT_PRIVACY를 사용해 안전하게 사용되는 반면, 후자는 연결의 진위성이나 무결성을 확인하지 않으므로 릴레이될 수 있는 인증 수준 RPC_C_AUTHN_LEVEL_CONNECT를 사용합니다(그림 5). 그림 5: 인증 정보를 설정하기 위한 두 가지 호출

두 개의 호출이 충돌하는 이유만 파악하면 됩니다. 함수 로직을 살펴보면 함수 포인터 변수와 함수 배열이 있음을 알 수 있습니다(그림 6). 이러한 함수는 특정 RPC 전송을 사용하도록 RPC 바인딩 정보를 설정합니다. 기본적으로 SMB 및 명명된 파이프를 사용하려고 시도하지만 실패하면 SPX, TCP/IP 등을 통해 바인딩을 시도합니다.

어떤 이유에서인지 SMB가 아닌 다른 프로토콜로 되돌아가면 RpcBindingSetAuthInfoA 를 사용하여 인증 수준을 연결로 설정하는데, 이는 안전하지 않습니다.

두 개의 호출이 충돌하는 이유만 파악하면 됩니다. 함수 로직을 살펴보면 함수 포인터 변수와 함수 배열이 있음을 알 수 있습니다(그림 6). 그림 6: 함수 포인터와 BaseBindToMachine 내부의 함수 배열

TCP/IP로의 폴백은 안전하지 않은 인증 방법을 사용해 클라이언트 몰래 중간자 공격을 통해 트래픽을 릴레이할 수 있다는 점에서 매우 유력합니다. 다른 전송 프로토콜로도 가능하지만, 상당히 구식이기 때문에 최신 네트워크에서 이를 사용하는 것은 비현실적일 수 있습니다(그리고 이를 사용하면 경종을 울릴 수도 있습니다). TCP/IP는 RPC 전송으로 훨씬 더 일반적이므로 공격자 환경에서도 괜찮을 것입니다.

알아 두어야 할 사항은 BaseBindToMachineRegConnectRegistryExW 는 모두 폴백 동작을 방지하는 플래그를 인수로 허용하지만 기본 함수인 RegConnectRegistryW가 RegConnectRegistryExW 를 해당 플래그가 없는 상태에서 호출한다는 점입니다.

릴레이 프로세스

NTLM 릴레이는 일반적인 기술이기 때문에 릴레이는 매우 간단합니다. Akamai가 필요로 하는 대부분의 로직은 이미 Impacket의 ntlmrelayx에 구축되어 있으며, 앞으로 이것을 가장 많이 사용할 것입니다.

RPC 릴레이 서버 구축하기

ntlmrelayx는 SMB 서버만 구축했기 때문에 TCP/IP RPC 서버가 부족합니다. 따라서 TCP/IP 바인딩 기능에 대한 폴백을 트리거하기 위해 winreg라는 명명된 파이프를 거부하는 자체 릴레이 서버를 구축해야 합니다.

세 가지 중요한 포인트를 구축해야 합니다.

  1. RPC 엔드포인트 매퍼

  2. NTLM을 사용한 RPC 바인드 요청

  3. NTLM 챌린지

RPC 엔드포인트 매퍼는 RPC 인터페이스 UUID를 각각의 엔드포인트로 변환하는 역할을 담당하며, TCP/IP 전송의 경우 포트 번호가 됩니다. 엔드포인트가 고유하고 미리 알 수 있는 명명된 파이프인 SMB와 달리, TCP 엔드포인트는 임시 포트를 사용하므로 또 다른 변환 레이어가 필요합니다.

중요한 부분은 NTLM 관련 문제입니다. RPC 바인딩이 NTLM과 함께 작동하는 방식은 바인드 요청 중에 NTLM 협상 메시지가 전송된 다음 바인드 응답과 함께 NTLM 챌린지가 전송되는 것입니다. 마지막으로 클라이언트는 챌린지 응답과 함께 AUTH3라는 또 다른 메시지를 보내야 합니다(그림 7).

클라이언트는 챌린지 응답과 함께 AUTH3라는 또 다른 메시지를 보내야 합니다(그림 7). 그림 7: RPC 바인딩을 통한 NTLM 인증

릴레이를 위해서는 RPC 서버에서 해당 메시지를 파싱하기만 하면 됩니다. 바인드 메시지에서 NTLM 협상 메시지를 확인하면 대상 인증 서버에 대한 자체 연결을 열고 NTLM을 통한 인증도 요청합니다. 그런 다음 서버가 보낸 챌린지를 캡처해 피해자에게 다시 전달하고 응답을 다시 서버로 전달해 자체 인증 세션을 얻기만 하면 됩니다.

인증을 릴레이할 서버만 고려하면 됩니다.

RPC에서 RPC로 릴레이

당장 생각나는 것은 서비스 관리자나 작업 스케줄러와 같은 다른 머신의 다른 RPC 서버로 릴레이해 원격 코드 실행을 달성하는 것입니다. 하지만 이 방법의 문제점은  더 이상 아무도 RPC를 통해 안전하지 않은 인증을 사용하지 않기 때문에 유명 RPC 서버로 릴레이할 수 없다는 것입니다 (RPC를 통한 안전하지 않은 인증이 없다는 점도 리서치 대상이 제한적이었던 이유와 같습니다).

서비스 관리자와 작업 스케줄러 RPC 서버는 모두 RPC_C_AUTHN_LEVEL_PKT_PRIVACY를 요구합니다. RPC_C_AUTHN_LEVEL_PKT_PRIVACY는 클라이언트의 NTLMv2 해시로 전체 트래픽을 암호화하고, NTLMv2 해시는 릴레이를 통해서도 알 수 없습니다. 대신 다른 각도에서 살펴봐야 합니다.

RPC에서 ADCS로

다행히도 SpecterOps의 직원들은 ADCS에 대해, 특히 ADCS에 대한 NTLM 릴레이에 대해 많은 연구를 해왔습니다. 이 기능도 Impacket에서 기본적으로 구축되어 있으므로 인증된 세션을 Impacket의 HTTPAttack 모듈에 전달하기만 하면 저절로 마법이 일어나게 됩니다.

ADCS의 HTTP 웹 서버는 보안이 필요하지 않으며 릴레이 공격에 취약합니다. 이를 악용해 한 번 인증을 받으면 사용자 인증서를 요청할 수 있고 이를 통해 인증을 다시 릴레이하는 수고를 거치지 않고도 자체적으로 인증에 사용할 수 있습니다(그림 8).

이를 악용해 한 번 인증을 받으면 사용자 인증서를 요청할 수 있고 이를 통해 인증을 다시 릴레이하는 수고를 거치지 않고도 자체적으로 인증에 사용할 수 있습니다(그림 8). 그림 8: NTLM 릴레이 공격 후 ADCS에서 인증서 요청 및 받기

이 인증서를 사용해 도메인 컨트롤러의 LDAP 서비스에 인증하고 감염된 도메인에 영구적인 새로운 도메인 관리자를 만들었습니다(그림 9).

이 인증서를 사용해 도메인 컨트롤러의 LDAP 서비스에 인증하고 감염된 도메인에 영구적인 새로운 도메인 관리자를 만들었습니다(그림 9). 그림 9: LDAP 셸을 사용해 새로운 도메인 관리자 만들기

잠재적 영향

advapi의 함수는 그 자체로는 흥미롭지 않으며, 다른 무언가가 이를 사용할 때만 영향을 미칩니다. 재빨리 RegConnectRegistryExW 또는 RegConnectRegistryExA 의 가져오기를 조회하면 최신 도메인 컨트롤러에 아무것도 표시되지 않지만 RegConnectRegistryW 를 검색하면 certutil 및 certsrv(AD CS), EFS, DFS 등과 같은 많은 잠재적 후보를 발견할 수 있습니다.

탐지

원격 레지스트리 서비스는 모든 Windows 머신에서 기본적으로 활성화되어 있지 않습니다. 다음 osquery를 사용해 이 서비스의 상태를 탐지할 수 있습니다.

  SELECT display_name, status, start_type, pid FROM services WHERE name='RemoteRegistry'

그러나 이는 클라이언트 문제이므로 CVE-2024-43532로부터 보호하지 못합니다. 쿼리 결과는 시스템을 강화할 때 고려해야 할 기업 내 원격 레지스트리의 실제 사용 사례를 제시해야 합니다.

취약한 WinAPI를 사용하는 클라이언트를 탐지하려면 다음 YARA 룰을 사용할 수 있습니다.

  import "pe"

rule winreg_client_import {
    meta:
        description =  "Detect binaries that rely on RegConnectRegistry"
        author = "Stiv Kupchik with Akamai Technologies"

    condition:
        pe.is_pe and (
            pe.imports(pe.IMPORT_ANY, "advapi32.dll", "RegConnectRegistryA")
            or pe.imports(pe.IMPORT_ANY, "advapi32.dll", "RegConnectRegistryW")
            or pe.imports(pe.IMPORT_ANY, "advapi32.dll", "RegConnectRegistryExA")
            or pe.imports(pe.IMPORT_ANY, "advapi32.dll", "RegConnectRegistryExW")
        )
    
}

Akamai Guardicore Segmentation 사용자는 RemoteRegistry 서비스로 들어오는 트래픽에 대한 정책 룰을 만들 수도 있습니다(그림 10).

Akamai Guardicore Segmentation 사용자는 RemoteRegistry 서비스로 유입되는 트래픽에 대한 정책 룰도 만들 수 있습니다(그림 10). 그림 10: RemoteRegistry 서비스에 대한 트래픽을 경고하는 세그멘테이션 정책 룰

또한 ETW(Event Tracing for Windows)를 사용해 통신의 클라이언트 및 서버 측 모두에서 RPC 트래픽을 모니터링할 수 있습니다. 이 주제는 Black Hat 2023 의 프레젠테이션과 그와 관련된 블로그 게시물에서 자세히 다루어집니다. 사용자는 RPC 가시성 오픈 소스 툴 을 사용해 RPC 호출을 추적하고 WinReg RPC 인터페이스 UUID {338cd001-2244-31f1-aaaa-900038001003}를 필터링할 수 있습니다.

결론

RPC 프로토콜과 MS-RPC는 보안을 염두에 두고 구축되었지만, 다양한 RPC 인터페이스 구축을 분석하면 시간이 지남에 따라 보안 원칙이 진화하는 것을 분명히 알 수 있습니다. 오늘날 대부분의 RPC 서버와 클라이언트는 안전하지만, 때때로 다양한 수준에서 안전하지 않게 구축된 과거의 잔재를 발견할 수 있습니다.

이 경우, Akamai는 과거 방식에 더 적합한 공격 유형인 NTLM 릴레이를 달성했습니다. 이는 어떤 오래된 인터페이스가 여전히 노출되어 있거나 실행되고 있는지 전혀 알 수 없기 때문에 네트워크 방어는 가능한 한 철저해야 한다는 것을 증명합니다.

공개 타임라인

2024/02/01 - MSRC에 취약점 공개

2024/04/25 - 문서 이슈로 보고서가 종료됨

2024/06/17 - 더 나은 PoC와 설명으로 보고서 다시 오픈

2024/07/08 - 취약점 확인됨

2024/10/08 - 취약점 패치됨

2024/10/19 - 블로그 게시물 게시



Stiv Kupchik

에 의해 작성

Stiv Kupchik

October 19, 2024

Stiv Kupchik

에 의해 작성

Stiv Kupchik

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