Windows Management Instrumentation (WMI)
Last updated
Last updated
Common Information Model (CIM)
a. General information
b. New-CimSession
c. New-CimSessionOption
Invoke-CimMethod
Operating system classes
a. Win32_Process method
Create method
b. Win32_Product method
Install method
c. Win32_Service method
d. ScheduledTasks
In this section, I will attempt to explain and illustrate how we can utilize the Windows Management Instrumentation (WMI) to perform lateral movement in an AD environment, to the best of my understanding. As this is a relatively new topic to me (as of 15/08/2025), I will try my best to consolidate what I can understand about the various commands and options. The primary resource will be the TryHackMe's "lateral movement and pivoting" room:
Refer to the links outlined in the Resources section above, to view the official documentation for the various commands used in this page.
First, we need to create a PSCredential object with a specified username and password, and store it in the $credential
variable. This variable will be used in a later command.
PSCredential is a class under the
System.Management.Automation
namespace, which "Offers a centralized way to manage usernames, passwords, and credentials."
$username = 'admin_name'
$password = 'admin_password'
$securePassword = convertTo-SecureString $password -AsPlainText -Force;
# create a new System.Management.Automation.PSCredential object with the specified username and password - store in the $credential variable
$credential = New-Object System.Management.Automation.PSCredential $username, $securePassword;
Now, we can establish a WMI session that will be stored in the $Session
variable. This variable can be supplied to our future commands, allowing us to perform actions as the authenticated user:
# (1) Configure connection options
$Opt = New-CimSessionOption -Protocol Dcom
# (2) Establish a new session against a remote host - store in $Session variable
$Session = New-CimSession -ComputerName TARGET -Credential $credential -SessionOption $Opt -ErrorAction Stop
a. New-CimSessionOption
The value provided to the -Protocol
option can be of the following values: Dcom, Wsman, Default.
The following outlines the difference between the Dcom and Wsman options (information retrieved from the TryHackMe room):
1) Dcom
RPC over IP will be used for connecting to WMI. This protocol uses port 135/TCP and ports 49152-65535/TCP, just as explained when using sc.exe
2) Wsman
WinRM will be used for connecting to WMI. This protocol uses ports 5985/TCP (WinRM HTTP) or 5986/TCP (WinRM HTTPS)
b. New-CimSession
-ComputerName
: Specifies the name of the computer to which to create the CIM session.
-Credential
: Specifies a user account that has permission to perform this action.
It can be specified with a range of formats (refer to the official documentation for the full list of formats). In our case, we are using the PSCredential object.
-SessionOption
: Sets advanced options for the new CIM session.
-ErrorAction
: ...
Now, we can use the $Session
variable to to perform various WMI actions as an authenticated user.
The Invoke-CimMethod
can be used to invoke a method of a CIM class. This command will be used for many of the techniques discussed in the below sections. In this section, I will outline a few commonly used options:
a. -CimSession
: Runs the command using the specified CIM session.
This will be the $Session
variable we have created previously
b. -ClassName
: Specifies the name of the CIM class for which to perform the operation.
Refer to "Operating system classes" in the resources link above
The techniques discussed below will utilize the following classes:
Win32_Process
Win32_Service
Win32_Product
c. -MethodName
: Specifies the name of the CMI method to invoke. This parameter is mandatory and cannot be null or empty.
Take note of the following:
-CimSession $Session
: specifies the session object created earlier
-ClassName Win32_xxxx
: specifies the class
The available values that can be provided to the -Arguments
option will differ based on the class.
The available options for the current class can be found from the documentations outlined in the Resources section above
Win32_Process
)From the official documentation: For security reasons the Win32_Process.Create method cannot be used to start an interactive process remotely.
Due to the security implementation, it appears that this technique may not work on all systems
This process uses the following ports:
135/TCP, 49152-65535/TCP (DCERPC)
5985/TCP (WinRM HTTP) or 5986/TCP (WinRM HTTPS)
and requires the specified user to be in the Administrators group.
a. First, we can create a new variable to store the command that we wish to execute on the remote machine:
PS> $Command = "<command_to_execute>"
b. Create a new process with the Invoke-CimMethod
command:
PS> Invoke-CimMethod -CimSession $Session -ClassName Win32_Process -MethodName Create -Arguments @{
CommandLine = $Command
}
Win32_Service
)This process uses the following ports:
135/TCP, 49152-65535/TCP (DCERPC)
5985/TCP (WinRM HTTP) or 5986/TCP (WinRM HTTPS)
and requires the specified user to be in the Administrators group.
a. Create a service
PS> Invoke-CimMethod -CimSession $Session -ClassName Win32_Service -MethodName Create -Arguments @{
Name = "servicename";
DisplayName = "displayname";
PathName = "payload"; # payload value
ServiceType = [byte]::Parse("16"); # Win32OwnProcess: Start service in a new process
StartMode = "Manual" # start with the StartService method (refer below)
}
b. Retrieve a handle on the service (get the service instance that be specified as an argument to start it later on)
PS> $Service = Get-CimInstance -CimSession $Session -ClassName Win32_Service -filter "Name LIKE 'servicename'"
Replace 'servicename' with the apprioprate value
c. Start the service
PS> Invoke-CimMethod -InputObject $Service -Methodname StartService
-InputObject
: Specifies a CIM instance object to use as input
d. Stop/delete the service
PS> Invoke-CimMethod -InputObject $Service -MethodName StopService
PS> Invoke-CimMethod -InputObject $Service -MethodName Delete
This process uses the following ports:
135/TCP, 49152-65535/TCP (DCERPC)
5985/TCP (WinRM HTTP) or 5986/TCP (WinRM HTTPS)
and requires the specified user to be in the Administrators group.
a. Create the task
# 1. Define the command to execute, along with the related arguments
PS> $Command = "<command>"
PS> $Args = "<args>"
PS> $Action = New-ScheduledTaskAction -CimSession $Session -Execute $Command -Argument $Args
b. Register and start the scheduled task
PS> Register-ScheduledTask -CimSession $Session -Action $Action -User "NT AUTHORITY\SYSTEM" -TaskName "<taskname>"
PS> Start-ScheduledTask -CimSession $Session -TaskName "<taskname>"
-User
: Specifies the name of the user account in the context of which Windows runs the task.
The value NT AUTHORITY\SYSTEM
value refers to the user with highest privilege on the local system
c. Delete the task
PS> Unregister-ScheduledTask -CimSession $Session -TaskName "<taskname>"
.msi
packages (Win32_Product
)This process uses the following ports:
135/TCP, 49152-65535/TCP (DCERPC)
5985/TCP (WinRM HTTP) or 5986/TCP (WinRM HTTPS)
and requires the specified user to be in the Administrators group.
For this technique, we attempt to upload a .msi
file to a target remote machine, before using WMI to install it.
From the Win32_Product Install method docs:
The static Install WMI class method installs an associated Win32_Product instance using the installation package provided through the PackageLocation parameter, and any supplied command line options.
Install the .msi
file:
PS> Invoke-CimMethod -CimSession $Session -ClassName Win32_Product -MethodName Install -Arguments @{
PackageLocation = "C:\Windows\<installed_msi>.msi";
Options = "";
AllUsers = $false
}
PackageLocation
: Path to the installer package, which is relative to the computer on which the software is being installed and which can be referenced using a Universal Naming Convention (UNC) path.
Options
: Command-line options required for installing the software. Format as property=setting
. If no options are required, this parameter should be left blank.
AllUsers
: Boolean value that indicates whether the software should be available to all the users on a computer or just the currently logged-on user.
For our case, we will generally want the value to be $false