갇힌 COM 객체를 통한 파일리스 수평 이동

어둡고 푸른 조명의 사무실에서 태블릿을 들고 노트북에 타이핑하는 남자의 손 클로즈업

1990년대 초부터 Microsoft Windows 개발의 초석이 되어온 COM(구성 요소 개체 모델)은 여전히 최신 Windows 운영 체제와 애플리케이션에서 널리 사용되고 있습니다. COM 구성 요소에 대한 의존도와 수년간의 광범위한 기능 개발로 인해 공격 표면이 넓어졌습니다. 2025년 2월, Google Project Zero의 James Forshaw(@tiraniddo)는 서버 측 DCOM 프로세스의 맥락에서 .NET 관리 코드를 실행하는 데 갇힌 COM 개체를 사용할 수 있는 분산 COM(DCOM) 원격 기술을 악용하는 새로운 방법을 자세히 설명하는 블로그 게시물을 발표했습니다. Forshaw는 권한 확대 및 PPL(Protected Process Light) 우회에 대한 여러 가지 사용 사례를 강조합니다.

Forshaw의 연구를 바탕으로 Mohamed Fakroud(@T3nb3w)는 2025년 3월 초에 PPL 보호를 우회하는 기술 구현을 발표했습니다. Jimmy Bayne(@bohops)와 저는 2025년 2월에 연구를 수행했으며, 그 결과 갇힌 COM 개체를 악용하여 개념 증명 파일리스 수평 이동 기술을 개발할 수 있었습니다.

도입 배경

COM은 기본 프로그래밍 언어에 관계없이 고유한 모듈식 구성 요소를 서로 상호 작용하고 애플리케이션과 상호 작용할 수 있도록 하는 바이너리 인터페이스 표준 및 미들웨어 서비스 계층입니다. 예를 들어 C++로 개발된 COM 개체는.NET 응용 프로그램과 쉽게 인터페이스할 수 있으므로 개발자는 다양한 소프트웨어 모듈을 효과적으로 통합할 수 있습니다. DCOM은 COM 클라이언트가 프로세스 간 통신(IPC) 또는 원격 프로시저 호출(RPC)을 통해 COM 서버와 통신할 수 있도록 하는 원격 기술입니다. 많은 Windows 서비스는 로컬 또는 원격으로 액세스할 수 있는 DCOM 구성 요소를 구현합니다.

COM 클래스는 일반적으로 Windows 레지스트리 내에 등록되고 포함됩니다. 클라이언트 프로그램은 COM 개체라고 하는 COM 클래스의 인스턴스를 만들어 COM 서버와 상호 작용합니다. 이 개체는 표준화된 인터페이스에 대한 포인터를 제공합니다. 클라이언트는 이 포인터를 사용하여 개체의 메서드와 속성에 액세스하여 클라이언트와 서버 간의 통신 및 기능을 용이하게 합니다.

COM 개체는 취약성 노출을 평가하고 악용 가능한 기능을 발견하기 위한 연구 대상이 되는 경우가 많습니다. 갇힌 COM 개체는 COM 클라이언트가 프로세스 외부 DCOM 서버에서 COM 클래스를 인스턴스화하고, 클라이언트가 참조로 마샬링된 개체 포인터를 통해 COM 개체를 제어하는 버그 클래스입니다. 조건에 따라 이 제어 벡터는 보안 관련 논리 결함이 있을 수 있습니다.

Forshaw의 블로그에서는 WaaSRemediation COM 클래스에 노출된 IDispatch 인터페이스가 갇힌 COM 개체 남용 및 .NET 코드 실행을 위해 조작되는 PPL 우회 사용 사례를 설명합니다. WaaSRemediation은 NT AUTHORITY\SYSTEM의 컨텍스트에서 보호된 svchost.exe 프로세스로 실행되는 WaaSMedicSvc 서비스에서 구현됩니다. Forshaw의 뛰어난 워크스루는 개념 증명용 파일리스 수평 이동 기법의 응용 연구 및 개발의 기반이 되었습니다.

컴퓨터를 바라보는 남성

보안 인텔리전스 강화 


매주 Think 뉴스레터에서 보안, AI 등에 대한 뉴스와 인사이트를 확인하고 위협에 한발 앞서 대처하세요. 


연구 개요

저희의 연구 여정은 IDispatch 인터페이스를 지원하는 WaaSRemediation COM 클래스를 살펴보는 것으로 시작되었습니다. 이 인터페이스를 통해 클라이언트는 후기 바인딩을 수행할 수 있습니다. 일반적으로 COM 클라이언트는 컴파일 시 사용 중인 개체에 대한 인터페이스 및 유형 정의가 정의되어 있습니다. 대신 지연 바인딩을 사용하면 클라이언트가 런타임에 개체에 대한 메서드를 검색하고 호출할 수 있습니다. IDispatch에는 ITypeInfo 인터페이스를 반환하는 GetTypeInfo 메서드가 포함되어 있습니다. ITypeInfo에는 이를 구현하는 개체에 대한 형식 정보를 검색하는 데 사용할 수 있는 메서드가 있습니다.

COM 클래스가 형식 라이브러리를 사용하는 경우 클라이언트는 ITYPELib(ITypeInfo-> GetContainingTypeLib에서 가져옴)를 통해 쿼리하여 형식 정보를 검색할 수 있습니다. 또한 유형 라이브러리는 추가 유형 정보를 위해 다른 유형 라이브러리를 참조할 수도 있습니다.

Forshaw의 블로그 게시물에 따르면 WaaSRemediationWaaSRemediationLib 형식 라이브러리를 참조하며, 이는 stdole(OLE 자동화)을 참조합니다. WaaSRemediationLib은 해당 라이브러리의 두 가지 COM 클래스인 StdFontStdPicture를 활용합니다. TreatAs 레지스트리 키를 수정하여 StdFont 개체에 대해 COM Hijacking을 수행하면 클래스가 .NET Framework의 System.Object와 같이 선택한 다른 COM 클래스를 가리킵니다. Forshaw는 StdPicture가 아웃 오브 프로세스 인스턴스화 검사를 수행하기 때문에 StdPicture가 실행 가능하지 않다고 지적했기 때문에 StdFont 사용에 계속 초점을 맞췄습니다.

.NET 개체는 System.ObjectGetType 메서드 때문에 흥미롭습니다. GetType을 통해 .NET 리플렉션을 수행하여 결국 Assembly.Load에 액세스할 수 있습니다. System.Object가 선택되었지만 이 유형은 .NET에서 유형 계층 구조의 루트입니다. 따라서 모든 .NET COM 개체를 사용할 수 있습니다.

초기 단계가 설정되면 HKLM\Software\Microsoft\.NetFramework 키 아래에 두 개의 다른 DWORD 값이 필요하여 저희가 인식한 사용 사례를 실현할 수 있었습니다.

  • AllowDCOMReflection: Forshaw가 언급했듯이 이 활성화된 값을 사용하면 any.NET 메서드 호출에 대한 임의의 리플렉션을 수행할 수 있습니다. 일반적으로 DCOM을 통한 .NET 리플렉션은 MS14-009에서 해결된 완화 조치로 인해 방지됩니다.
  • OnlyUseLatestCLR: Procmon을 사용하여 최신 버전의.NET CLR(버전 4)을 로드하려면 이 값을 활성화해야 한다는 사실을 알게 되었습니다. 그렇지 않으면 기본적으로 버전 2가 로드됩니다.

초기 테스트 작업에서 최신 버전의 CLR 및 .NET을 로드할 수 있음을 확인하자마자 올바른 방향으로 가고 있다는 것을 알 수 있었습니다.

로컬 프로세스에서 원격 컴퓨터로

원격 프로그래밍 측면에 초점을 맞추기 위해 먼저 원격 레지스트리를 사용하여 .NetFramework 레지스트리 키 값을 조작하고 대상 컴퓨터에서 StdFont 개체를 하이재킹했습니다. 다음으로, 원격 대상에서 WaaSRemediation COM 개체를 인스턴스화하고 IDispatch 인터페이스에 대한 포인터를 가져오기 위해 CoCreateInstanceCoCreateInstanceEx로 교체했습니다.

IDispatch에 대한 포인터를 사용하여 GetTypeInfo 멤버 메서드를 호출하여 서버에 갇혀 있는 ITypeInfo 인터페이스에 대한 포인터를 가져옵니다. 이후 호출된 멤버 메서드는 서버 측에서 발생합니다. 관심 있는 포함된 형식 라이브러리 참조(stdole)를 식별하고 관심 있는 후속 클래스 개체 참조(StdFont)를 도출한 후, 결국 ItypeInfo 인터페이스에서 "remotable" CreateInstance 메서드를 사용하여 StdFont 개체 링크 흐름을 리디렉션하여(이전 TreatAs 조작을 통해) System.Object를 인스턴스화했습니다.

AllowDCOMReflection이 제대로 설정되었으므로 DCOM을 통해 .NET 리플렉션을 수행하여 Assembly.Load에 액세스하여 .NET 어셈블리를 COM 서버에 로드할 수 있습니다. DCOM을 통해 Assembly.Load를 사용하고 있기 때문에 어셈블리 바이트 전송이 DCOM 원격 마법에 의해 처리되므로 이 수평 이동 기술은 완전히 파일리스입니다. 개체 인스턴스화에서 반사까지의 기술적 흐름에 대한 자세한 설명은 다음 다이어그램을 참조하세요.

System.Object 클래스 인스턴스화를 보여주는 흐름도
System.Object 클래스 인스턴스화 흐름

개발의 어려움

첫 번째이자 주요 문제는 IDispatch->Invoke를 통해 Assembly.Load_3을 호출하는 것이었습니다. Invoke는 인수의 개체 배열을 대상 함수에 전달하고, Load_3은 단일 바이트 배열을 사용하는 Assembly.Load의 오버로드입니다. 따라서 바이트의 SAFEARRAYVARIANT의 또 다른 SAFEARRAY 내에 래핑해야 했습니다. 처음에는 바이트로 구성된 단일 SAFEARRAY를 계속 전달하려고 했습니다.

Object Byte의 관리되지 않은 동등물을 만드는 방법을 보여주는 코드
관리되지 않는 Object Byte에 해당하는 개체 만들기

또 다른 문제는 적절한 Assembly.Load 과부하를 찾는 것이었습니다. 헬퍼 함수는 GetStaticMethod 함수가 포함된 Forshaw의 CVE-2014-0257 코드에서 가져왔습니다. 이 함수는 DCOM을 통한 .NET 리플렉션을 사용하여 형식 포인터, 메서드 이름 및 매개 변수 수가 주어진 정적 메서드를 찾았습니다. Assembly.Load에는 단일 인수를 사용하는 두 개의 정적 오버로드가 있습니다. 결국 저희는 해키 솔루션을 사용하게 되었습니다. 저희는 단일 인수를 가진 Load의 세 번째 인스턴스가 우리의 올바른 선택이라는 것을 알았습니다.

적절한 Assembly.Load 과부하를 헌팅하는 데 사용되는 코드
적절한 Assembly.Load 과부하 헌팅

운영상의 어려움

이 기술에서 저희가 관찰한 가장 큰 단점 중 하나는 생성된 비콘의 수명이 COM 클라이언트로 제한된다는 것입니다. 이 경우 무기화 바이너리 "ForsHops.exe"의 애플리케이션 수명은 다음과 같습니다. (물론 이름도 우아하게 지었습니다). 따라서 ForsHops.exe가 COM 참조를 정리하거나 종료하면 원격 시스템의 svchost.exe에서 실행 중인 비콘도 정리됩니다. .NET 어셈블리가 메인 스레드를 무기한 중단하고, 다른 스레드에서 셸코드를 실행하고, ForsHops.exe가 익스플로잇 스레드를 중단된 상태로 두는 등 다양한 솔루션을 시도했지만, 아무 소용이 없었습니다.

.NET 로더 메인 스레드가 중단되고 셸코드는 별도의 스레드에서 실행
.NET 로더 메인 스레드가 중단되고 셸코드는 별도의 스레드에서 실행

현재 상태에서 ForsHops.exe는 비콘이 종료될 때까지 실행되며, 그 시점이 지나면 레지스트리 작업을 제거합니다. 개선의 여지가 있지만 독자를 위한 연습 문제로 남겨 두겠습니다.

ForShops.exe 실행 데모
ForShops.exe 실행
Windows 2019 Server의 성공적인 비콘
Windows 2019 Server의 성공적인 비콘
PPL svchost 프로세스에서 실행 중인 비콘의 스크린샷
비콘은 PPL svchost 프로세스에서 실행됩니다
비콘 종료 후 변경 사항을 제거하는 ForShops.exe의 예
비콘 종료 후 변경 사항을 제거하는 ForShops.exe

방어적 권장 사항

Mohamed Fakroud가 구현을 발표한 후 Samir Bousseaden(@SBousseaden)이 제안한 탐지 지침도 이 수평 이동 기술에 적용됩니다.

  • WaaSMedicSvcsvchost.exe 프로세스 내에서 CLR 로드 이벤트 감지
  • 다음 키의 레지스트리 조작(또는 생성) 감지: HKLM\SOFTWARE\Classes\CLSID\{0BE35203-8F91-11CE-9DE3-00AA004BB851}\TreatAs(StandardFont CLSID의 TreatAs 키)

또한 다음과 같은 추가 제어 기능을 구현하는 것이 좋습니다.

  • HKLM\SOFTWARE\Classes\CLSID\{0BE35203-8F91-11CE-9DE3-00AA004BB851}의 DACL 조작 감지
  • HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework에서 활성화된 OnlyUseLatestCLRAllowDCOMReflection 값의 존재 여부를 검색합니다.
  • 가능한 경우 호스트 기반 방화벽을 사용하여 DCOM 임시 포트 액세스를 제한합니다.

또한 다음 개념 증명 YARA 규칙을 활용하여 표준 ForsHops.exe 실행 파일을 탐지합니다.

rule Detect_Standard_ForsHops_PE_By_Hash

{
    meta:   
        description = "Detects the standard ForShops PE file by strings"
        reference = "GitHub Project: https://github.com/xforcered/ForsHops/"
    strings:
        $s1 = "System.Reflection.Assembly, mscorlib" wide
        $s2 = "{72566E27-1ABB-4EB3-B4F0-EB431CB1CB32}" wide
        $s3 = "{34050212-8AEB-416D-AB76-1E45521DB615}" wide
        $s4 = "GetType" wide
        $s5 = "Load" wide

    condition:
        all of them
}

결론

저희의 구현은 Forshaw의 블로그에서 설명한 COM 남용을 약간 확장하여 PPL 우회를 위해 로컬 실행이 아닌 수평 이동을 위해 갇힌 COM 개체를 활용합니다. 따라서 로컬 실행을 수행하는 구현과 동일한 탐지에 여전히 취약합니다.

ForsHops.exe 개념 증명 수평 이동 코드는 여기에서 찾을 수 있습니다.

승인

이 연구에 대한 피드백을 제공하고 블로그 게시물을 검토해 주신 Dwight Hohnstein(@djhohnstein)과 Sanjiv Kawa(@sanjivkawa)에게 감사합니다.

리소스

Mixture of Experts | 12월 12일, 에피소드 85

AI 디코딩: 주간 뉴스 요약

세계적인 수준의 엔지니어, 연구원, 제품 리더 등으로 구성된 패널과 함께 불필요한 AI 잡음을 차단하고 실질적인 AI 최신 소식과 인사이트를 확인해 보세요.

관련 솔루션
엔터프라이즈 보안 솔루션

최대 규모 엔터프라이즈 보안 제공업체의 솔루션으로 보안 프로그램을 혁신하세요.

사이버 보안 솔루션 살펴보기
사이버 보안 서비스

사이버 보안 컨설팅, 클라우드 및 관리형 보안 서비스를 통해 비즈니스를 혁신하고 위험을 관리하세요.

    사이버 보안 서비스 살펴보기
    인공 지능(AI) 사이버 보안

    AI 기반 사이버 보안 솔루션으로 보안팀의 속도, 정확성, 생산성을 향상시키세요.

    AI 사이버 보안 살펴보기
    다음 단계 안내

    데이터 보안, 엔드포인트 관리, ID 및 액세스 관리(IAM) 솔루션 등 어떤 솔루션이 필요하든 IBM의 전문가들이 협력하여 엄격한 보안 태세를 갖추도록 도와드립니다.사이버 보안 컨설팅, 클라우드, 관리형 보안 서비스 분야의 글로벌 리더와 협력하여 기업을 혁신하고 리스크를 관리하세요.

    사이버 보안 솔루션 살펴보기 사이버 보안 서비스 알아보기