Fix issue 5790

Leaving around plaintext username and passwords in a script on a box isn't the best from a security standpoint. This change ensures the scheduled task wrapper script for WinRM doesn't leave these around on the box, and instead passes them to the script as arguments.
This commit is contained in:
Shawn Neal 2015-06-10 12:47:26 -07:00
parent 28a42122b8
commit 1152b4e1df
2 changed files with 21 additions and 26 deletions

View File

@ -134,12 +134,7 @@ module VagrantPlugins
}.merge(opts || {}) }.merge(opts || {})
opts[:good_exit] = Array(opts[:good_exit]) opts[:good_exit] = Array(opts[:good_exit])
command = wrap_in_scheduled_task(command) if opts[:elevated]
if opts[:elevated]
guest_script_path = create_elevated_shell_script(command)
command = "powershell -executionpolicy bypass -file #{guest_script_path}"
end
output = shell.send(opts[:shell], command, &block) output = shell.send(opts[:shell], command, &block)
execution_output(output, opts) execution_output(output, opts)
end end
@ -187,19 +182,15 @@ module VagrantPlugins
) )
end end
# Creates and uploads a PowerShell script which wraps the specified # Creates and uploads a PowerShell script which wraps a command in a
# command in a scheduled task. The scheduled task allows commands to # scheduled task. The scheduled task allows commands to run on the guest
# run on the guest as a true local admin without any of the restrictions # as a true local admin without any of the restrictions that WinRM puts
# that WinRM puts in place. # in place.
# #
# @return The path to elevated_shell.ps1 on the guest # @return The wrapper command to execute
def create_elevated_shell_script(command) def wrap_in_scheduled_task(command)
path = File.expand_path("../scripts/elevated_shell.ps1", __FILE__) path = File.expand_path("../scripts/elevated_shell.ps1", __FILE__)
script = Vagrant::Util::TemplateRenderer.render(path, options: { script = Vagrant::Util::TemplateRenderer.render(path)
username: shell.username,
password: shell.password,
command: command.gsub("\"", "`\""),
})
guest_script_path = "c:/tmp/vagrant-elevated-shell.ps1" guest_script_path = "c:/tmp/vagrant-elevated-shell.ps1"
file = Tempfile.new(["vagrant-elevated-shell", "ps1"]) file = Tempfile.new(["vagrant-elevated-shell", "ps1"])
begin begin
@ -211,7 +202,15 @@ module VagrantPlugins
file.close file.close
file.unlink file.unlink
end end
guest_script_path
# convert to double byte unicode string then base64 encode
# just like PowerShell -EncodedCommand expects
wrapped_encoded_command = Base64.strict_encode64(
"#{command}; exit $LASTEXITCODE".encode('UTF-16LE', 'UTF-8'))
"powershell -executionpolicy bypass -file \"#{guest_script_path}\" " +
"-username \"#{shell.username}\" -password \"#{shell.password}\" " +
"-encoded_command \"#{wrapped_encoded_command}\""
end end
# Handles the raw WinRM shell result and converts it to a # Handles the raw WinRM shell result and converts it to a

View File

@ -1,6 +1,4 @@
$command = "<%= options[:command] %>" + '; exit $LASTEXITCODE' param([String]$username, [String]$password, [String]$encoded_command)
$user = '<%= options[:username] %>'
$password = '<%= options[:password] %>'
$task_name = "WinRM_Elevated_Shell" $task_name = "WinRM_Elevated_Shell"
$out_file = "$env:SystemRoot\Temp\WinRM_Elevated_Shell.log" $out_file = "$env:SystemRoot\Temp\WinRM_Elevated_Shell.log"
@ -14,7 +12,7 @@ $task_xml = @'
<Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task"> <Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
<Principals> <Principals>
<Principal id="Author"> <Principal id="Author">
<UserId>{user}</UserId> <UserId>{username}</UserId>
<LogonType>Password</LogonType> <LogonType>Password</LogonType>
<RunLevel>HighestAvailable</RunLevel> <RunLevel>HighestAvailable</RunLevel>
</Principal> </Principal>
@ -47,19 +45,17 @@ $task_xml = @'
</Task> </Task>
'@ '@
$bytes = [System.Text.Encoding]::Unicode.GetBytes($command)
$encoded_command = [Convert]::ToBase64String($bytes)
$arguments = "/c powershell.exe -EncodedCommand $encoded_command &gt; $out_file 2&gt;&amp;1" $arguments = "/c powershell.exe -EncodedCommand $encoded_command &gt; $out_file 2&gt;&amp;1"
$task_xml = $task_xml.Replace("{arguments}", $arguments) $task_xml = $task_xml.Replace("{arguments}", $arguments)
$task_xml = $task_xml.Replace("{user}", $user) $task_xml = $task_xml.Replace("{username}", $username)
$schedule = New-Object -ComObject "Schedule.Service" $schedule = New-Object -ComObject "Schedule.Service"
$schedule.Connect() $schedule.Connect()
$task = $schedule.NewTask($null) $task = $schedule.NewTask($null)
$task.XmlText = $task_xml $task.XmlText = $task_xml
$folder = $schedule.GetFolder("\") $folder = $schedule.GetFolder("\")
$folder.RegisterTaskDefinition($task_name, $task, 6, $user, $password, 1, $null) | Out-Null $folder.RegisterTaskDefinition($task_name, $task, 6, $username, $password, 1, $null) | Out-Null
$registered_task = $folder.GetTask("\$task_name") $registered_task = $folder.GetTask("\$task_name")
$registered_task.Run($null) | Out-Null $registered_task.Run($null) | Out-Null