Decrypt PowerShell Secure String Password

Decrypt PowerShell Secure String Password

  • Comments 12
  • Likes

Summary: Microsoft Scripting Guy, Ed Wilson, shows how to easily decrypt the Windows PowerShell secure string password.

Hey, Scripting Guy! Question Hey, Scripting Guy! We have an FTP site that I have to use on a regular basis. I need an easy way to get a credential and use that credential with the FTP site so that I can download a file that changes on a daily basis. I found a few scripts and functions on the Internet that will decrypt the secure string password from a Windows PowerShell credential object, but they all seem really complicated. Is there an easy way to do this?

—AD

Hey, Scripting Guy! Answer Hello AD,

Microsoft Scripting Guy, Ed Wilson, is here. Today I am sitting here drinking a cup of Earl Grey tea with a pinch of lavender in it. I love the way the two flavors complement each other. As I look over my email, I ran across your question. Although you did not include a link to the complicated versions of the scripts and functions you ran across, I will venture to say that my method should be relatively painless.

           Note   What I am showing here today is exactly by design, and is not a hack.

Using Get-Credential for credentials

I love using the Get-Credential cmdlet to retrieve a credential object. It is already set up to work; and therefore, it is easy to use. If I need credentials, I do not need to mess around writing HTAs, creating various WinForms to prompt for a user name and password, or worry about how to mask the password—all of which were problems before Windows PowerShell and the Get-Credential cmdlet. So, like I say, I absolutely love it. To use the Get-Credential cmdlet, I generally store the resulting credential object in a variable. (I do not have to do so, because I can use it directly if I need to, but it is more flexible to store it in a variable.) Here is the command.

$credential = Get-Credential

When I run this command, a dialog box appears. The box is already set up to use, with a user name on the top, and it masks the password in the bottom box. The box is shown here.

Image of dialog box

 The problem with Get-Credential

The problem with the Get-Credential cmdlet is that it returns a PSCredential object. In itself, this is not an issue, but it does mean that I can only use the credential object for cmdlets and for other items that know what a PSCredential object is. Not even all .NET classes know how to deal with a PSCredential object, so when it comes to connecting to legacy databases and things like websites and FTP sites, there is little hope of being able to use the object directly.

Luckily, I can use the Get-Member cmdlet to look at the members of a PSCredential object. The members are listed here.

PS C:\> $credential | 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 GetNetworkCredential()

GetObjectData        Method     void GetObjectData(System.Runtime.Serialization.S...

GetType              Method     type GetType()

ToString             Method     string ToString()

Password             Property   securestring Password {get;}

UserName             Property   string UserName {get;}

At first, it looks like things are relatively easy. If I want to see the user name, all I need to do is access the UserName property as shown here.

PS C:\> $credential.UserName

mydomain\someuser

That is cool. Now what about the password? When I access the Password property, it returns SecureString. This is shown here.

PS C:\> $credential.Password

System.Security.SecureString

Hmmm, what if I look at the members of SecureString? I pipe it to the Get-Member cmdlet, and I see the following members.

PS C:\> $credential.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;}

Ok, cool. I will try the ToString method and see what happens.

PS C:\> $credential.Password.ToString()

System.Security.SecureString

Well, that was less than illuminating…

What if I try the Length property? Does it give me anything?

PS C:\> $credential.Password.Length

17

It does.This is promising. I can at least write code that checks the length of the password and provides some sort of feedback to users regarding the length of the password they supply. It could be rather a cool solution.

What if I use the ConvertFrom-SecureString cmdlet? This is a standard Windows PowerShell cmdlet, so I decide to pipe the password to the ConvertFrom-SecureString cmdlet. The following illustrates the output.

PS C:\> $credential.Password | ConvertFrom-SecureString

01000000d08c9ddf0115d1118c7a00c04fc297eb0100000052ded6c2db80e748933432e19b9de8b10000

000002000000000003660000c00000001000000016dc35885d76d07bab289eb9927cfc1e000000000480

0000a0000000100000003106cde553f45b08d13d89d11336170b280000005cc865c1ee1b57e84ed3d1a2

d3f2d0ec0f189b532e61c18d1f31444d6f119a1e8368477fd2d81f54140000000cb0262e58b08ae14f37

22c14c69684841b6b21c

This latest representation is a string, and therefore there are no more options available for decrypting the password—at  least, none that are very direct or easy to use.

Get a network credential

The solution, is to go back to the PSCredential object itself. It has a method that is designed to help with the exact scenario. I need to provide credentials to a legacy type of interface that does not know how to handle a PSCredential. Therefore, I need to be able to get both the user name and the password in an easy-to-use and easy-to-digest manner. When I call the GetNetworkCredential method from the PSCredential object, it returns the user name and the domain name. This is shown here.

PS C:\> $credential.GetNetworkCredential() 

UserName                                           Domain

--------                                           ------

someuser                                           mydomain

If I pipe the returned object to the Get-Member cmdlet, however, I see that I now have a NetworkCredential object. The members are listed here.

PS C:\> $credential.GetNetworkCredential() | gm 

   TypeName: System.Net.NetworkCredential

 

Name           MemberType Definition

----           ---------- ----------

Equals         Method     bool Equals(System.Object obj)

GetCredential  Method     System.Net.NetworkCredential GetCredential(uri uri, str...

GetHashCode    Method     int GetHashCode()

GetType        Method     type GetType()

ToString       Method     string ToString()

Domain         Property   string Domain {get;set;}

Password       Property   string Password {get;set;}

SecurePassword Property   securestring SecurePassword {get;set;}

UserName       Property   string UserName {get;set;}

I see the password has a SecureString for the SecurePassword property, but there is also the Password property that is a plain string. So, I pipe the NetworkCredential object to the Format-List cmdlet and the following appears.

PS C:\> $credential.GetNetworkCredential() | fl * 

UserName       : someuser

Password       : SomeUsersPassword

SecurePassword : System.Security.SecureString

Domain         : mydomain

If I need only the password, I simply retrieve the Password property as shown here.

PS C:\> $credential.GetNetworkCredential().password

SomeUsersPassword

By the way, I can also get the password length here. This is because all string objects contain a Length property. This is shown here.

PS C:\> $credential.GetNetworkCredential().password.length

17

AD, that is all there is to using the NetworkCredential object. Join me tomorrow when I will talk about more cool Windows PowerShell stuff.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • "This latest representation is a string, and therefore there are no more options available for decrypting the password—at  least, none that are very direct or easy to use."

    You can decrypt the Get-Credential provided password ($credential.Password) using:

    $PlainTextPassword= [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR( (ConvertTo-SecureString $credential.Password) ))

  • This came as a chock to me!

    So using the Get-Crendentials command in a script is a security issue?

  • $credential = Get-Credential

    $credential.GetNetworkCredential().password

    Those above 2 lines seem simpler. But nice to know another way. Thanks Michel

  • @Michel de Rooij Thank you for sharing this code. I have seen it several times, and personally I find it a bit confusing. Therefore my statement of 'none that are very direct or easy to use." But, this is great because you show how to do this without using the power of PowerShell. Thank you for sharing.

  • @Kenny This is the reason I share this information, is that I want people to know what is going on. This is, in my mind, not a security issue because I know the password before I store it in a credential object. Therefore, that I am able to decrypt my own password that I just typed in, does not seem like a security issue. But yes, some people are shocked that this is directly accessible. The main point here, is that it is very easy to use Get-Credential to solicit credentials, and then you can get the plain text required for use with things like FTP -- which by their very nature are plain text and therefore insecure. All this is by design, and is not therefore necessarily a security issue.

  • @Ed

    Good point, Thanks Ed!

  • This was an amazing answer to a question that has been bothering me for about 3 months now.  Excelent explaination of how this all works.


  • All files including videos, photos and documents on your computer are encrypted.

    Encryption was produced using a unique public key generated for this computer. To decrypt files, you need to obtain the private key.

    The single copy of the private key, which will allow you to decrypt the files, located on a secret server on the Internet; the server will destroy the key after a time specified in this window. After that, nobody and never will be able to restore files.

    In order to decrypt the files, open site 4sfxctgp53imlvzk.onion.to/index.php and follow the instructions.

    If 4sfxctgp53imlvzk.onion.to/index.php is not opening, please follow the steps below:

    1. You must download and install this browser http://www.torproject.org/projects/torbrowser.html.en
    2. After installation, run the browser and enter the address: 4sfxctgp53imlvzk.onion/index.php
    3. Follow the instructions on the web-site. We remind you that the sooner you do, the more chances are left to recover the files.

    IMPORTANT INFORMATION:

    Your Personal CODE: 00000002-F8688D7B
    anirudhdigitalstudio@hotmail.com

  • pkz hepl me

    how to decript this string

    110,101,121,99,121,112,108,54,66,57,55,53,

  • @Amkit Amrutiya
    This isn't encrypted, it's just the ASCII codes for each char
    Try the following:
    "110,101,121,99,121,112,108,54,66,57,55,53".Split(",") | ForEach {[char][Int]$_}

    @Mod, could you please remove the very dodgy SPAM comment from anand Sonawane, anyone reading, I'd recommend against following the instructions! :)

  • I need to generate a password length report for a list of users from a .txt file. Please help. Thanks!