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)
ISC Stormcast For Friday, December 2nd 2016


Diary Archives