azure-cli icon indicating copy to clipboard operation
azure-cli copied to clipboard

Issue to set password for secret at KeyVauklt by azure CLI

Open chamir2 opened this issue 4 years ago • 10 comments

[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.

chamir2 avatar Jan 13 '22 09:01 chamir2

For further information you can contact me by internal teams. Thanks, Amir Chen

chamir2 avatar Jan 13 '22 09:01 chamir2

yes

chamir2 avatar Jan 13 '22 11:01 chamir2

For your reference: https://github.com/Azure/azure-cli/blob/dev/doc/quoting-issues-with-powershell.md#ampersand--is-interpreted-by-command-prompt

evelyn-ys avatar Jan 27 '22 03:01 evelyn-ys

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: @.***>

chamir2 avatar Jan 28 '22 02:01 chamir2

+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
»

seh-msft avatar Apr 25 '22 22:04 seh-msft

@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.

jiasli avatar Apr 28 '22 03:04 jiasli

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

brendandburns avatar Aug 10 '22 23:08 brendandburns

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.cmd needs 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.

jiasli avatar Aug 11 '22 03:08 jiasli

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 cmd script from Command Prompt, double quotes are preserved in %*
    • When invoking a cmd script from PowerShell, double quotes are dropped, so not preserved in %*. This is a known issue of PowerShell (https://github.com/PowerShell/PowerShell/issues/1995)
  • On Linux
    • When invoking a sh script 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)

jiasli avatar Aug 11 '22 05:08 jiasli

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.

jiasli avatar Aug 11 '22 09:08 jiasli