Encode powershell using utf8
Fix a bug in the size of string that was returned when decoding a base64 string Added tests around encoding and decoding powershell scripts. Used [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes('powershell commands')) | clip to generate what base 64 strings should look like
This commit is contained in:
parent
17597b48e1
commit
d61513bf77
|
@ -2,22 +2,33 @@ package powershell
|
|||
|
||||
import (
|
||||
"encoding/base64"
|
||||
|
||||
"golang.org/x/text/encoding/unicode"
|
||||
)
|
||||
|
||||
func powershellEncode(buffer []byte) string {
|
||||
// 2 byte chars to make PowerShell happy
|
||||
wideCmd := ""
|
||||
for _, b := range buffer {
|
||||
wideCmd += string(b) + "\x00"
|
||||
func powershellUtf8(message string) (string, error) {
|
||||
utf8 := unicode.UTF8
|
||||
utfEncoder := utf8.NewEncoder()
|
||||
utf8EncodedMessage, err := utfEncoder.String(message)
|
||||
|
||||
return utf8EncodedMessage, err
|
||||
}
|
||||
|
||||
func powershellEncode(message string) (string, error) {
|
||||
utf8EncodedMessage, err := powershellUtf8(message)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Base64 encode the command
|
||||
input := []uint8(wideCmd)
|
||||
return base64.StdEncoding.EncodeToString(input)
|
||||
input := []uint8(utf8EncodedMessage)
|
||||
return base64.StdEncoding.EncodeToString(input), nil
|
||||
}
|
||||
|
||||
func powershellDecode(message string) (retour string) {
|
||||
base64Text := make([]byte, base64.StdEncoding.DecodedLen(len(message)))
|
||||
base64.StdEncoding.Decode(base64Text, []byte(message))
|
||||
return string(base64Text)
|
||||
func powershellDecode(message string) (retour string, err error) {
|
||||
data, err := base64.StdEncoding.DecodeString(message)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(data), nil
|
||||
}
|
||||
|
|
|
@ -399,9 +399,25 @@ func (p *Provisioner) createCommandTextNonPrivileged() (command string, err erro
|
|||
return "", fmt.Errorf("Error processing command: %s", err)
|
||||
}
|
||||
|
||||
encodedCommand := "powershell -executionpolicy bypass -encodedCommand " + powershellEncode([]byte("if (Test-Path variable:global:ProgressPreference){$ProgressPreference=\"SilentlyContinue\"}; "+command+"; exit $LastExitCode"))
|
||||
commandText, err := p.generateCommandLineRunner(command)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Error generating command line runner: %s", err)
|
||||
}
|
||||
|
||||
return encodedCommand, err
|
||||
return commandText, err
|
||||
}
|
||||
|
||||
func (p *Provisioner) generateCommandLineRunner(command string) (commandText string, err error) {
|
||||
log.Printf("Building command line for: %s", command)
|
||||
|
||||
base64EncodedCommand, err := powershellEncode("if (Test-Path variable:global:ProgressPreference){$ProgressPreference=\"SilentlyContinue\"}; " + command + "; exit $LastExitCode")
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Error encoding command: %s", err)
|
||||
}
|
||||
|
||||
commandText = "powershell -executionpolicy bypass -encodedCommand " + base64EncodedCommand
|
||||
|
||||
return commandText, nil
|
||||
}
|
||||
|
||||
func (p *Provisioner) createCommandTextPrivileged() (command string, err error) {
|
||||
|
@ -422,6 +438,9 @@ func (p *Provisioner) createCommandTextPrivileged() (command string, err error)
|
|||
// OK so we need an elevated shell runner to wrap our command, this is going to have its own path
|
||||
// generate the script and update the command runner in the process
|
||||
path, err := p.generateElevatedRunner(command)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Error generating elevated runner: %s", err)
|
||||
}
|
||||
|
||||
// Return the path to the elevated shell wrapper
|
||||
command = fmt.Sprintf("powershell -executionpolicy bypass -file \"%s\"", path)
|
||||
|
@ -434,12 +453,18 @@ func (p *Provisioner) generateElevatedRunner(command string) (uploadedPath strin
|
|||
|
||||
// generate command
|
||||
var buffer bytes.Buffer
|
||||
|
||||
base64EncodedCommand, err := powershellEncode("if (Test-Path variable:global:ProgressPreference){$ProgressPreference=\"SilentlyContinue\"}; " + command + "; exit $LastExitCode")
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Error encoding command: %s", err)
|
||||
}
|
||||
|
||||
err = elevatedTemplate.Execute(&buffer, elevatedOptions{
|
||||
User: p.config.ElevatedUser,
|
||||
Password: p.config.ElevatedPassword,
|
||||
TaskDescription: "Packer elevated task",
|
||||
TaskName: fmt.Sprintf("packer-%s", uuid.TimeOrderedUUID()),
|
||||
EncodedCommand: powershellEncode([]byte("if (Test-Path variable:global:ProgressPreference){$ProgressPreference=\"SilentlyContinue\"}; " + command + "; exit $LastExitCode")),
|
||||
EncodedCommand: base64EncodedCommand,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
|
|
|
@ -390,14 +390,27 @@ func TestProvisionerProvision_Inline(t *testing.T) {
|
|||
}
|
||||
|
||||
expectedCommand := `if (Test-Path variable:global:ProgressPreference){$ProgressPreference="SilentlyContinue"}; $env:PACKER_BUILDER_TYPE="iso"; $env:PACKER_BUILD_NAME="vmware"; c:/Windows/Temp/inlineScript.bat; exit $LastExitCode`
|
||||
expectedCommandUtf8, err := powershellUtf8(expectedCommand)
|
||||
if err != nil {
|
||||
t.Fatal("should not have error when Utf 8 encoding")
|
||||
}
|
||||
expectedCommandBase64Encoded := `aWYgKFRlc3QtUGF0aCB2YXJpYWJsZTpnbG9iYWw6UHJvZ3Jlc3NQcmVmZXJlbmNlKXskUHJvZ3Jlc3NQcmVmZXJlbmNlPSJTaWxlbnRseUNvbnRpbnVlIn07ICRlbnY6UEFDS0VSX0JVSUxERVJfVFlQRT0iaXNvIjsgJGVudjpQQUNLRVJfQlVJTERfTkFNRT0idm13YXJlIjsgYzovV2luZG93cy9UZW1wL2lubGluZVNjcmlwdC5iYXQ7IGV4aXQgJExhc3RFeGl0Q29kZQ==`
|
||||
expectedCommandPrefix := `powershell -executionpolicy bypass -encodedCommand `
|
||||
expectedCommandEncoded := expectedCommandPrefix + powershellEncode([]byte(expectedCommand))
|
||||
expectedCommandEncoded := expectedCommandPrefix + expectedCommandBase64Encoded
|
||||
|
||||
actualCommandWithoutPrefix := strings.Replace(comm.StartCmd.Command, expectedCommandPrefix, "", -1)
|
||||
actualCommandDecoded, err := powershellDecode(actualCommandWithoutPrefix)
|
||||
if err != nil {
|
||||
t.Fatal("should not have error when base64 decoding")
|
||||
}
|
||||
|
||||
// Should run the command without alteration
|
||||
if comm.StartCmd.Command != expectedCommandEncoded {
|
||||
actualCommandWithoutPrefix := strings.Replace(comm.StartCmd.Command, expectedCommandPrefix, "", -1)
|
||||
actualCommandDecoded := powershellDecode(actualCommandWithoutPrefix)
|
||||
t.Fatalf("Expect command to be: %s, got %s. Expected decoded: %s, got %s", expectedCommandEncoded, comm.StartCmd.Command, expectedCommand, actualCommandDecoded)
|
||||
t.Fatalf("Expect command to be: %s, got %s.", expectedCommandEncoded, comm.StartCmd.Command)
|
||||
}
|
||||
|
||||
if actualCommandDecoded != expectedCommandUtf8 {
|
||||
t.Fatalf("Expected decoded:%s, %s, got %s", expectedCommandEncoded, len(expectedCommandUtf8), len(actualCommandDecoded))
|
||||
}
|
||||
|
||||
envVars := make([]string, 2)
|
||||
|
@ -413,14 +426,27 @@ func TestProvisionerProvision_Inline(t *testing.T) {
|
|||
}
|
||||
|
||||
expectedCommand = `if (Test-Path variable:global:ProgressPreference){$ProgressPreference="SilentlyContinue"}; $env:BAR="BAZ"; $env:FOO="BAR"; $env:PACKER_BUILDER_TYPE="iso"; $env:PACKER_BUILD_NAME="vmware"; c:/Windows/Temp/inlineScript.bat; exit $LastExitCode`
|
||||
expectedCommandUtf8, err = powershellUtf8(expectedCommand)
|
||||
if err != nil {
|
||||
t.Fatal("should not have error when Utf 8 encoding")
|
||||
}
|
||||
expectedCommandBase64Encoded = `aWYgKFRlc3QtUGF0aCB2YXJpYWJsZTpnbG9iYWw6UHJvZ3Jlc3NQcmVmZXJlbmNlKXskUHJvZ3Jlc3NQcmVmZXJlbmNlPSJTaWxlbnRseUNvbnRpbnVlIn07ICRlbnY6QkFSPSJCQVoiOyAkZW52OkZPTz0iQkFSIjsgJGVudjpQQUNLRVJfQlVJTERFUl9UWVBFPSJpc28iOyAkZW52OlBBQ0tFUl9CVUlMRF9OQU1FPSJ2bXdhcmUiOyBjOi9XaW5kb3dzL1RlbXAvaW5saW5lU2NyaXB0LmJhdDsgZXhpdCAkTGFzdEV4aXRDb2Rl`
|
||||
expectedCommandPrefix = `powershell -executionpolicy bypass -encodedCommand `
|
||||
expectedCommandEncoded = expectedCommandPrefix + powershellEncode([]byte(expectedCommand))
|
||||
expectedCommandEncoded = expectedCommandPrefix + expectedCommandBase64Encoded
|
||||
|
||||
actualCommandWithoutPrefix = strings.Replace(comm.StartCmd.Command, expectedCommandPrefix, "", -1)
|
||||
actualCommandDecoded, err = powershellDecode(actualCommandWithoutPrefix)
|
||||
if err != nil {
|
||||
t.Fatal("should not have error when base64 decoding")
|
||||
}
|
||||
|
||||
// Should run the command without alteration
|
||||
if comm.StartCmd.Command != expectedCommandEncoded {
|
||||
actualCommandWithoutPrefix := strings.Replace(comm.StartCmd.Command, expectedCommandPrefix, "", -1)
|
||||
actualCommandDecoded := powershellDecode(actualCommandWithoutPrefix)
|
||||
t.Fatalf("Expect command to be: %s, got %s. Expected decoded: %s, got %s", expectedCommandEncoded, comm.StartCmd.Command, expectedCommand, actualCommandDecoded)
|
||||
t.Fatalf("Expect command to be: %s, got %s.", expectedCommandEncoded, comm.StartCmd.Command)
|
||||
}
|
||||
|
||||
if actualCommandDecoded != expectedCommandUtf8 {
|
||||
t.Fatalf("Expected decoded: %s, got %s", expectedCommandUtf8, actualCommandDecoded)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -443,14 +469,27 @@ func TestProvisionerProvision_Scripts(t *testing.T) {
|
|||
}
|
||||
|
||||
expectedCommand := `if (Test-Path variable:global:ProgressPreference){$ProgressPreference="SilentlyContinue"}; $env:PACKER_BUILDER_TYPE="footype"; $env:PACKER_BUILD_NAME="foobuild"; c:/Windows/Temp/script.ps1; exit $LastExitCode`
|
||||
expectedCommandUtf8, err := powershellUtf8(expectedCommand)
|
||||
if err != nil {
|
||||
t.Fatal("should not have error when Utf 8 encoding")
|
||||
}
|
||||
expectedCommandBase64Encoded := `aWYgKFRlc3QtUGF0aCB2YXJpYWJsZTpnbG9iYWw6UHJvZ3Jlc3NQcmVmZXJlbmNlKXskUHJvZ3Jlc3NQcmVmZXJlbmNlPSJTaWxlbnRseUNvbnRpbnVlIn07ICRlbnY6UEFDS0VSX0JVSUxERVJfVFlQRT0iZm9vdHlwZSI7ICRlbnY6UEFDS0VSX0JVSUxEX05BTUU9ImZvb2J1aWxkIjsgYzovV2luZG93cy9UZW1wL3NjcmlwdC5wczE7IGV4aXQgJExhc3RFeGl0Q29kZQ==`
|
||||
expectedCommandPrefix := `powershell -executionpolicy bypass -encodedCommand `
|
||||
expectedCommandEncoded := expectedCommandPrefix + powershellEncode([]byte(expectedCommand))
|
||||
expectedCommandEncoded := expectedCommandPrefix + expectedCommandBase64Encoded
|
||||
|
||||
actualCommandWithoutPrefix := strings.Replace(comm.StartCmd.Command, expectedCommandPrefix, "", -1)
|
||||
actualCommandDecoded, err := powershellDecode(actualCommandWithoutPrefix)
|
||||
if err != nil {
|
||||
t.Fatal("should not have error when base64 decoding")
|
||||
}
|
||||
|
||||
// Should run the command without alteration
|
||||
if comm.StartCmd.Command != expectedCommandEncoded {
|
||||
actualCommandWithoutPrefix := strings.Replace(comm.StartCmd.Command, expectedCommandPrefix, "", -1)
|
||||
actualCommandDecoded := powershellDecode(actualCommandWithoutPrefix)
|
||||
t.Fatalf("Expect command to be: %s, got %s. Expected decoded: %s, got %s", expectedCommandEncoded, comm.StartCmd.Command, expectedCommand, actualCommandDecoded)
|
||||
t.Fatalf("Expect command to be: %s, got %s.", expectedCommandEncoded, comm.StartCmd.Command)
|
||||
}
|
||||
|
||||
if actualCommandDecoded != expectedCommandUtf8 {
|
||||
t.Fatalf("Expected decoded: %n, got %n", len(expectedCommandUtf8), len(actualCommandDecoded))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -480,14 +519,27 @@ func TestProvisionerProvision_ScriptsWithEnvVars(t *testing.T) {
|
|||
}
|
||||
|
||||
expectedCommand := `if (Test-Path variable:global:ProgressPreference){$ProgressPreference="SilentlyContinue"}; $env:BAR="BAZ"; $env:FOO="BAR"; $env:PACKER_BUILDER_TYPE="footype"; $env:PACKER_BUILD_NAME="foobuild"; c:/Windows/Temp/script.ps1; exit $LastExitCode`
|
||||
expectedCommandUtf8, err := powershellUtf8(expectedCommand)
|
||||
if err != nil {
|
||||
t.Fatal("should not have error when Utf 8 encoding")
|
||||
}
|
||||
expectedCommandBase64Encoded := `aWYgKFRlc3QtUGF0aCB2YXJpYWJsZTpnbG9iYWw6UHJvZ3Jlc3NQcmVmZXJlbmNlKXskUHJvZ3Jlc3NQcmVmZXJlbmNlPSJTaWxlbnRseUNvbnRpbnVlIn07ICRlbnY6QkFSPSJCQVoiOyAkZW52OkZPTz0iQkFSIjsgJGVudjpQQUNLRVJfQlVJTERFUl9UWVBFPSJmb290eXBlIjsgJGVudjpQQUNLRVJfQlVJTERfTkFNRT0iZm9vYnVpbGQiOyBjOi9XaW5kb3dzL1RlbXAvc2NyaXB0LnBzMTsgZXhpdCAkTGFzdEV4aXRDb2Rl`
|
||||
expectedCommandPrefix := `powershell -executionpolicy bypass -encodedCommand `
|
||||
expectedCommandEncoded := expectedCommandPrefix + powershellEncode([]byte(expectedCommand))
|
||||
expectedCommandEncoded := expectedCommandPrefix + expectedCommandBase64Encoded
|
||||
|
||||
actualCommandWithoutPrefix := strings.Replace(comm.StartCmd.Command, expectedCommandPrefix, "", -1)
|
||||
actualCommandDecoded, err := powershellDecode(actualCommandWithoutPrefix)
|
||||
if err != nil {
|
||||
t.Fatal("should not have error when base64 decoding")
|
||||
}
|
||||
|
||||
// Should run the command without alteration
|
||||
if comm.StartCmd.Command != expectedCommandEncoded {
|
||||
actualCommandWithoutPrefix := strings.Replace(comm.StartCmd.Command, expectedCommandPrefix, "", -1)
|
||||
actualCommandDecoded := powershellDecode(actualCommandWithoutPrefix)
|
||||
t.Fatalf("Expect command to be: %s, got %s. Expected decoded: %s, got %s", expectedCommandEncoded, comm.StartCmd.Command, expectedCommand, actualCommandDecoded)
|
||||
t.Fatalf("Expect command to be: %s, got %s.", expectedCommandEncoded, comm.StartCmd.Command)
|
||||
}
|
||||
|
||||
if actualCommandDecoded != expectedCommandUtf8 {
|
||||
t.Fatalf("Expected decoded: %s, got %s", expectedCommandUtf8, actualCommandDecoded)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -599,14 +651,24 @@ func TestProvision_createCommandText(t *testing.T) {
|
|||
cmd, _ := p.createCommandText()
|
||||
|
||||
expectedCommand := `if (Test-Path variable:global:ProgressPreference){$ProgressPreference="SilentlyContinue"}; $env:PACKER_BUILDER_TYPE=""; $env:PACKER_BUILD_NAME=""; c:/Windows/Temp/script.ps1; exit $LastExitCode`
|
||||
expectedCommandBase64Encoded := `aWYgKFRlc3QtUGF0aCB2YXJpYWJsZTpnbG9iYWw6UHJvZ3Jlc3NQcmVmZXJlbmNlKXskUHJvZ3Jlc3NQcmVmZXJlbmNlPSJTaWxlbnRseUNvbnRpbnVlIn07ICRlbnY6UEFDS0VSX0JVSUxERVJfVFlQRT0iIjsgJGVudjpQQUNLRVJfQlVJTERfTkFNRT0iIjsgYzovV2luZG93cy9UZW1wL3NjcmlwdC5wczE7IGV4aXQgJExhc3RFeGl0Q29kZQ==`
|
||||
expectedCommandPrefix := `powershell -executionpolicy bypass -encodedCommand `
|
||||
expectedCommandEncoded := expectedCommandPrefix + powershellEncode([]byte(expectedCommand))
|
||||
expectedCommandEncoded := expectedCommandPrefix + expectedCommandBase64Encoded
|
||||
|
||||
actualCommandWithoutPrefix := strings.Replace(cmd, expectedCommandPrefix, "", -1)
|
||||
|
||||
actualCommandDecoded, err := powershellDecode(actualCommandWithoutPrefix)
|
||||
if err != nil {
|
||||
t.Fatal("should not have error when base64 decoding")
|
||||
}
|
||||
|
||||
// Should run the command without alteration
|
||||
if cmd != expectedCommandEncoded {
|
||||
actualCommandWithoutPrefix := strings.Replace(comm.StartCmd.Command, expectedCommandPrefix, "", -1)
|
||||
actualCommandDecoded := powershellDecode(actualCommandWithoutPrefix)
|
||||
t.Fatalf("Expect command to be: %s, got %s. Expected decoded: %s, got %s", expectedCommandEncoded, comm.StartCmd.Command, expectedCommand, actualCommandDecoded)
|
||||
t.Fatalf("Expect command to be: %s, got %s.", expectedCommandEncoded, cmd)
|
||||
}
|
||||
|
||||
if actualCommandDecoded != expectedCommand {
|
||||
t.Fatalf("Expected decoded: %s, got %s", expectedCommand, actualCommandDecoded)
|
||||
}
|
||||
|
||||
// Elevated
|
||||
|
|
Loading…
Reference in New Issue