From 6a88be69558834409269219991150a62ea27c4e7 Mon Sep 17 00:00:00 2001 From: Vladyslav Horbachov <50652041+LeftTwixWand@users.noreply.github.com> Date: Tue, 3 Oct 2023 15:54:36 +0200 Subject: [PATCH] Update powershell sanitizer regex (#1199) * Updated regex to allow more characters Copy of https://github.com/microsoft/azure-pipelines-tasks/pull/19028 * Bump extension and tasks versions --- .../IISWebAppDeployV1/task.json | 2 +- .../IISWebAppDeployV2/task.json | 2 +- .../IISWebAppMgmt/IISWebAppMgmtV1/task.json | 2 +- .../IISWebAppMgmt/IISWebAppMgmtV2/task.json | 2 +- .../IISWebAppMgmt/IISWebAppMgmtV3/task.json | 2 +- .../SqlDacpacDeployV1/task.json | 2 +- .../SqlDacpacDeployV2/task.json | 2 +- .../IISWebAppDeploy/Src/vss-extension.json | 2 +- .../Sanitizer/ArgumentsSanitizer.ps1 | 4 +- .../resources.resjson/de-DE/resources.resjson | 2 + .../resources.resjson/en-US/resources.resjson | 2 +- .../resources.resjson/es-ES/resources.resjson | 2 + .../resources.resjson/fr-FR/resources.resjson | 2 + .../resources.resjson/it-IT/resources.resjson | 2 + .../resources.resjson/ja-JP/resources.resjson | 2 + .../resources.resjson/ko-KR/resources.resjson | 2 + .../resources.resjson/ru-RU/resources.resjson | 2 + .../resources.resjson/zh-CN/resources.resjson | 2 + .../resources.resjson/zh-TW/resources.resjson | 2 + TaskModules/powershell/Sanitizer/Tests/L0.ts | 19 ++++++--- ...sArray.DoesNotBreakExistingBashFormats.ps1 | 4 +- ...tsArray.DoesNotBreakExistingCmdFormats.ps1 | 2 +- ....DoesNotBreakExistingPowerShellFormats.ps1 | 2 +- ...mentsArray.ReplacesForbiddenCharacters.ps1 | 4 +- .../L0Protect-ScriptArguments.Passes.ps1 | 41 +++++++++++++++++++ .../L0Protect-ScriptArguments.Throws.ps1 | 22 ++++++++++ .../Sanitizer/Tests/L0Split-Arguments.ps1 | 4 +- TaskModules/powershell/Sanitizer/module.json | 2 +- 28 files changed, 114 insertions(+), 26 deletions(-) create mode 100644 TaskModules/powershell/Sanitizer/Strings/resources.resjson/de-DE/resources.resjson create mode 100644 TaskModules/powershell/Sanitizer/Strings/resources.resjson/es-ES/resources.resjson create mode 100644 TaskModules/powershell/Sanitizer/Strings/resources.resjson/fr-FR/resources.resjson create mode 100644 TaskModules/powershell/Sanitizer/Strings/resources.resjson/it-IT/resources.resjson create mode 100644 TaskModules/powershell/Sanitizer/Strings/resources.resjson/ja-JP/resources.resjson create mode 100644 TaskModules/powershell/Sanitizer/Strings/resources.resjson/ko-KR/resources.resjson create mode 100644 TaskModules/powershell/Sanitizer/Strings/resources.resjson/ru-RU/resources.resjson create mode 100644 TaskModules/powershell/Sanitizer/Strings/resources.resjson/zh-CN/resources.resjson create mode 100644 TaskModules/powershell/Sanitizer/Strings/resources.resjson/zh-TW/resources.resjson create mode 100644 TaskModules/powershell/Sanitizer/Tests/L0Protect-ScriptArguments.Passes.ps1 create mode 100644 TaskModules/powershell/Sanitizer/Tests/L0Protect-ScriptArguments.Throws.ps1 diff --git a/Extensions/IISWebAppDeploy/Src/Tasks/IISWebAppDeploy/IISWebAppDeployV1/task.json b/Extensions/IISWebAppDeploy/Src/Tasks/IISWebAppDeploy/IISWebAppDeployV1/task.json index c918165e9..9edd4abe2 100644 --- a/Extensions/IISWebAppDeploy/Src/Tasks/IISWebAppDeploy/IISWebAppDeployV1/task.json +++ b/Extensions/IISWebAppDeploy/Src/Tasks/IISWebAppDeploy/IISWebAppDeployV1/task.json @@ -7,7 +7,7 @@ "version": { "Major": 1, "Minor": 5, - "Patch": 5 + "Patch": 6 }, "demands": [ ], diff --git a/Extensions/IISWebAppDeploy/Src/Tasks/IISWebAppDeploy/IISWebAppDeployV2/task.json b/Extensions/IISWebAppDeploy/Src/Tasks/IISWebAppDeploy/IISWebAppDeployV2/task.json index ad08f4488..091b0f490 100644 --- a/Extensions/IISWebAppDeploy/Src/Tasks/IISWebAppDeploy/IISWebAppDeployV2/task.json +++ b/Extensions/IISWebAppDeploy/Src/Tasks/IISWebAppDeploy/IISWebAppDeployV2/task.json @@ -16,7 +16,7 @@ "version": { "Major": 2, "Minor": 1, - "Patch": 5 + "Patch": 6 }, "demands": [ ], diff --git a/Extensions/IISWebAppDeploy/Src/Tasks/IISWebAppMgmt/IISWebAppMgmtV1/task.json b/Extensions/IISWebAppDeploy/Src/Tasks/IISWebAppMgmt/IISWebAppMgmtV1/task.json index 91d171051..f3b00c899 100644 --- a/Extensions/IISWebAppDeploy/Src/Tasks/IISWebAppMgmt/IISWebAppMgmtV1/task.json +++ b/Extensions/IISWebAppDeploy/Src/Tasks/IISWebAppMgmt/IISWebAppMgmtV1/task.json @@ -16,7 +16,7 @@ "version": { "Major": 1, "Minor": 4, - "Patch": 5 + "Patch": 6 }, "demands": [ ], diff --git a/Extensions/IISWebAppDeploy/Src/Tasks/IISWebAppMgmt/IISWebAppMgmtV2/task.json b/Extensions/IISWebAppDeploy/Src/Tasks/IISWebAppMgmt/IISWebAppMgmtV2/task.json index c2454b09b..fcb3e5fee 100644 --- a/Extensions/IISWebAppDeploy/Src/Tasks/IISWebAppMgmt/IISWebAppMgmtV2/task.json +++ b/Extensions/IISWebAppDeploy/Src/Tasks/IISWebAppMgmt/IISWebAppMgmtV2/task.json @@ -16,7 +16,7 @@ "version": { "Major": 2, "Minor": 2, - "Patch": 5 + "Patch": 6 }, "demands": [ ], diff --git a/Extensions/IISWebAppDeploy/Src/Tasks/IISWebAppMgmt/IISWebAppMgmtV3/task.json b/Extensions/IISWebAppDeploy/Src/Tasks/IISWebAppMgmt/IISWebAppMgmtV3/task.json index 899895117..b8101f697 100644 --- a/Extensions/IISWebAppDeploy/Src/Tasks/IISWebAppMgmt/IISWebAppMgmtV3/task.json +++ b/Extensions/IISWebAppDeploy/Src/Tasks/IISWebAppMgmt/IISWebAppMgmtV3/task.json @@ -16,7 +16,7 @@ "version": { "Major": 3, "Minor": 1, - "Patch": 5 + "Patch": 6 }, "demands": [ ], diff --git a/Extensions/IISWebAppDeploy/Src/Tasks/SqlDacpacDeploy/SqlDacpacDeployV1/task.json b/Extensions/IISWebAppDeploy/Src/Tasks/SqlDacpacDeploy/SqlDacpacDeployV1/task.json index 65b84b639..aa07a6d8b 100644 --- a/Extensions/IISWebAppDeploy/Src/Tasks/SqlDacpacDeploy/SqlDacpacDeployV1/task.json +++ b/Extensions/IISWebAppDeploy/Src/Tasks/SqlDacpacDeploy/SqlDacpacDeployV1/task.json @@ -16,7 +16,7 @@ "version": { "Major": 1, "Minor": 4, - "Patch": 6 + "Patch": 7 }, "demands": [ ], diff --git a/Extensions/IISWebAppDeploy/Src/Tasks/SqlDacpacDeploy/SqlDacpacDeployV2/task.json b/Extensions/IISWebAppDeploy/Src/Tasks/SqlDacpacDeploy/SqlDacpacDeployV2/task.json index 442dabeca..0810902eb 100644 --- a/Extensions/IISWebAppDeploy/Src/Tasks/SqlDacpacDeploy/SqlDacpacDeployV2/task.json +++ b/Extensions/IISWebAppDeploy/Src/Tasks/SqlDacpacDeploy/SqlDacpacDeployV2/task.json @@ -16,7 +16,7 @@ "version": { "Major": 2, "Minor": 1, - "Patch": 6 + "Patch": 7 }, "demands": [ ], diff --git a/Extensions/IISWebAppDeploy/Src/vss-extension.json b/Extensions/IISWebAppDeploy/Src/vss-extension.json index 4ff4af397..e8bda2c78 100644 --- a/Extensions/IISWebAppDeploy/Src/vss-extension.json +++ b/Extensions/IISWebAppDeploy/Src/vss-extension.json @@ -2,7 +2,7 @@ "manifestVersion": 1, "extensionId": "iiswebapp", "name": "IIS Web App Deployment Using WinRM", - "version": "1.6.7", + "version": "1.6.8", "publisher": "ms-vscs-rm", "description": "Using WinRM connect to the host Computer, to deploy a Web project using Web Deploy or a SQL DB using sqlpackage.exe.", "public": true, diff --git a/TaskModules/powershell/Sanitizer/ArgumentsSanitizer.ps1 b/TaskModules/powershell/Sanitizer/ArgumentsSanitizer.ps1 index b24c43d8a..160e1a2c1 100644 --- a/TaskModules/powershell/Sanitizer/ArgumentsSanitizer.ps1 +++ b/TaskModules/powershell/Sanitizer/ArgumentsSanitizer.ps1 @@ -60,7 +60,7 @@ function Get-SanitizedArguments([string]$inputArgs) { # regex rule for removing symbols and telemetry. # '?", + "loc.messages.PS_ScriptArgsSanitized": "Detected characters in arguments that may not be executed correctly by the shell. Please escape special characters using backtick (`). More information is available here: https://aka.ms/ado/75787", "loc.messages.PS_ScriptArgsNotSanitized": "Arguments passed sanitization without change." } \ No newline at end of file diff --git a/TaskModules/powershell/Sanitizer/Strings/resources.resjson/es-ES/resources.resjson b/TaskModules/powershell/Sanitizer/Strings/resources.resjson/es-ES/resources.resjson new file mode 100644 index 000000000..7a73a41bf --- /dev/null +++ b/TaskModules/powershell/Sanitizer/Strings/resources.resjson/es-ES/resources.resjson @@ -0,0 +1,2 @@ +{ +} \ No newline at end of file diff --git a/TaskModules/powershell/Sanitizer/Strings/resources.resjson/fr-FR/resources.resjson b/TaskModules/powershell/Sanitizer/Strings/resources.resjson/fr-FR/resources.resjson new file mode 100644 index 000000000..7a73a41bf --- /dev/null +++ b/TaskModules/powershell/Sanitizer/Strings/resources.resjson/fr-FR/resources.resjson @@ -0,0 +1,2 @@ +{ +} \ No newline at end of file diff --git a/TaskModules/powershell/Sanitizer/Strings/resources.resjson/it-IT/resources.resjson b/TaskModules/powershell/Sanitizer/Strings/resources.resjson/it-IT/resources.resjson new file mode 100644 index 000000000..7a73a41bf --- /dev/null +++ b/TaskModules/powershell/Sanitizer/Strings/resources.resjson/it-IT/resources.resjson @@ -0,0 +1,2 @@ +{ +} \ No newline at end of file diff --git a/TaskModules/powershell/Sanitizer/Strings/resources.resjson/ja-JP/resources.resjson b/TaskModules/powershell/Sanitizer/Strings/resources.resjson/ja-JP/resources.resjson new file mode 100644 index 000000000..7a73a41bf --- /dev/null +++ b/TaskModules/powershell/Sanitizer/Strings/resources.resjson/ja-JP/resources.resjson @@ -0,0 +1,2 @@ +{ +} \ No newline at end of file diff --git a/TaskModules/powershell/Sanitizer/Strings/resources.resjson/ko-KR/resources.resjson b/TaskModules/powershell/Sanitizer/Strings/resources.resjson/ko-KR/resources.resjson new file mode 100644 index 000000000..7a73a41bf --- /dev/null +++ b/TaskModules/powershell/Sanitizer/Strings/resources.resjson/ko-KR/resources.resjson @@ -0,0 +1,2 @@ +{ +} \ No newline at end of file diff --git a/TaskModules/powershell/Sanitizer/Strings/resources.resjson/ru-RU/resources.resjson b/TaskModules/powershell/Sanitizer/Strings/resources.resjson/ru-RU/resources.resjson new file mode 100644 index 000000000..7a73a41bf --- /dev/null +++ b/TaskModules/powershell/Sanitizer/Strings/resources.resjson/ru-RU/resources.resjson @@ -0,0 +1,2 @@ +{ +} \ No newline at end of file diff --git a/TaskModules/powershell/Sanitizer/Strings/resources.resjson/zh-CN/resources.resjson b/TaskModules/powershell/Sanitizer/Strings/resources.resjson/zh-CN/resources.resjson new file mode 100644 index 000000000..7a73a41bf --- /dev/null +++ b/TaskModules/powershell/Sanitizer/Strings/resources.resjson/zh-CN/resources.resjson @@ -0,0 +1,2 @@ +{ +} \ No newline at end of file diff --git a/TaskModules/powershell/Sanitizer/Strings/resources.resjson/zh-TW/resources.resjson b/TaskModules/powershell/Sanitizer/Strings/resources.resjson/zh-TW/resources.resjson new file mode 100644 index 000000000..7a73a41bf --- /dev/null +++ b/TaskModules/powershell/Sanitizer/Strings/resources.resjson/zh-TW/resources.resjson @@ -0,0 +1,2 @@ +{ +} \ No newline at end of file diff --git a/TaskModules/powershell/Sanitizer/Tests/L0.ts b/TaskModules/powershell/Sanitizer/Tests/L0.ts index 194fdf836..a770c8468 100644 --- a/TaskModules/powershell/Sanitizer/Tests/L0.ts +++ b/TaskModules/powershell/Sanitizer/Tests/L0.ts @@ -1,12 +1,9 @@ /// /// -/// -import Q = require('q'); -import assert = require('assert'); import path = require('path'); -var psm = require('../../../Tests/lib/psRunner'); +var psm = require('../../../../Tests/lib/psRunner'); var psr = null; describe('Security Suite', function () { @@ -49,4 +46,16 @@ describe('Security Suite', function () { psr.run(path.join(__dirname, 'L0Get-SanitizedArgumentsArray.DoesNotBreakExistingBashFormats.ps1'), done); }); } -}); \ No newline at end of file + + if (psm.testSupported()) { + it('Protect-ScriptArguments should pass correctly', (done) => { + psr.run(path.join(__dirname, 'L0Protect-ScriptArguments.Passes.ps1'), done); + }); + } + + if (psm.testSupported()) { + it('Protect-ScriptArguments should throw', (done) => { + psr.run(path.join(__dirname, 'L0Protect-ScriptArguments.Throws.ps1'), done); + }); + } +}); diff --git a/TaskModules/powershell/Sanitizer/Tests/L0Get-SanitizedArgumentsArray.DoesNotBreakExistingBashFormats.ps1 b/TaskModules/powershell/Sanitizer/Tests/L0Get-SanitizedArgumentsArray.DoesNotBreakExistingBashFormats.ps1 index 01af752bc..76bdd2bd0 100644 --- a/TaskModules/powershell/Sanitizer/Tests/L0Get-SanitizedArgumentsArray.DoesNotBreakExistingBashFormats.ps1 +++ b/TaskModules/powershell/Sanitizer/Tests/L0Get-SanitizedArgumentsArray.DoesNotBreakExistingBashFormats.ps1 @@ -21,5 +21,5 @@ foreach ($argument in $bashArgumentsFormats) { $sanitizedArguments = Get-SanitizedArguments -InputArgs $argument # Assert - Assert-AreEqual $sanitizedArguments $argument -} \ No newline at end of file + Assert-AreEqual -Actual $sanitizedArguments -Expected $argument +} diff --git a/TaskModules/powershell/Sanitizer/Tests/L0Get-SanitizedArgumentsArray.DoesNotBreakExistingCmdFormats.ps1 b/TaskModules/powershell/Sanitizer/Tests/L0Get-SanitizedArgumentsArray.DoesNotBreakExistingCmdFormats.ps1 index 070d9568a..5ff8bccec 100644 --- a/TaskModules/powershell/Sanitizer/Tests/L0Get-SanitizedArgumentsArray.DoesNotBreakExistingCmdFormats.ps1 +++ b/TaskModules/powershell/Sanitizer/Tests/L0Get-SanitizedArgumentsArray.DoesNotBreakExistingCmdFormats.ps1 @@ -20,5 +20,5 @@ foreach ($argument in $cmdArgumentsFormats) { $sanitizedArguments = Get-SanitizedArguments -InputArgs $argument # Assert - Assert-AreEqual $sanitizedArguments $argument + Assert-AreEqual -Actual $sanitizedArguments -Expected $argument } \ No newline at end of file diff --git a/TaskModules/powershell/Sanitizer/Tests/L0Get-SanitizedArgumentsArray.DoesNotBreakExistingPowerShellFormats.ps1 b/TaskModules/powershell/Sanitizer/Tests/L0Get-SanitizedArgumentsArray.DoesNotBreakExistingPowerShellFormats.ps1 index 22cdef700..5c7f2a783 100644 --- a/TaskModules/powershell/Sanitizer/Tests/L0Get-SanitizedArgumentsArray.DoesNotBreakExistingPowerShellFormats.ps1 +++ b/TaskModules/powershell/Sanitizer/Tests/L0Get-SanitizedArgumentsArray.DoesNotBreakExistingPowerShellFormats.ps1 @@ -21,5 +21,5 @@ foreach ($argument in $powershellArgumentsFormats) { $sanitizedArguments = Get-SanitizedArguments -InputArgs $argument # Assert - Assert-AreEqual $sanitizedArguments $argument + Assert-AreEqual -Actual $sanitizedArguments -Expected $argument } \ No newline at end of file diff --git a/TaskModules/powershell/Sanitizer/Tests/L0Get-SanitizedArgumentsArray.ReplacesForbiddenCharacters.ps1 b/TaskModules/powershell/Sanitizer/Tests/L0Get-SanitizedArgumentsArray.ReplacesForbiddenCharacters.ps1 index a71fe62af..214311c89 100644 --- a/TaskModules/powershell/Sanitizer/Tests/L0Get-SanitizedArgumentsArray.ReplacesForbiddenCharacters.ps1 +++ b/TaskModules/powershell/Sanitizer/Tests/L0Get-SanitizedArgumentsArray.ReplacesForbiddenCharacters.ps1 @@ -14,5 +14,5 @@ $sanitizedArguments = Get-SanitizedArguments -InputArgs $arguments # Assert -# We need to use $sanitizedArguments[1] because $sanitizedArguments contains buffer with Write-Output message from the function execution. -Assert-AreEqual $sanitizedArguments[1] "start notepad.exe _#removed#_ echo 'hello' _#removed#_ calc.exe" \ No newline at end of file +# We need to use $sanitizedArguments[1] because $sanitizedArguments contains buffer with Write-Output message from the function execution. +Assert-AreEqual -Expected "start notepad.exe _#removed#_ echo 'hello' _#removed#_ calc.exe" -Actual $sanitizedArguments diff --git a/TaskModules/powershell/Sanitizer/Tests/L0Protect-ScriptArguments.Passes.ps1 b/TaskModules/powershell/Sanitizer/Tests/L0Protect-ScriptArguments.Passes.ps1 new file mode 100644 index 000000000..a81e6c9d6 --- /dev/null +++ b/TaskModules/powershell/Sanitizer/Tests/L0Protect-ScriptArguments.Passes.ps1 @@ -0,0 +1,41 @@ +[CmdletBinding()] +param() + +Set-Item -Path env:AZP_75787_ENABLE_NEW_LOGIC -Value 'true' + +. $PSScriptRoot\..\..\..\..\Tests\lib\Initialize-Test.ps1 +. $PSScriptRoot\..\ArgumentsSanitizer.ps1 + +$inputArgsSuites = @( + "/parameter", # Traditional way to pass parameters in CMD + "-parameter", # Modern applications accept parameters with a hyphen + "--parameter", # Many modern applications accept parameters with double hyphen + "parameter=value", # Format for passing values to parameters + "parameter value.txt", # Argument with dot in the middle + "-parameter", # Single hyphen followed by a single letter or digit (POSIX style) + "-parameter value", # When the parameter needs a value + "--parameter", # Double hyphen followed by a word (GNU style) + "--parameter=value", # Value directly attached to the parameter with an equals sign + "parameter=value", # Used to pass environment variables to a command + "parameter value.txt", # Argument with dot in the middle + "-Parameter Value", # Most common form + "-Parameter:Value", # Colon connects the parameter and its value + "/p:Parameter=Value", # Specific syntax for tools like MSBuild or NuGet + "--Parameter Value", # Used by cmdlets or scripts for cross-platform compatibility + "--Parameter=Value", # Used by cross-platform tools + "parameter value.txt" # Argument with dot in the middle + 'a A 1 \ ` _ '' " - = / : . * , + ~ ? %', # Just each allowed symbol + '', + 'test 1', + 'test `; whoami `&`& echo test', + "line 1 `n line 2" +) + +foreach ($inputArgs in $inputArgsSuites) { + try { + Protect-ScriptArguments $inputArgs + } + catch { + throw "Error occured with '$inputArgs' input args: $($_.Exception.Message)" + } +} diff --git a/TaskModules/powershell/Sanitizer/Tests/L0Protect-ScriptArguments.Throws.ps1 b/TaskModules/powershell/Sanitizer/Tests/L0Protect-ScriptArguments.Throws.ps1 new file mode 100644 index 000000000..2b8f65262 --- /dev/null +++ b/TaskModules/powershell/Sanitizer/Tests/L0Protect-ScriptArguments.Throws.ps1 @@ -0,0 +1,22 @@ +[CmdletBinding()] +param() + +Set-Item -Path env:AZP_75787_ENABLE_NEW_LOGIC -Value 'true' + +. $PSScriptRoot\..\..\..\..\Tests\lib\Initialize-Test.ps1 +. $PSScriptRoot\..\ArgumentsSanitizer.ps1 + +$inputArgsSuites = @( + 'test; whoami', + 'test && whoami', + 'echo "$(rm ./somedir)"', + 'test | whoami' +) + +$expectedMsg = Get-VstsLocString -Key 'PS_ScriptArgsSanitized' + +foreach ($inputArgs in $inputArgsSuites) { + Assert-Throws { + Protect-ScriptArguments $inputArgs + } -MessagePattern $expectedMsg +} diff --git a/TaskModules/powershell/Sanitizer/Tests/L0Split-Arguments.ps1 b/TaskModules/powershell/Sanitizer/Tests/L0Split-Arguments.ps1 index 3a4f82905..9a4f45a7d 100644 --- a/TaskModules/powershell/Sanitizer/Tests/L0Split-Arguments.ps1 +++ b/TaskModules/powershell/Sanitizer/Tests/L0Split-Arguments.ps1 @@ -33,5 +33,5 @@ for ($i = 0; $i -lt $argumentsFormats.Length; $i++) { [string[]]$splitArguments = Split-Arguments -arguments $argumentsFormats[$i] # Assert - Assert-AreEqual $splitArguments $expectedOutputs[$i] -} \ No newline at end of file + Assert-AreEqual -Expected $splitArguments -Actual $expectedOutputs[$i] +} diff --git a/TaskModules/powershell/Sanitizer/module.json b/TaskModules/powershell/Sanitizer/module.json index b00eb9eb7..52d6c692b 100644 --- a/TaskModules/powershell/Sanitizer/module.json +++ b/TaskModules/powershell/Sanitizer/module.json @@ -1,6 +1,6 @@ { "messages": { - "PS_ScriptArgsSanitized": "Detected characters in arguments that may not be executed correctly by the shell. Please escape special characters using backtick (`). More information is available here: ", + "PS_ScriptArgsSanitized": "Detected characters in arguments that may not be executed correctly by the shell. Please escape special characters using backtick (`). More information is available here: https://aka.ms/ado/75787", "PS_ScriptArgsNotSanitized": "Arguments passed sanitization without change." } } \ No newline at end of file