Issue to set password for secret at KeyVauklt by azure CLI
[Enter feedback here] Hi,
Yesterday while trying to change a secret value that contains special characters I encountered an error saying that the command is not recognize. The RC was the secret had pipeline or “And” sign (| or &) at the secret value and due to it, it tried to run the secret value as a command.
To resolve this issue I use `" signs to wrap the variable
here by command example:
az keyvault secret set --name $secretName --vault-name $KeyVaultName --tags $TagsConverted --value "$newConnectionString" --expires $vaultexpires --not-before $vaultstart | Out-Null
First of all I would be happy if it can be fixed to reduce issues for other people. As well as I understand it, it can be a vulnerability - Please verify.
Thanks, Amir Chen
Document Details
⚠ Do not edit this section. It is required for docs.microsoft.com ➟ GitHub issue linking.
- ID: eeedb9a7-2aed-6727-4cfb-1515809d676e
- Version Independent ID: 2c83180d-22ad-db42-e2eb-f27f11977963
- Content: az
- Content Source: latest/docs-ref-autogen/reference-index.yml
- GitHub Login: @rloutlaw
- Microsoft Alias: routlaw
For further information you can contact me by internal teams. Thanks, Amir Chen
yes
For your reference: https://github.com/Azure/azure-cli/blob/dev/doc/quoting-issues-with-powershell.md#ampersand--is-interpreted-by-command-prompt
Thanks for your replay So I understand it’s a known issue. Would it be fixed? Any ETA? Don’t you worry it can be used as a way to remote code execution?
On Thu, 27 Jan 2022 at 5:13 Yishi Wang @.***> wrote:
For your reference: https://github.com/Azure/azure-cli/blob/dev/doc/quoting-issues-with-powershell.md#ampersand--is-interpreted-by-command-prompt
— Reply to this email directly, view it on GitHub https://github.com/Azure/azure-cli/issues/20972#issuecomment-1022806718, or unsubscribe https://github.com/notifications/unsubscribe-auth/ALTNAS5WJ2RA4NIRBLHGOZTUYCZ7LANCNFSM5L3IVAJA . Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.
You are receiving this because you authored the thread.Message ID: @.***>
+1, ran into this today.
Has to be mishandling of the input value when passing on a password with a pipe | character.
Ex.
az keyvault secret set --vault-name SomeVault --name foobar --value abc123|de
Yielding the error:
'de' is not recognized as an internal or external command,
operable program or batch file.
Not through the shell, but through an exec call to az directly, which tells me that this is a mishandling inside the az cli not properly quoting values, then passing them on into a shell execution later.
You can trivially turn this into code execution with a command like:
» az keyvault secret set --vault-name SomeVault --name foobar --value 'abc123|whoami'
mydom\myusername
Exception ignored in: <_io.TextIOWrapper name='<stdout>' mode='w' encoding='cp1252'>
OSError: [Errno 22] Invalid argument
»
@evelyn-ys is correct. This is caused by PowerShell issue https://github.com/PowerShell/PowerShell/issues/1995 that PowerShell doesn't quote arguments correctly when calling a cmd script.
⚠️ This issue happens when using PowerShell to call any cmd script, not only limited to Azure CLI.
az is a cmd script at C:\Program Files (x86)\Microsoft SDKs\Azure\CLI2\wbin\az.cmd:
@IF EXIST "%~dp0\..\python.exe" (
SET AZ_INSTALLER=MSI
"%~dp0\..\python.exe" -IBm azure.cli %*
) ELSE (
echo Failed to load python executable.
exit /b 1
)
Since there is no space in abc123|whoami, PowerShell won't quote abc123|whoami when calling the cmd script, causing raw abc123|whoami to appear in %*. For example, %* becomes
keyvault secret set --vault-name SomeVault --name foobar --value abc123|whoami
Command Prompt will then interpret |.
The fix should be on PowerShell side that if an argument is quoted, the argument should also be quoted when calling a cmd script.
To work around this issue, you may quote the input twice, one for PowerShell, one for Command Prompt:
> az keyvault secret set --debug --vault-name SomeVault --name foobar --value '"abc123|whoami"'
cli.knack.cli: Command arguments: ['keyvault', 'secret', 'set', '--debug', '--vault-name', 'SomeVault', '--name', 'foobar', '--value', 'abc123|whoami']
On Azure CLI side, this is tracked by https://github.com/Azure/azure-cli/issues/15529.
I looked into this and I believe that this is actually a bug in the az.cmd command. The reason for this is that the single quotes in --value 'foo|whoami' are there to preserve the string for the context of the shell (in this case PowerShell) it's responsibility is to pass that string to the underlying command without interpreting it, but it is expected to drop the quotes in this case. This is what bash does for example.
az.cmd needs to re-escape with single quotes all of the arguments that it gets from powershell in this context
Thanks @brendandburns for the insights. Please allow me to provide more details.
az on Windows: Command Prompt vs PowerShell
Consider the entry script az.cmd is invoked by Command Prompt and PowerShell.
In Command Prompt: az.cmd works as expected, because double quotes are preserved by Command Prompt, so that foo|whoami is treated as a string:
>az --debug "foo|whoami"
cli.knack.cli: Command arguments: ['--debug', 'foo|whoami']
In PowerShell: The same command causes issue because double quotes are dropped by PowerShell, so the vertical bar (|) was interpreted by Command Prompt as pipe:
> az --debug "foo|whoami"
fareast\jiasli
DEBUG: cli.knack.cli: Command arguments: ['--debug', 'foo']
> az --debug 'foo|whoami'
fareast\jiasli
DEBUG: cli.knack.cli: Command arguments: ['--debug', 'foo']
The base line is, Command Prompt and PowerShell should have the same behavior when invoking the same cmd script. It is also hard and not very practicable for the cmd script to detect its caller and behave differently.
az on Linux
The entry script az on Debian/Ubuntu is generated by this line:
https://github.com/Azure/azure-cli/blob/1d065f0cb183ab32fef32c7eeb27882ce03dfaa0/scripts/release/debian/prepare.sh#L109
And the generated file is
$ cat /usr/bin/az
#!/usr/bin/env bash
bin_dir=`cd "$(dirname "$BASH_SOURCE[0]")"; pwd`
AZ_INSTALLER=DEB "$bin_dir"/../../opt/az/bin/python3 -Im azure.cli "$@"
It utilizes Bash's Special Parameters @* and double quotes it as "$@" to avoid shell interpretation while preserving individual arguments.
"$@" is equivalent to "$1" "$2"
For example, when we call az --debug "foo|whoami", even though double quotes are dropped by the calling Bash, "$@" will re-escape it:
...python3 -Im azure.cli "--debug" "foo|whoami"
az.cmdneeds to re-escape with single quotes all of the arguments that it gets from powershell in this context
But as far as we know, Command Prompt can't re-escape arguments while preserving individual arguments, because "%*" will concatenate all arguments as one string. Even if we can quote all arguments similar to Bash, re-escaping arguments will break az.cmd in Command Prompt, because Command Prompt doesn't drop double quotes and the python command will become
python.exe -IBm azure.cli ""foo|whoami""
^ ^ These quotes are added by us, causing duplicated quotes
whoami will again be interpreted by Command Prompt.
Also, single quotes (') are not recognized as by Command Prompt. Only double quotes (") are interpreted by Command Prompt denoting strings.
I think the fundamental difference between Windows and Linux is whether quotes are preserved when calling a script from shell. In a nutshell,
- On Windows
- When invoking a
cmdscript from Command Prompt, double quotes are preserved in%* - When invoking a
cmdscript from PowerShell, double quotes are dropped, so not preserved in%*. This is a known issue of PowerShell (https://github.com/PowerShell/PowerShell/issues/1995)
- When invoking a
- On Linux
- When invoking a
shscript from Bash, double quotes are NOT preserved in$@. That why we use"$@"to re-escape with double quotes. (I found a very helpful post: https://stackoverflow.com/a/9995322/2199657)
- When invoking a
To better demonstrate the behavior difference between Command Prompt and PowerShell, consider a very simply script test.cmd:
@echo %*
When invoked from Command Prompt:
D:\>test "arg1" arg2
"arg1" arg2
D:\>test "a|b"
"a|b"
But when invoked from PowerShell:
PS D:\> ./test "arg1" arg2
arg1 arg2
PS D:\> ./test "a|b"
'b' is not recognized as an internal or external command,
operable program or batch file.
In the first execution, arg1's double quotes are lost. In the second execution, | is interpreted by cmd.exe.