vRO: Securing Your PowerShell Execution and Password in vRO (SKKB1035)

It's only fair to share...Share on FacebookTweet about this on TwitterShare on LinkedInShare on Google+Digg thisPin on PinterestShare on TumblrPrint this pageEmail this to someone

In this blog post we will take a look at how we can secure your end to end PowerShell Execution from vRO. Including how not to show passwords when using CredSSP in a double-hop authentication scenario.

Update Log:

12.02.2016 – Updated diagrams. Added "Securing the PowerShell Password" chapter.

 

Lab Environment

The full lab logical design can be seen HERE.

Introduction

We will take a look at few common use cases regarding the configuration of vRO, the PowerShell Host, the WinRM Protocol, and the PS Script/command and how we can best secure all of them.

WS-Management encrypts all traffic by default and this is controlled by the AllowUnencrypted client and server WinRM configuration parameter. Even if you only work with HTTP (which is the default configuration) and not with HTTPS. Prior to Windows Server 2003 R2 this WInRM in an HTTP session is not encrypted.

By default, PowerShell remoting authenticates using a “Network Logon”.  Network Logons work by proving to the remote server that you have possession of the users credential without sending the credential to that server. Because the remote server doesn’t have possession of your credential, when you try to make the second hop (from Server A to Server B) it fails because Server A doesn’t have a credential to authenticate to Server B with.
To get around this issue, PowerShell provides the CredSSP option. When using CredSSP, PowerShell will perform a “Network Clear-text Logon” instead of a “Network Logon”. Network Clear-text Logon works by sending the user’s clear-text password to the remote server. When using CredSSP, Server A will be sent the user’s clear-text password, and will therefore be able to authenticate to Server B. Double hop works!

Microsoft has made changes to Windows Server 2012R2 and Windows 8.1 to eliminate clear-text credentials from being stored in memory. Additionally, even though your clear-text credential is not saved in memory, it is still sent to the remote server.

An additional layer of protection can be added by using WinRM with HTTPS . HTTPS doesn’t just add another encryption layer; its main purpose is to verify the authenticity of the remote machine, thereby preventing man-in-the-middle attacks.

So back the example.

As you have a double-hop authentication scenario you need to use CredSSP. Your starting script will most likely contain the following code:

$username = "vmware\administrator"
$password = "VMware1!"
$psHost = "lan1dc1"
$cred = New-Object System.Management.Automation.PSCredential -ArgumentList @($username,(ConvertTo-SecureString -String $password -AsPlainText -Force))
Invoke-Command -ComputerName $psHost -ScriptBlock { SomeCommand } -Authentication CredSSP -credential $cred

As you can see the password is stored in plain text. After successfully securing it will no longer be exposed.

 

Use Case 1 (least secure)

This use case illustrates the worst use case scenario possible. In it every component is configured to allow unencrypted traffic and passwords are send in plain text over the network.
Consider the following configuration:

  • We have stored the password in plain text in our PowerShell script. The script is stored in vRO.
  • We have added an HTTP PowerShell Host. Therefore communication b/n vRO and the PowerShell host is not encrypted.
  • WinRM is set to allow unencrypted traffic (AllowUnencrypted=True). Therefore WinRM traffic when using CredSSP from out powershell host to our second server the password is send WinRM unencrypted in plain text.
  • WinRM is configured to use HTTP. Therefore traffic is unencrypted b/n server.
  • The end destination server (on the CredSSP receiving side) is prior to Windows Server 2008 R2. Therefore the password is stored in plain text in memory and can easily be retrieved.

Illustrated this configuration will look something like this:

Lets explore another use case that shows more secure configuration. 

 

Use Case 2

This use case illustrates a bit more secure scenario.
Consider the following configuration:

  • We have stored the password as SecureString in vRO . vRO cannot see the password in the WF. The password is still being send over the network to the PS Host in plain text.
  • We have added an HTTPS PowerShell Host. Therefore communication b/n vRO and the PowerShell host is encrypted. Although the password itself is send in plain text it is send over an encrypted HTTPS channel.
  • WinRM is set to deny unencrypted traffic (AllowUnencrypted=False). Therefore WinRM traffic when using CredSSP from our PowerShell host to our second server the password is send WinRM encrypted.
  • WinRM is configured to use HTTP and HTTPS, but we are not forcing HTTPS in our script code. Therefore traffic is unencrypted b/n server.
  • The end destination server (on the CredSSP receiving side) is newer then Windows Server 2008 R2. Therefore the password is no longer stored in plain text in memory.

Illustrated this configuration will look something like this:

Lets explore another use case that shows even more secure configuration. 

 

Use Case 3 (Most Secure)

This use case illustrates a secure scenario.
Consider the following configuration:

  • We have converted out password as PowerShell SecureString Object and saved it in a file. That file can lie on the Windows Server or within vRO. vRO Users cannot see the password in plain text in the WF. Password in Plain Text from vRO to the PS Host server is not send, instead the PowerShell SecureString Object is send.
  • We have added an HTTPS PowerShell Host. Therefore communication b/n vRO and the PowerShell host is encrypted. HTTPS brings additional layer of protection on top of the use of  PowerShell SecureString Object to encrypt the communication channel.
  • WinRM is set to deny unencrypted traffic (AllowUnencrypted=False). Therefore WinRM traffic when using CredSSP from our PowerShell host to our second server the password is send WinRM encrypted.
  • WinRM is configured to use HTTP and HTTPS. In addition we are using the –UseSSL switch in the Invoke-Command to force WinRM to use HTTPS. Therefore traffic is encrypted b/n servers. To go even further we may even delete the HTTP Listener so that only HTTPS communication is possible.
  • The end destination server (on the CredSSP receiving side) is newer then Windows Server 2008 R2. Therefore the password is no longer stored in plain text in memory.

Illustrated this configuration will look something like this:

 

Securing the PowerShell Password

In a typical scenario your script will contain similar code where CredSSP is used:

$username = "vmware\administrator"
$password = "VMware1!"
$psHost = "lan1dc1"
$cred = New-Object System.Management.Automation.PSCredential -ArgumentList @($username,(ConvertTo-SecureString -String $password -AsPlainText -Force))
Invoke-Command -ComputerName $psHost -ScriptBlock { SomeCommand } -Authentication CredSSP -credential $cred

This an example of typical payload send by vRO when executing PowerShell commands. If we send the payload as it is the password is send over the network in plain text.
We can use the ConvertTo-SecureString and ConvertFrom-SecureString cmdlets to encrypt the password.

The ConvertTo-SecureString cmdlet converts encrypted standard strings into secure strings. It can also convert plain text to secure strings. The secure string created by the cmdlet can be used with cmdlets or functions that require a parameter of type SecureString. The secure string can be converted back to an encrypted, standard string using the ConvertFrom-SecureString cmdlet. This enables it to be stored in a file for later use.

If the standard string being converted was encrypted with ConvertFrom-SecureString using a specified key, that same key must be provided as the value of the Key or SecureKey parameter of the ConvertTo-SecureString cmdlet.

The ConvertFrom-SecureString cmdlet converts a secure string (System.Security.SecureString) to an encrypted standard string (System.String). Unlike a secure string, an encrypted standard string can be saved in a file for later use. The encrypted standard string can be converted back to a secure string by using the ConvertTo-SecureString cmdlet.

If an encryption key is specified by using the Key or SecureKey parameters, the Advanced Encryption Standard (AES) encryption algorithm is used. The specified key must have a length of 128, 192, or 256 bits, because those are the key lengths supported by the AES encryption algorithm. If no key is specified, the Windows Data Protection API (DPAPI) is used to encrypt the standard string representation.

Back to our example. We will use the simplest way and utilize the Windows Data Protection API (DPAPI) to the standard string (plain text password).

To do this we run once the following command on the PS Host to encrypt the plain text password:

"VMware1"| ConvertTo-SecureString -AsPlainText -Force | ConvertFrom-SecureString | Out-File "C:\Windows\Temp\MyEncryptedPassword.txt">

Note that the account with which you are logged in to the Windows machine when running the command must be the same as the user account you are entering when adding the PS Host in vRO. Otherwise decrypting the password will not work and you should utilize other options like SecureKey to do the encryption.

The content of the MyEncryptedPassword.txt file looks similar to this:

PS C:\_TMP> Get-Content  .\MyEncryptedPassword.txt
01000000d08c9ddf0115d1118c7a00c04fc297eb01000000e83f87deaad0ad489930981c12bb88210000000002000000000003660000c0000000100
00000abce011db75e41c01d855ddbb1d858f20000000004800000a000000010000000258af14ec5af2229f2e30d75345487a218000000925c307b64
59f34025a90c4c4a8c4816bd48a29f3c78695414000000e0501f5effc6a953a63f5c3fcc707baa5419f3c8

Now that we have a file containing an encypted password we can modify PowerShell Script to utilize it.
To do this we modify we modify our PoweShell script as follows:

$username = "vmware\administrator"
$password = Get-Content "C:\Windows\TEMP\MyEncryptedPassword.txt" | ConvertTo-SecureString
$psHost = "lan1dc1"
$cred = New-Object System.Management.Automation.PSCredential -ArgumentList $username, $password
Invoke-Command -ComputerName $psHost -ScriptBlock { get-DNSServerSetting } -Authentication CredSSP -credential $cred

If we run this script payload from vRO no password will be send over the network. Instead the password will be read from the file and decrypted straight on the PS Host.
Alternatively we can copy the entire content of the MyEncryptedPassword.txt file into our PowerShell script as follows:

$password = Get-Content "01000000d08c9ddf0115d1118c7a00c04fc297eb01000000e83f87deaad0ad489930981c12bb88210000000002000000000003660000c000000010000000abce011db75e41c01d855ddbb1d858f20000000004800000a000000010000000258af14ec5af2229f2e30d75345487a218000000925c307b6459f34025a90c4c4a8c4816bd48a29f3c78695414000000e0501f5effc6a953a63f5c3fcc707baa5419f3c8 " | ConvertTo-SecureString

Now when we run our PowerShell script from vRO it will send the encrypted password over the network. The password will still be decrypted on the PowerShell host itself.

Lets take a look into two network trace examples.

During the first we will have a plain text password in our script send from vRO.
During the second we will have a PS SecureString object storing the password
For both cases we are using an HTTP host so that we can examine the traffic.

 In the first example when we examine the TCP Stream we can capture the encoded script send over the network

We now will decode this base64 string twice:

PS C:\_TMP> $EncodedText = "WW5KdmEyVnlYM05sY21saGJHbDZaU0FuSkhWelpYSnVZVzFsSUQwZ0luWnRkMkZ5WlZ4aFpHMXBibWx6ZEhKaGRHOXlJ
Z29rY0dGemMzZHZjbVFnUFNBaVZrMTNZWEpsTVNFaUNpUndjMGh2YzNRZ1BTQWliR0Z1TVdSak1TSUtKR055WldRZ1BTQk9aWGN0VDJKcVpXTjBJRk41YzNS
bGJTNU5ZVzVoWjJWdFpXNTBMa0YxZEc5dFlYUnBiMjR1VUZORGNtVmtaVzUwYVdGc0lDMUJjbWQxYldWdWRFeHBjM1FnUUNna2RYTmxjbTVoYldVc0tFTnZi
blpsY25SVWJ5MVRaV04xY21WVGRISnBibWNnTFZOMGNtbHVaeUFrY0dGemMzZHZjbVFnTFVGelVHeGhhVzVVWlhoMElDMUdiM0pqWlNrcENrbHVkbTlyWlMx
RGIyMXRZVzVrSUMxRGIyMXdkWFJsY2s1aGJXVWdKSEJ6U0c5emRDQXRVMk55YVhCMFFteHZZMnNnZXlCblpYUXRSRTVUVTJWeWRtVnlVMlYwZEdsdVp5QjlJ
QzFCZFhSb1pXNTBhV05oZEdsdmJpQkRjbVZrVTFOUUlDMWpjbVZrWlc1MGFXRnNJQ1JqY21Wa0p5QU5DZzBLRFFvPQ0K"
PS C:\_TMP> $DecodedText = [System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String($EncodedText))
PS C:\_TMP> $DecodedText
YnJva2VyX3NlcmlhbGl6ZSAnJHVzZXJuYW1lID0gInZtd2FyZVxhZG1pbmlzdHJhdG9yIgokcGFzc3dvcmQgPSAiVk13YXJlMSEiCiRwc0hvc3QgPSAibGF
uMWRjMSIKJGNyZWQgPSBOZXctT2JqZWN0IFN5c3RlbS5NYW5hZ2VtZW50LkF1dG9tYXRpb24uUFNDcmVkZW50aWFsIC1Bcmd1bWVudExpc3QgQCgkdXNlcm
5hbWUsKENvbnZlcnRUby1TZWN1cmVTdHJpbmcgLVN0cmluZyAkcGFzc3dvcmQgLUFzUGxhaW5UZXh0IC1Gb3JjZSkpCkludm9rZS1Db21tYW5kIC1Db21wd
XRlck5hbWUgJHBzSG9zdCAtU2NyaXB0QmxvY2sgeyBnZXQtRE5TU2VydmVyU2V0dGluZyB9IC1BdXRoZW50aWNhdGlvbiBDcmVkU1NQIC1jcmVkZW50aWFs
ICRjcmVkJyANCg0KDQo=

PS C:\_TMP> $EncodedText = "YnJva2VyX3NlcmlhbGl6ZSAnJHVzZXJuYW1lID0gInZtd2FyZVxhZG1pbmlzdHJhdG9yIgokcGFzc3dvcmQgPSAiVk13
YXJlMSEiCiRwc0hvc3QgPSAibGFuMWRjMSIKJGNyZWQgPSBOZXctT2JqZWN0IFN5c3RlbS5NYW5hZ2VtZW50LkF1dG9tYXRpb24uUFNDcmVkZW50aWFsIC1B
cmd1bWVudExpc3QgQCgkdXNlcm5hbWUsKENvbnZlcnRUby1TZWN1cmVTdHJpbmcgLVN0cmluZyAkcGFzc3dvcmQgLUFzUGxhaW5UZXh0IC1Gb3JjZSkpCklu
dm9rZS1Db21tYW5kIC1Db21wdXRlck5hbWUgJHBzSG9zdCAtU2NyaXB0QmxvY2sgeyBnZXQtRE5TU2VydmVyU2V0dGluZyB9IC1BdXRoZW50aWNhdGlvbiBD
cmVkU1NQIC1jcmVkZW50aWFsICRjcmVkJyANCg0KDQo="
PS C:\_TMP> $DecodedText = [System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String($EncodedText))
PS C:\_TMP> $DecodedText
broker_serialize ‘$username = "vmware\administrator"
$password = "VMware1!"
$psHost = "lan1dc1"
$cred = New-Object System.Management.Automation.PSCredential -ArgumentList @($username,(ConvertTo-SecureString -String
$password -AsPlainText -Force))
Invoke-Command -ComputerName $psHost -ScriptBlock { get-DNSServerSetting } -Authentication CredSSP -credential $cred’

You can see that we have captured the plain text password send from vRO.

Now in the second example let’s examine the traffic and see how the PS SecureString Object will be shown:

As we can see the password is not transferred over the network.

Adding SSL and therefore adding encryption on the HTTPS transport protocol level will even more enforce security. To do this we need to add the host with HTTPS

 

 

References

Secure Password with PowerShell: Encrypting Credentials – Part 1
PowerShell Remoting over HTTPS with a self-signed SSL certificate
Accidental Sabotage: Beware of CredSSP
Compromising Yourself with WinRM’s “AllowUnencrypted = True”

Final Step

If all went well, go grab a beer.

 

It's only fair to share...Share on FacebookTweet about this on TwitterShare on LinkedInShare on Google+Digg thisPin on PinterestShare on TumblrPrint this pageEmail this to someone

One thought on “vRO: Securing Your PowerShell Execution and Password in vRO (SKKB1035)

Leave a Reply

Your email address will not be published. Required fields are marked *