mirror of
https://github.com/ansible-collections/community.general.git
synced 2025-04-25 03:41:25 -07:00
split PS wrapper and payload (CVE-2018-16859) (#49142)
* prevent scriptblock logging from logging payload contents * added tests to verify no payload contents in PS Operational event log * fix script action to send split-aware wrapper * fix CLIXML error parser (return to -EncodedCommand exposed problems with it)
This commit is contained in:
parent
e7104a445b
commit
8c1f701e6e
12 changed files with 91 additions and 30 deletions
|
@ -39,8 +39,9 @@ $Payload.async_results_path = $results_path
|
|||
$Payload.actions = $Payload.actions[1..99]
|
||||
$payload_json = ConvertTo-Json -InputObject $Payload -Depth 99 -Compress
|
||||
|
||||
#
|
||||
$exec_wrapper = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($Payload.exec_wrapper))
|
||||
$exec_wrapper = $exec_wrapper.Replace("`$json_raw = ''", "`$json_raw = @'`r`n$payload_json`r`n'@")
|
||||
$exec_wrapper += "`0`0`0`0" + $payload_json
|
||||
$payload_bytes = [System.Text.Encoding]::UTF8.GetBytes($exec_wrapper)
|
||||
$pipe_name = "ansible-async-$jid-$([guid]::NewGuid())"
|
||||
|
||||
|
@ -77,7 +78,9 @@ $bootstrap_wrapper = {
|
|||
$pipe.Close()
|
||||
}
|
||||
$exec = [System.Text.Encoding]::UTF8.GetString($input_bytes)
|
||||
$exec = [ScriptBlock]::Create($exec)
|
||||
$exec_parts = $exec.Split(@("`0`0`0`0"), 2, [StringSplitOptions]::RemoveEmptyEntries)
|
||||
Set-Variable -Name json_raw -Value $exec_parts[1]
|
||||
$exec = [ScriptBlock]::Create($exec_parts[0])
|
||||
&$exec
|
||||
}
|
||||
|
||||
|
|
|
@ -98,11 +98,14 @@ Write-AnsibleLog "INFO - parsed become input, user: '$username', type: '$logon_t
|
|||
# NB: CreateProcessWithTokenW commandline maxes out at 1024 chars, must
|
||||
# bootstrap via small wrapper which contains the exec_wrapper passed through the
|
||||
# stdin pipe. Cannot use 'powershell -' as the $ErrorActionPreference is always
|
||||
# set to Stop and cannot be changed
|
||||
# set to Stop and cannot be changed. Also need to split the payload from the wrapper to prevent potentially
|
||||
# sensitive content from being logged by the scriptblock logger.
|
||||
$bootstrap_wrapper = {
|
||||
&chcp.com 65001 > $null
|
||||
$exec_wrapper_str = [System.Console]::In.ReadToEnd()
|
||||
$exec_wrapper = [ScriptBlock]::Create($exec_wrapper_str)
|
||||
$split_parts = $exec_wrapper_str.Split(@("`0`0`0`0"), 2, [StringSplitOptions]::RemoveEmptyEntries)
|
||||
Set-Variable -Name json_raw -Value $split_parts[1]
|
||||
$exec_wrapper = [ScriptBlock]::Create($split_parts[0])
|
||||
&$exec_wrapper
|
||||
}
|
||||
$exec_command = [System.Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes($bootstrap_wrapper.ToString()))
|
||||
|
@ -115,8 +118,9 @@ $Payload.actions = $Payload.actions[1..99]
|
|||
$Payload.encoded_output = $true
|
||||
|
||||
$payload_json = ConvertTo-Json -InputObject $Payload -Depth 99 -Compress
|
||||
# delimit the payload JSON from the wrapper to keep sensitive contents out of scriptblocks (which can be logged)
|
||||
$exec_wrapper = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($Payload.exec_wrapper))
|
||||
$exec_wrapper = $exec_wrapper.Replace("`$json_raw = ''", "`$json_raw = @'`r`n$payload_json`r`n'@")
|
||||
$exec_wrapper += "`0`0`0`0" + $payload_json
|
||||
|
||||
try {
|
||||
Write-AnsibleLog "INFO - starting become process '$lp_command_line'" "become_wrapper"
|
||||
|
|
7
lib/ansible/executor/powershell/bootstrap_wrapper.ps1
Normal file
7
lib/ansible/executor/powershell/bootstrap_wrapper.ps1
Normal file
|
@ -0,0 +1,7 @@
|
|||
&chcp.com 65001 > $null
|
||||
$exec_wrapper_str = $input | Out-String
|
||||
$split_parts = $exec_wrapper_str.Split(@("`0`0`0`0"), 2, [StringSplitOptions]::RemoveEmptyEntries)
|
||||
If (-not $split_parts.Length -eq 2) { throw "invalid payload" }
|
||||
Set-Variable -Name json_raw -Value $split_parts[1]
|
||||
$exec_wrapper = [ScriptBlock]::Create($split_parts[0])
|
||||
&$exec_wrapper
|
|
@ -159,9 +159,10 @@ $($ErrorRecord.InvocationInfo.PositionMessage)
|
|||
}
|
||||
.$wrapper_functions
|
||||
|
||||
# NB: do not adjust the following line - it is replaced when doing
|
||||
# non-streamed input
|
||||
$json_raw = ''
|
||||
# only init and stream in $json_raw if it wasn't set by the enclosing scope
|
||||
if (-not $(Get-Variable "json_raw" -ErrorAction SilentlyContinue)) {
|
||||
$json_raw = ''
|
||||
}
|
||||
} process {
|
||||
$json_raw += [String]$input
|
||||
} end {
|
||||
|
|
|
@ -280,9 +280,7 @@ def _create_powershell_wrapper(b_module_data, module_args, environment,
|
|||
exec_manifest['csharp_utils'][name] = b64_data
|
||||
exec_manifest['csharp_utils_module'] = list(finder.cs_utils_module.keys())
|
||||
|
||||
# FUTURE: smuggle this back as a dict instead of serializing here;
|
||||
# the connection plugin may need to modify it
|
||||
b_json = to_bytes(json.dumps(exec_manifest))
|
||||
b_data = exec_wrapper.replace(b"$json_raw = ''",
|
||||
b"$json_raw = @'\r\n%s\r\n'@" % b_json)
|
||||
# delimit the payload JSON from the wrapper to keep sensitive contents out of scriptblocks (which can be logged)
|
||||
b_data = exec_wrapper + b'\0\0\0\0' + b_json
|
||||
return b_data
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue