VBS 엔클레이브를 악용해 회피성 멀웨어 만들기
목차
서론
VBS(Virtualization-Based Security)는 최근 가장 흥미로운 보안 발전 분야 중 하나입니다. 운영 체제의 중요한 구성요소를 격리할 수 있는 기능 덕분에 Microsoft는 Credential Guard 및 HVCI(Hypervisor-Protected Code Integrity)와 같은 기능을 통해 보안을 상당히 향상할 수 있었습니다.
VBS가 활성화하는 기능 중 간과되기 쉬운 기능은 VBS 엔클레이브 입니다. 이 기술은 프로세스의 특정 영역을 격리해 다른 프로세스, 프로세스 자체, 심지어 커널까지도 접근할 수 없도록 하는 기술입니다.
VBS 엔클레이브는 다양한 보안 응용 분야에 사용될 수 있으며 Microsoft는 논란이 되고 있는 리콜 기능을 포함해 몇 가지 주목할 만한 서비스를 구축하는 데 이 기술을 사용합니다. 또한, Microsoft는 VBS 엔클레이브의 써드파티 개발을 지원하고 적극적으로 도입을 장려하고 있습니다.
엔클레이브는 시스템을 보호하는 데 도움이 될 수 있지만 공격자에게도 매우 매력적일 수 있습니다. 엔클레이브 내부에서 실행되는 멀웨어는 메모리 기반 탐지 및 포렌식 기술에 의해 탐지되지 않을 수 있습니다.
Akamai는 VBS 엔클레이브를 탐색하고 악의적인 목적으로 사용될 수 있는 경우를 이해하기 시작했습니다. 이 블로그 게시물을 통해 Akamai가 발견한 주요 내용을 자세히 설명합니다. Akamai는 이전에 문서화되지 않은 행동을 탐색하고, 공격자가 엔클레이브 내부에서 악성 코드를 실행할 수 있는 다양한 시나리오를 설명하고, ‘엔클레이브 멀웨어’가 사용할 수 있는 다양한 기술을 검토함으로써 VBS 엔클레이브에 대해 자세히 살펴볼 것입니다.
또한, 새로운 접근 방식에 기반한 메모리 회피 기법인 Mirage를 소개합니다. Akamai는 이 기법을 ‘취약한 엔클레이브를 가져오기‘라고 부릅니다. 공격자가 오래된 취약한 버전의 정상적인 엔클레이브를 사용해 이 은밀한 회피 기법을 구축할 수 있는 방법을 살펴보겠습니다.
가상 신뢰 수준
Windows는 전통적으로 사용자 애플리케이션이 OS를 조작하지 못하도록 프로세서 링 레벨에 의존해 왔습니다. 이 하드웨어 기능은 OS와 사용자 애플리케이션을 분리할 수 있게 해줍니다. 커널은 ring3 사용자 모드 애플리케이션과 격리된 ring0에서 실행됩니다. 이 접근 방식의 문제는 커널 악용과 같은 공격자가 OS를 감염시킬 수 있는 비교적 쉬운 경로를 제공한다는 것입니다.
Windows 커널은 매우 풍부한 공격 표면을 노출합니다. 커널 자체에 의해 노출되는 다양한 서비스와 함께 방대한 써드파티 드라이버 목록은 커널 악용의 끊임없는 개발로 이어집니다. 공격자는 이러한 악용을 사용해 잠재적으로 OS의 모든 측면을 제어할 수 있습니다. 사용자/커널 모드의 경계가 불충분하다는 것이 증명되었습니다.
이 문제를 해소하기 위해 Microsoft는 VTL(Virtual Trust Level)이라는 형태로 OS에 추가적인 보안 경계를 도입했습니다. VTL 권한은 메모리 접속을 기반으로 합니다. 각 신뢰 수준은 그 아래에서 실행되는 엔티티에 물리적 메모리에 대한 서로 다른 접속 권한을 제공합니다. 무엇보다도, 이러한 권한은 낮은 VTL이 높은 VTL의 메모리에 접속할 수 없도록 합니다.
기존의 프로세서 링 아키텍처와 마찬가지로 VTL은 OS를 실행의 다른 ‘모드’로 분리하며 VTL0에서 시작해 (잠재적으로) VTL16에서 끝납니다. ring0이 가장 권한이 많은 프로세서 링과 달리 상위 VTL은 하위 VTL보다 더 많이 권한을 가집니다.
현재 Windows는 VTL0과 VTL1의 두 가지 주요 신뢰 수준을 사용합니다(VTL2도 사용되지만, 이 블로그 게시물의 범위를 벗어납니다). VTL0은 커널과 사용자 모드 애플리케이션을 포함한 기존의 OS 구성요소를 실행하는 데 사용됩니다. VTL0보다 더 많은 권한을 가진 VTL1은 보안 커널 모드 및 격리된 사용자 모드라는 두 가지 새로운 실행 모드를 생성합니다.
보안 커널 모드
보안 커널 모드는 ring0 VTL1 실행 모드를 의미합니다. 이 모드는 보안 커널을 실행하는 데 사용됩니다. 보안 커널은 VTL1에서 실행되는 커널이기 때문에 일반 커널보다 더 많은 권한을 가지고 있습니다. 보안 커널은 이러한 권한을 사용해 일반 커널에 정책을 적용하고 민감한 메모리 영역에 대한 접속을 제한할 수 있습니다.
앞서 언급했듯이 커널은 공격에 노출되는 표면이 넓고 감염되기 쉽습니다. 커널의 일부 권한을 제거하고 그 권한을 보안 커널에 부여함으로써 커널 감염으로부터의 영향을 줄일 수 있습니다.
이론적으로 공격자는 여전히 보안 커널의 감염을 통해 시스템을 완전히 감염시킬 수 있습니다. 그럼에도 불구하고 보안 커널이 매우 좁고 써드파티 드라이버를 지원하지 않아 공격 표면이 상당히 감소하기 때문에 이 시나리오의 발생 가능성은 훨씬 작습니다.
격리된 사용자 모드
VTL1은 또 다른 흥미로운 실행 모드인 IUM(Isolated User Mode)을 생성합니다. IUM은 ring3 VTL1 실행 모드를 의미합니다. IUM은 VTL1의 메모리 분리 기능을 사용하는 특별한 종류의 사용자 모드 프로세스인 보안 프로세스를 실행하는 데 사용됩니다. IUM 내부의 메모리는 일반 커널을 포함한 어떤 VTL0 코드도 접속할 수 없습니다. 이 실행 모드는 Credential Guard와 같은 분리 기반 기능의 중추입니다.
요약하면 VTL0/1의 도입으로 네 가지 실행 모드가 생성됩니다(그림 1).
- Ring0 VTL0 - 일반 커널 모드
- Ring0 VTL1 - 보안 커널 모드
- Ring3 VTL0 - 일반 사용자 모드
- Ring3 VTL1 - 격리된 사용자 모드
VBS 엔클레이브란 무엇일까요?
IUM을 통해 활성화되는 또 다른 기능은 VBS 엔클레이브입니다. VBS 엔클레이브는 IUM에 상주하는 사용자 모드 프로세스의 한 부분으로 ‘엔클레이브 모듈’이라고 불리는 DLL을 로딩할 수 있습니다.
모듈이 엔클레이브에 로딩되면 ‘신뢰할 수 있는 실행 환경’이 됩니다. 엔클레이브 내부의 데이터와 코드는 VTL0에서 실행되는 어떤 것도 접근할 수 없으므로, 조작되거나 도난당할 수 없습니다(그림 2). 이 기능은 시스템을 감염시킬 수 있는 공격자로부터 민감한 작업을 격리하는 데 유용합니다.
사용자 모드 프로세스는 전용 Windows API 를 호출해 엔클레이브를 생성하고, 엔클레이브에 모듈을 로딩하고, 엔클레이브를 초기화할 수 있습니다. 엔클레이브 모듈은 이 목적을 위해 특별히 컴파일된 DLL의 형태로 제공됩니다. 엔클레이브가 초기화된 후에는 호스팅 사용자 모드 프로세스가 엔클레이브의 메모리에 접속할 수 없으며 CallEnclave API를 사용해 모듈에서 내보낸 함수를 호출하는 방식으로만 엔클레이브와 상호작용을 할 수 있습니다.
그림 3은 이 프로세스를 구축하는 코드의 예입니다(더 자세한 예시 코드는 Microsoft에서 제공합니다).
Microsoft는 VTL1에 대한 접근을 최대한 제한하려고 하기 때문에 DLL을 엔클레이브에 로딩하려면 Microsoft가 발급한 특별한 인증서를 사용해 적절하게 서명해야 합니다. 그런 서명 없이 모듈을 로딩하려고 하면 실패하게 됩니다. 엔클레이브 모듈에 서명하는 옵션은 신뢰할 수 있는 써드파티에게만 위임됩니다. 흥미롭게도, 이러한 모듈을 로딩할 수 있는 사람 에 대한 제한은 없습니다. 서명이 되어 있는 한, 어떤 프로세스든 임의의 모듈을 엔클레이브에 로딩할 수 있습니다.
엔클레이브 모듈은 시스템과 상호작용을 하거나 시스템에 영향을 미칠 수 있는 능력이 매우 제한적인 작은 ‘계산 단위’로 사용됩니다. 따라서 최소한의 API 세트만 사용할 수 있으며 이로 인해 대부분의 OS 구성요소에 접속할 수 없습니다.
엔클레이브 내부에서 사용할 수 있는 API는 VTL1에 로딩된 전용 라이브러리에서 가져옵니다. 예를 들어, 일반적인 프로세스는 OS에서 서비스를 요청하기 위해 ntdll.dll 라이브러리에 의존하지만 엔클레이브 모듈은 시스템 호출을 통해 보안 커널과 통신하는 데 사용되는 ‘대체’ ntdll인 vertdll.dll 을 사용합니다.
엔클레이브 멀웨어
엔클레이브 멀웨어의 개념은 두 가지 중요한 장점을 제공하기 때문에 공격자에게 확실히 매력적일 수 있습니다.
격리된 메모리 영역에서 실행: 엔클레이브의 주소 공간은 EDR과 분석 툴을 포함해 VTL0에서 실행되는 모든 것에서 접속할 수 없기 때문에 탐지가 훨씬 더 복잡해집니다.
추적 불가능한 API 호출: 엔클레이브 내에서 이루어진 API 호출은 EDR에 보이지 않을 수 있습니다. EDR은 시스템 라이브러리 내에 후크를 배치해 사용자 모드에서 API를 모니터링하고, 드라이버를 사용해 커널의 활동을 모니터링합니다. 엔클레이브 호출은 VTL1에서 수행되고 이러한 ‘후크된’ VTL0 구성요소를 거치지 않기 때문에, 이러한 기술로는 엔클레이브에서 발생한 API 호출을 탐지할 수 없습니다.
그림 4는 이 장점을 보여줍니다. Windows API를 호출하는 일반적인 프로세스는 NTDLL 내부의 후크나 커널 자체를 통해 모니터링할 수 있습니다. 그러나 엔클레이브 모듈은 VTL1 상주 vertdll 을 통과하고 보안 커널에 대한 호출을 호출합니다. 이 두 가지 모두 EDR에서 접속할 수 없습니다.
Akamai는 이러한 잠재력을 인식하고 엔클레이브 멀웨어의 개념을 조사하기 시작했습니다. 엔클레이브를 이러한 목적으로 활용하기 위해서는 두 가지 질문에 답해야 합니다.
- 공격자는 어떻게 엔클레이브 내에서 악성 코드를 실행할 수 있습니까?
- 엔클레이브 내에서 실행되면 공격자는 어떤 기술을 사용할 수 있습니까?
공격자는 어떻게 엔클레이브 내에서 악성 코드를 실행할 수 있습니까?
앞서 언급했듯이, 엔클레이브 모듈을 로딩하려면 Microsoft에서 발급한 인증서로 서명해야 합니다. 즉, 엔클레이브 내에서 자체 코드를 실행할 수 있는 것은 Microsoft에서 승인한 엔티티뿐입니다. 그럼에도 불구하고 공격자는 여전히 몇 가지 옵션을 가지고 있습니다.
첫째, 공격자는 OS 취약점을 이용할 수 있습니다. CVE-2024-49706은 알렉스 이오네스쿠(Alex Ionescu, Winsider Seminars & Solutions에서 근무)가 발견한 취약점으로 공격자는 이를 통해 서명되지 않은 모듈을 엔클레이브에 로딩할 수 있습니다. 이 취약점은 Microsoft에 의해 패치되었지만, 의욕적인 공격자가 향후 유사한 버그를 발견할 수도 있습니다.
두 번째로 간단한 접근 방식은 정상적인 서명을 얻는 것입니다. 이 접근 방식은 Microsoft가 Trusted Signing 플랫폼을 통해 서명 엔클레이브를 써드파티에게 공개하기 때문에 가능합니다. 물론 간단하지는 않지만, 고도로 숙련된 공격자는 Trusted Signing 엔티티에 접속해 자신의 엔클레이브에 서명할 수 있습니다.
이 두 가지 옵션 외에도 Akamai는 공격자가 VBS 엔클레이브 내부에서 코드를 실행하기 위해 사용할 수 있는 두 가지 추가 기술을 탐구했습니다. 바로 디버그 가능한 엔클레이브를 악용하는 방법과 취약한 엔클레이브를 이용하는 방법입니다.
디버그 가능한 엔클레이브 모듈 악용
개발자는 VBS 엔클레이브 모듈을 만들 때 디버그 가능하도록 구성할 수 있습니다. 이 설정을 통해 모듈을 컴파일하면 디버그할 수 있습니다. 엔클레이브 모듈은 VTL1에서 실행되기 때문에 디버거가 엔클레이브 메모리에 접속해 데이터를 가져오거나 브레이크포인트를 설정할 수 없어서 일반적으로 디버그가 불가능합니다. 그림 5는 디버거가 엔클레이브 내부의 메모리 주소에서 읽기에 실패하는 경우의 예를 보여줍니다.
흥미롭게도, 디버그 가능한 엔클레이브 모듈은 실행될 때도 여전히 VTL1에 로딩됩니다. 디버그를 활성화하기 위해, 보안 커널은 디버그 가능한 엔클레이브 모듈에 적용되는 몇 가지 예외를 구축합니다. 예를 들어, 그러한 모듈의 메모리에서 읽으려고 할 때 일반 커널은 요청된 작업을 수행하기 전에 SkmmDebugReadWriteMemory 보안 커널 호출을 실행해 대상 모듈이 실제로 디버그 가능한지 확인합니다.
그림 6에서 이 예를 볼 수 있습니다. 디버거는 디버그 가능한 엔클레이브 모듈을 로딩한 후, 엔클레이브 메모리에서 성공적으로 읽을 수 있습니다.
비슷한 방식으로, 디버그 가능한 엔클레이브 모듈 내의 메모리 권한도 VTL0 프로세스에 의해 수정될 수 있습니다( SkmmDebugProtectVirtualMemory 보안 커널 호출에서 구축된 예외).
Microsoft는 개발자들에게 디버그 가능한 엔클레이브 모듈을 출시하지 말 것을 강력히 권고합니다. 그렇게 하면 엔클레이브의 핵심 목적, 즉 VTL0에서 메모리 섹션을 분리한다는 목적을 저해하게 되기 때문입니다(그림 7). 디버그 가능한 모듈을 사용한다는 것은 모듈이 처리하는 데이터가 쉽게 노출될 수 있다는 것을 의미합니다.
디버그 가능한 엔클레이브 모듈을 실행하는 프로덕션 애플리케이션의 리스크는 분명하지만 공격자는 실제로 VTL1에서 서명되지 않은 코드를 실행하는 등 다른 목적으로 이를 악용할 수 있습니다. 공격자가 어떤 디버그 가능한 서명된 엔클레이브 모듈을 획득하면 다음 네 단계를 수행해 VTL1 코드 실행을 달성할 수 있습니다.
- 엔클레이브 모듈 내 루틴의 주소를 획득합니다. GetProcAddress 사용
- 루틴 메모리 보호를 RWX로 변경합니다
- 임의의 쉘코드로 루틴 코드를 덮어씁니다
- 루틴을 트리거합니다. CallEnclave 사용
그림 8은 이 과정을 구축하는 코드를 보여줍니다.
공격자의 관점에서 명백한 문제는 이것이 양날의 검이라는 것입니다. 공격자가 엔클레이브 메모리에 접속할 수 있는 것처럼 EDR도 접속할 수 있습니다. 그럼에도 불구하고, API 모니터링을 피할 수 있다는 장점이 있습니다. 엔클레이브 모듈에 의해 수행되는 API 호출은 여전히 VTL1 DLL과 보안 커널을 통과하므로 EDR의 가시성이 제한됩니다.
전반적으로, 이 방법은 엔클레이브 내부에서 실행할 때 얻을 수 있는 몇 가지 장점을 활용하는 은밀한 ‘세미 VTL1’ 임플란트를 만드는 데 유용할 수 있습니다.
Akamai는 VirusTotal과 다른 소스를 사용해 디버그 가능한 서명된 엔클레이브 모듈을 식별하려고 시도했지만, 이 글을 쓰는 시점에서는 성공하지 못했습니다. 그러나 충분한 시간이 주어지고 엔클레이브 기술이 널리 도입된다면 결국에는 일부가 유출될 것이라고 가정하는 것이 안전하다고 생각합니다.
취약한 엔클레이브를 가져오기
앞서 설명한 바와 같이 Windows는 신뢰할 수 없는 엔클레이브가 VTL1에 로딩되는 것을 방지하기 위해 서명을 사용합니다. 이 접근 방식은 엔클레이브에만 적용되는 것은 아닙니다. DSE(Driver Signing Enforcement) 를 통해 등장한 이 개념은 신뢰할 수 없는 드라이버가 Windows 커널에서 실행되는 것을 방지합니다.
이러한 장애물을 극복하기 위해 공격자는 BYOVD(Bring Your Own Vulnerable Driver) 기법을 사용하기 시작했습니다. 즉, 공격자는 자신의 드라이버를 로딩할 수 없기 때문에 알려진 취약점이 있는 정상적인 서명된 드라이버를 대신 로딩합니다. 그런 다음 이 취약점을 악용해 커널에서 서명되지 않은 코드를 실행할 수 있습니다.
Akamai는 엔클레이브의 맥락에서 이 접근 방식을 탐구하고자 했습니다. 취약한 서명된 엔클레이브 모듈을 악용해 IUM에서 코드를 실행할 수 있을까요?
첫 번째 단계는 그러한 엔클레이브를 찾는 것이었는데, 이로 인해 CVE-2023-36880 (Microsoft Edge에서 사용하는 VBS 엔클레이브 모듈의 취약점)에 대해 곧 알게 되었습니다. 이 취약점을 통해 공격자는 엔클레이브 내부의 임의의 데이터를 읽고 쓸 수 있습니다. 이 취약점은 Microsoft에서 정보 유출 취약점으로 분류했지만 노트는 제한된 코드 실행으로 이어질 수 있다는 내용도 명시하고 있습니다(그림 9).
이 취약점은 Chrome 보안팀의 알렉스 고프(Alex Gough)가 발견했으며, 그는 이 취약점을 악용하는 방법에 대한 개념 증명(PoC) 도 공유했습니다. Akamai는 이 엔클레이브의 취약한 버전을 VirusTotal에서발견한 후, 코드 실행을 위해 이를 악용하는 시도를 시작했습니다.
Akamai의 아이디어는 읽기/쓰기 프리미티브를 악용해 ROP 체인으로 엔클레이브 스택을 덮어쓰는 것이었습니다. 이를 통해 결국 엔클레이브 내에서 쉘코드를 실행할 수 있게 될 것입니다. 이 옵션을 탐색하는 과정에서 흥미로운 사실을 발견했습니다. 엔클레이브는 ACG(Arbitrary Code Guard)를 사용해 서명되지 않은 코드 실행으로부터 엔클레이브를 보호합니다.
ACG는 동적으로 생성된 코드의 실행을 차단하도록 설계된 보안 방어 기능입니다. 이 코드는 원래 프로세스 실행 파일이나 DLL의 일부가 아니라 런타임에 생성된 코드입니다. ACG는 다음 두 가지 룰을 적용해 구축됩니다.
- 프로세스의 초기 로딩 이후에는 새로운 실행 가능 페이지를 생성할 수 없습니다
- 이미 실행 가능한 페이지는 쓰기 가능 상태가 될 수 없습니다
ACG는 일반 커널에서는 기본적으로 적용되지만 사용자 모드에서는 ACG를 사용하도록 설정된 프로세스에만 적용됩니다. Akamai의 리서치에 따르면 엔클레이브를 포함하는 IUM 프로세스에서는 일반 커널에서와 마찬가지로 ACG가 자동으로 적용되는 것으로 보입니다.
VirtualAlloc을 사용해 엔클레이브 내에서 새로운 RWX 페이지를 할당하려고 하면 이것을 관찰할 수 있습니다. 이 작업은 오류 코드 0x677, STATUS_DYNAMIC_CODE_BLOCKED 로 실패합니다(그림 10). VirtualProtect를 사용해 실행 페이지 권한을 수정하거나 페이지를 실행 가능으로 바꾸려고 하면 동일한 결과가 나타납니다.
이 동작을 이해하기 위해, IUM에서 동적 메모리 할당을 처리하는 보안 커널 함수인 SecureKernel!NtAllocateVirtualMemoryEx를 살펴볼 수 있습니다. 이 함수는 요청된 보호 마스크를 평가하고, 실행 가능한 페이지가 요청된 경우 ACG 오류 STATUS_DYNAMIC_CODE_BLOCKED를 반환합니다. 기존 IUM 페이지의 변경을 방지하기 위해 SkmmProtectVirtualMemory 에도 유사한 검사가 구축되어 있습니다(그림 11).
Akamai는 엔클레이브 내에서 ACG를 우회하고 서명되지 않은 코드를 로딩하는 방법을 찾지 못했습니다. 이론적으로는 전체 ROP 악용이 가능하므로 공격자가 VTL1에서 임의의 API를 호출할 수 있게 될 가능성이 있습니다. 그러나 Akamai는 이 방향을 추구하지 않았습니다. 그럼에도 불구하고, Akamai는 취약한 엔클레이브에 대한 또 다른 흥미로운 애플리케이션을 확인했으며 이 글의 뒷부분에서 이 내용을 논의할 것입니다.
엔클레이브 내에서 실행되면 공격자는 어떤 기술을 사용할 수 있습니까?
Akamai는 엔클레이브가 악성 활동에 이용될 많은 잠재력을 가지고 있을 수 있고, 의욕적인 공격자가 엔클레이브를 실행할 수 있다는 것을 이해한 다음, 이러한 종류의 멀웨어에 어떤 기술이 사용될 수 있는지 연구했습니다.
가장 직접적인 사용 방법은 엔클레이브를 의도된 대로 사용하는 것입니다. 엔클레이브가 공격자로부터 민감한 데이터를 보호할 수 있는 것처럼, 공격자는 VTL0 엔티티로부터 ‘비밀’을 숨기기 위해 엔클레이브를 사용할 수도 있습니다.
이는 EDR의 손이 닿지 않는 곳에 페이로드를 저장하거나, 분석가로부터 숨겨진 암호화 키를 봉인하거나, 민감한 멀웨어 설정을 메모리 덤프에서 제외하는 등 다양한 상황에서 유용할 수 있습니다.
보다 고급 옵션의 경우, 많은 기존의 멀웨어 기법이 엔클레이브 내에서 구축될 수 없습니다. 엔클레이브는 제한된 시스템 API 하위 집합으로 제한되기 때문에 파일, 레지스트리, 네트워킹, 기타 프로세스 등과 같은 주요 OS 구성요소와의 상호 작용이 차단됩니다.
그럼에도 불구하고 IUM에서 실행할 때 얻을 수 있는 장점을 활용할 수 있도록 하는 엔클레이브 내에서 실행할 수 있는 여러 가지 기술이 여전히 있습니다.
VTL0 사용자 모드 메모리 접속
시스템에 대한 접속이 제한되어 있음에도 불구하고, 엔클레이브는 여전히 하나의 중요한 리소스인 프로세스 메모리에 접속할 수 있습니다. 엔클레이브는 VTL0을 포함한 전체 프로세스 주소 공간 내에서 읽기/쓰기 작업을 수행할 수 있습니다.
이 접속에는 몇 가지 제한 사항이 적용됩니다. 엔클레이브 내에서 실행되는 코드는 메모리 권한을 준수하며 이를 변경할 수 없습니다. 즉, 엔클레이브는 쓰기 불가능한 메모리에 쓰거나 실행 불가능한 메모리를 실행 가능 메모리로 바꿀 수 없습니다. 그림 12는 엔클레이브 내에서 실행되는 코드를 보여주고 이러한 다양한 가능성과 제약 사항을 보여줍니다.
Akamai는 VTL0 사용자 모드 메모리에 접속해 여러 유용한 기술을 구축할 수 있습니다. Akamai는 악성 엔클레이브를 대상 프로세스에 로딩해, 은밀하게 모니터링하고 민감한 정보를 훔치거나, 프로세스 내의 값을 패치해 동작을 변경할 수 있습니다.
엔클레이브를 사용해 이러한 기술을 구축하면 상당한 장점이 있습니다. 앞서 설명한 바와 같이, 엔클레이브에서 API를 트리거하면 EDR의 모니터링을 피할 수 있습니다. 이러한 기술의 메모리 접속은 엔클레이브에 의해 수행되기 때문에 보이지 않게 유지될 수 있습니다.
VTL0 사용자 모드 코드 실행
엔클레이브가 적절한 권한을 부여받은 경우 VTL0 사용자 모드 메모리에서 읽기/쓰기가 가능하지만, VTL0에 저장된 코드는 엔클레이브 내에서 실행될 수 없습니다. 실행 권한이 있더라도 마찬가지입니다.
엔클레이브 내에서 VTL0 코드를 실행할 수는 없지만, 이를 ‘원격으로’ 실행할 수 있는 옵션이 엔클레이브에는 있습니다. 엔클레이브는 VTL0 주소로 CallEnclave API를 사용해 일반 사용자 모드 스레드에서 VTL0 코드의 실행을 트리거할 수 있습니다(그림 13).
엔클레이브는 사용자 모드 프로세스를 ‘엔클레이브를 대신해 작동하도록’ 해, 일반적으로 불가능한 방식으로 시스템에 간접 접속할 수 있습니다. 예를 들어, 엔클레이브는 파일에서 읽고, 소켓을 생성하는 등의 작업을 수행하는 VTL0 루틴을 트리거할 수 있습니다.
이 방법으로 사용자 모드 코드를 실행하는 것은 우회 측면에서 장점이 없다는 점에 유의해야 합니다. 사용자 모드 코드는 다른 사용자 모드 코드와 마찬가지로 실행되기 때문에 EDR에 노출될 수 있습니다.
안티 디버그
엔클레이브 멀웨어의 또 다른 흥미로운 응용 분야는 안티 디버그입니다. 엔클레이브 내에서 실행되는 코드는 디버거를 포함한 VTL0 애플리케이션에 접속할 수 없다는 사실은 멀웨어에 상당한 장점을 제공합니다.
엔클레이브에 노출되는 API가 감소하므로 기존의 디버그 방지 기술 중 일부는 엔클레이브에서 사용할 수 없습니다. 예를 들어, NtQueryInformationProcess 또는 IsDebuggerPresent API와 모든 날짜 및 시간 API는 엔클레이브에서 사용할 수 없습니다. 그럼에도 불구하고, 여전히 몇 가지 옵션이 있습니다.
먼저, 프로세스 VTL0 주소 공간에 대한 엔클레이브의 접속을 통해 프로세스 PEB를 수동으로 읽고 ‘BeingDebugged‘ 플래그의 값을 확인할 수 있습니다. 디버거가 탐지되면 엔클레이브가 프로세스를 종료할 수 있습니다.
또 다른 접근 방식은 시간 기반 디버그 방지 기술을 구축하는 것입니다(그림 14). 날짜 및 시간 API는 엔클레이브에서 사용할 수 없지만 rdtsc 어셈블리 명령어를 사용할 수 있습니다. 이 명령어는 부팅 이후 프로세서 클럭 사이클의 수를 반환합니다. 이 명령어를 사용하면 서로 다른 엔클레이브 호출 사이에 소요된 시간을 측정할 수 있고, 상당한 지연이 탐지되면 프로세스를 종료할 수 있습니다.
코드의 중요한 부분을 안티 디버그 체크와 함께 엔클레이브로 옮기면 동적 분석을 거의 완벽하게 방어하는 멀웨어를 만들 수 있습니다. 멀웨어는 엔클레이브를 제대로 실행하기 위해 엔클레이브에 의존하는 반면, 사용자 모드 프로세스는 엔클레이브 내부에서 실행되는 체크를 패치할 수 없습니다. 이 접근법을 올바르게 구축하면 Hyper-V 또는 보안 커널 디버그를 통해서만 무력화할 수 있습니다.
BYOVE - 2라운드
이전 섹션에서는 취약한 엔클레이브 모듈을 이용해서 IUM에서 코드 실행을 시도했습니다. Akamai는 이것이 불가능할 수 있다는 것을 깨닫고 BYOVE의 개념이 다른 응용 분야에 적용될 수 있는지 알아보고 취약한 엔클레이브 모듈을 더 자세히 조사하기로 결정했습니다.
취약점(CVE-2023-36880)은 SealSettings 및 UnsealSettings 함수( 엔클레이브 모듈이 내보냄)에서 비롯됩니다. SealSettings 함수는 데이터 버퍼에 대한 포인터를 받아 암호화한 다음, 그 결과를 호출자가 제공한 대상 주소에 씁니다. UnsealSettings 도 비슷한 방식으로 작동하는데, 제공된 버퍼를 해독한 다음, 지정된 주소에 씁니다.
이 두 함수의 문제는 대상 주소나 소스 버퍼 주소를 검증하지 않아 프로세스 내의 모든 주소( 엔클레이브 내부의 주소 포함)를 가리키도록 한다는 점입니다. 그림 15는 취약한 코드를 보여줍니다. UnsealSettings가 사용자가 제공한 임의의 주소에 memcpy 를 수행합니다.
이 취약점은 공격자에게 두 가지 기능을 제공합니다(그림 16).
엔클레이브 내부의 임의 쓰기: 공격자는 SealSettings 를 호출해 임의의 데이터를 암호화한 다음, UnsealSettings 를 호출해 엔클레이브 내부의 대상 주소를 가리킬 수 있습니다. 이로 인해 원래의 데이터가 엔클레이브 메모리에 기록됩니다.
엔클레이브 내부 임의 읽기: 공격자는 SealSettings를 호출할 수 있으며, 엔클레이브 내부의 주소를 소스 버퍼 포인터로 제공할 수 있습니다. 이 경우 엔클레이브는 엔클레이브 메모리에서 데이터를 암호화해 공격자가 제어하는 위치에 씁니다. 그런 다음 공격자는 UnsealSettings를 호출해 데이터를 해독함으로써 엔클레이브에서 임의의 데이터를 읽을 수 있습니다.
Mirage - VTL1 기반 메모리 회피
VTL1에서 코드를 실행할 수는 없었지만 임의 쓰기 프리미티브는 두 가지 고유한 기능을 제공합니다.
VTL1에 임의의 데이터를 저장할 수 있으며, 이 데이터는 VTL0 엔티티에서 접속할 수 없습니다
VTL1에서 일반 프로세스 주소 공간(VTL0)으로 임의의 데이터를 쓸 수 있으며, 이로 인해 VTL0 엔티티가 이 작업을 모니터링할 수 없습니다
게다가, 이러한 기능은 서명된 엔클레이브 모듈을 로딩함으로써 활성화되기 때문에 공격자가 직접 서명하지 않아도사용할 수 있습니다.
Akamai는 이러한 기능의 잠재력을 증명하기 위해 ‘Mirage’라고 이름 붙인 메모리 스캐닝 회피 기술을 고안해 냈습니다. Mirage는 Gargoyle이라는 회피 기술에서 영감을 얻었습니다. Gargoyle은 무해한 상태와 무기화된 상태 사이를 계속 전환하는 페이로드를 생성합니다(그림 17).
Gargoyle이 실행 가능한 메모리와 실행 불가능한 메모리 사이를 전환하는 방식으로 이 작업을 수행하는 반면, Mirage는 VTL1과 VTL0 메모리 사이를 전환하는 방식으로 유사한 결과를 달성하는 것을 목표로 합니다. 즉, 쉘코드를 VTL1 엔클레이브 메모리에 저장하고, 취약점을 이용해 주기적으로 VTL0으로 다시 전송한 다음, 이를 실행한 후 즉시 VTL0 메모리에서 삭제합니다(그림 18).
이 접근 방식에는 두 가지 주요 장점이 있습니다. 첫째, 페이로드가 대부분의 시간 동안 VTL1에 숨겨져 있기 때문에 메모리 스캔과 덤프에 대한 복원력이 뛰어납니다. 이 점은 Gargoyle 기법보다 우수한 장점입니다. 왜냐하면 페이로드가 휴면 단계에서 ‘탐지되지 않을’ 뿐만 아니라 접근이 불가능하기 때문입니다.
두 번째 장점은 쉘코드를 VTL0에 쓰는 작업이 엔클레이브에 의해 수행된다는 것입니다. 앞서 설명한 바와 같이 EDR은 VTL1에서 실행되는 코드를 모니터링할 수 없기 때문에 일반적인 EDR 후크는 메모리에 쓰여지는 쉘코드를 가로챌 수 없습니다.
Akamai는 Mirage를 위한 PoC 를 개발했습니다(그림 19). 이 PoC는 기법의 이면에 있는 아이디어를 보여주기 위한 것이기 때문에 완전히 무기화되지 않았습니다.
탐지
현재로서는 아주 제한된 수의 애플리케이션이 엔클레이브를 사용하고 있습니다. 더 널리 도입되더라도 임의의 프로세스보다는 특정 프로세스에 의해서만 로딩될 것입니다. 예를 들어 calc.exe 는 VBS 엔클레이브를 로딩하지 않을 것입니다.
이 때문에, 비정상적인 엔클레이브 사용은 훌륭한 탐지 기회가 될 수 있습니다. 보안팀은 VBS 엔클레이브의 알려진 정상적인 사용 방식의 기준을 구축하고, 그 기준에서 벗어나는 모든 것을 표시함으로써 비정상적인 엔클레이브 사용을 활용해야 합니다. 엔클레이브 사용은 엔클레이브 API를 모니터링하는 것과 로딩된 엔클레이브 DLL을 탐지하는 것의 두 가지 방법으로 식별할 수 있습니다.
엔클레이브 API
다음의 API는 호스팅 프로세스에 의해 VBS 엔클레이브를 관리하는 데 사용되며 이러한 엔클레이브가 로딩 중임을 나타낼 수 있습니다.
- CreateEnclave
- LoadEnclaveImageW
- InitializeEnclave
- CallEnclave
- DeleteEnclave
- TerminateEnclave
로딩된 엔클레이브 DLL
비정상적인 엔클레이브 사용을 탐지하는 또 다른 방법은 일반적으로 엔클레이브에서 사용하는 환경 DLL, 즉 Vertdll.dll 및 ucrtbase_enclave.dll의 로딩을 탐지하는 것입니다. 이러한 DLL은 엔클레이브 이외의 다른 것에 의해 사용되지 않아야 하므로, 이 DLL이 존재한다는 것은 해당 프로세스가 이를 사용할 가능성이 높다는 것을 의미합니다.
결론
VBS 엔클레이브는 개발자들이 애플리케이션의 민감한 부분을 보호할 수 있는 놀라운 툴을 제공하지만, 방금 설명한 것처럼 위협적인 공격자가 멀웨어를 ‘보호’하는 데 사용할 수도 있습니다. 이 개념은 현재로서는 대부분 이론적인 개념이지만, 미래에 노련한 위협적 공격자가 악의적인 목적으로 VBS 엔클레이브를 사용할 가능성이 분명히 있습니다.
감사의 메시지
최근 이와 매우 유사한 연구 프로젝트를 수행한 Offsec의 마테오 말비카(Matteo Malvica)와 Outflank의 세드릭 반 복크하벤(Cedric Van Bockhaven)에게 감사의 말씀을 전합니다. 두 부분으로 구성된 시리즈의 첫 번째 블로그 게시물 을 확인하고 Insomni'Hack 2025 이후에 게시될 두 번째 게시물을 기다려 주세요.