Protecting Powershell Credentials (NOT)

Published: 2016-12-02
Last Updated: 2016-12-02 14:35:57 UTC
by Rob VandenBrink (Version: 1)
3 comment(s)

If you're like me, you've worked through at least one Powershell tutorial, class or even a "how-to" blog.  And you've likely been advised to use the PSCredential construct to store credentials.  The discussion usually covers that this a secure way to collect credentials, then store them in a variable for later use.  You can even store them in a file and read them back later.  Awesome - this solves a real problem you thought - or does it?

For instance, to collect credentials for a VMware vSphere infrastructure (I'm wrapping up a number of audit scripts this week), you'd do something like:

$vicreds = Get-Credential $null

Which gets you a familiar input screen:

But while I was working on my scripts, I got to thinking.  Wait a minute - I'm using this same credential variable to authenticate to vSphere, to map drives and to login to several web interfaces.  What that means to me is that these credentials are being decrypted as they're used in at least some cases.  And given that Powershell is essentially a front-end to dotNet and every other Windows API ever invented, that means that we can likely decrypt this password too.

Let's take a look.  First, what's in that PSCredentials variable?

$vicreds | gm

   TypeName: System.Management.Automation.PSCredential

Name                 MemberType Definition
----                 ---------- ----------
Equals               Method     bool Equals(System.Object obj)
GetHashCode          Method     int GetHashCode()
GetNetworkCredential Method     System.Net.NetworkCredential GetNetworkCrede...
GetObjectData        Method     void GetObjectData(System.Runtime.Serializat...
GetType              Method     type GetType()
ToString             Method     string ToString()
Password             Property   securestring Password {get;}
UserName             Property   string UserName {get;}

The username is in the clear:


However, the password is in the Powershell "securestring" format:


Digging deeper, what's behind that passord property?

$vicreds.password | gm

   TypeName: System.Security.SecureString

Name         MemberType Definition
----         ---------- ----------
AppendChar   Method     void AppendChar(char c)
Clear        Method     void Clear()
Copy         Method     securestring Copy()
Dispose      Method     void Dispose(), void IDisposable.Dispose()
Equals       Method     bool Equals(System.Object obj)
GetHashCode  Method     int GetHashCode()
GetType      Method     type GetType()
InsertAt     Method     void InsertAt(int index, char c)
IsReadOnly   Method     bool IsReadOnly()
MakeReadOnly Method     void MakeReadOnly()
RemoveAt     Method     void RemoveAt(int index)
SetAt        Method     void SetAt(int index, char c)
ToString     Method     string ToString()
Length       Property   int Length {get;}

Running digging deeper with "tostring", we get no further.


But dumping the password length, we get the right answer!  This means it's getting decrypted for-sure.


After some googling, I found the "convertfrom-securestring" command, but what I get out of that is a boatload of obfuscation:

ConvertFrom-SecureString $vicreds.password

After a bit more looking, it was as simple as finding the right command - which is what we pretty much knew going in!


Yup, that's the super-secret password we started with!

The point of all of this?  There is no secure, native way to store passwords for re-use.  For some reason as an industry, lots of folks have got the understanding that PSCredential makes a great "vault" for passwords though.  The PSCredential approach is definitely the way to go in any code you might be writing.  For me though, I'd be sure to use it only where required, zero out these variables when you're done with them to at least try to work against memory scraping (and hope that zeroing them out actually works), and I'm not storing them off to files for later re-use.   If you can use certificates for authentication, that's really the best way to go - though there are good and not-so-good ways to do this too (stay tuned).  Or better yet, 2FA beats every other method hands-down!

And for goodness sake, don't use PSCredentials as a credential store for use in authentication of other users - don't take userid/password entry and compare it to encrypted passwords of any kind!  Salted hashes (PBKDF2 by preference) is still the way to go for this!

Rob VandenBrink

Keywords: PowerShell
3 comment(s)


What happens if you try to decrypt the password saved in a file, but as another user or on another computer? For example, with this procedure:

In my testing, I wasn't able to decrypt the password unless I was on the same computer and logged on as the same user as when I created the file. It's been a while since I did this, and maybe I messed up...

That's a point in the favour of PSCredentials - if it's an interactive process, you're entering your own password in your own session. This would certainly reduce the risk factor by a mile, so much better than I realized, thanks very much!

But if it's saved to a file, then it's only as secure as the credentials that saved them or uses the file. I would expect that a common use of this type of saved file would be to give a user an elevated access via a script, without giving them actual credentials. For instance, giving the helpdesk rights to shutdown vSphere during a power outage - if you've ever had to race the thermometer, then this situation will be really familiar! If you can use the file, then you (or anyone who can compromise your account) can decrypt the file.

Thanks for the additional info though, it certainly modifies the discussion when considering the risk of using this method!!
It uses DPAPI under the hood as clearly shown by 'ConvertFrom-SecureString $vicreds.password' output. So whatever applies to DPAPI should hold here.

Diary Archives