Decrypt PSCredential object password and it’s applications

Hello Everyone,

I feel it’s no more a secret that you can decrypt PSCredential Object and read/get the password in plain text. Wait…, I do not know what is PSCredntial objectThis is what you must be thinking. I feel you stumble upon PSCredential object if you do basic PowerShell for system administration.

Get-Credential is the cmdlet that will prompt you for username and password. once you enter your username and password then its basically a PSCredential object for you.

gc

Now, Let’s take a look at the PSCredential Object.

$cred= Get-Credential 
$cred|Get-Member

I have stored credentials in a variable $cred which is now a PSCredential Object. When you do Get-member you will come to know more about this PSCredential Object. Look at the below screenshot to understand more.

gc1

When I get $cred in the last command, It does show you a username and password. but if you notice Password than you will come to know that it’s stored as a secure string. This is good because you do not want PowerShell to store the password in plain text.

However, this is sometimes a need to reuse the same credential to authenticate with some other processes in your PowerShell script which requires plain text password as an input. Also, there is a limitation of the PSCredential Object. PSCredential Object will work on cmdlets that know what a PSCredential Object is. In fact, not all the .Net Classes understand what PSCredential Object is. So if you have a cmdlet which is written in .Net class rather than a PowerShell class than you can’t reuse the PSCredential object. In Order to use this, you need to decrypt the password from PSCredential Object and reuse the password to the respective class. Another example is invoking REST APIs, Not all REST APIs understand PSCredential so this means that you need to pass the username and password as a plain text.

Check the below example script, Here I need to invoke a REST method POST which requires username and password to authenticate. I have 2 parameters Pwd(Password) and Name (Username). This specific API does not understand the PSCredential so I need to pass the credential password in plain text.

Now, if I have this script than obviously, it is not secure because whoever has the access to the script will be able to know the credential which you don’t want to do obviously.

$headersLogin = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headersLogin.Add("Content-Type", "application/json")

$bodyLogin = @{
    aaaUser = @{
        attributes=@{
                      pwd= "TestPassword"
                      name = "Admin"
                     }
                }
             }

$payload= $bodyLogin|ConvertTo-Json
$responseLogin = Invoke-RestMethod 'https://Controller-IP/api/aaaLogin.json' -Method 'POST' -Headers $headersLogin -Body $payload
$responseLogin | ConvertTo-Json

So what is the Solution?  Let’s try something.

Can I access the password directly from the PSCredential object

No, You can’t as it’s stored as a secure string. Look at this example.

gc2

  • $cred.Password will not return you the Password as plain text
  • $cred.Password|Convertfrom-SecureString will give you cipher data rather than a password as a plain text.

So what’s the solution. Well, the solution is in the PSCredential object itself. Do $cred|Get-member. 

gc3

PSCredential object has a method called GetNetworkCredential() method. you can use this method to decrypt the password in PSCredential object.

When I invoke this method and do Get-Member, it will show you the properties of the object and you will find a property called Password. use the last command $cred.GetNetworkCredential().Password and it will return the password in plain text. Please refer to the below screenshot.

gc4

So now I have modified the same script as below,

$headersLogin = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headersLogin.Add("Content-Type", "application/json")

$cred= Get-Credential
$bodyLogin = @{
    aaaUser = @{
        attributes=@{
                      pwd= $cred.GetNetworkCredential().Password
                      name = "Admin"
                     }
                }
             }

$payload= $bodyLogin|ConvertTo-Json
$responseLogin = Invoke-RestMethod 'https://Controller-IP/api/aaaLogin.json' -Method 'POST' -Headers $headersLogin -Body $payload
$responseLogin | ConvertTo-Json

Conclusion: 

Yes, PSCredential stores the password in a secure string but it has a built-in function GetNetworkCredential() to decrypt the same.

Is it safe to use?

I feel No. Once script execution stops or runtime environment close, variables get disposed and you no longer have access to the variable. However, there are ways in which you can obviously exploit this feature with some tweaks in your Powershell script. for example, I wrote this to a text file. So yes, a PowerShell developer can write this line of code to a txt file and exploit a feature that was intended to be there to help you out.

gc5

I am not sure what is the right way to use credentials in PowerShell script. if you know a method which is definitely a secure way than do let me know with your comments here.


Thanks,

 

 

Leave a Reply