PowerShell Credentials and GetNetworkCredential()

Thu, Jan 25, 2007 2-minute read

Martin Zugec recently wrote about a security concern he has with PowerShell: Once you have a credential (i.e.: from Get-Credential,) it is quite easy to get the plain-text password by calling its GetNetworkCredential() method.

The reason we don’t make this more difficult is that you already have the credential. In security, something is either possible or impossible – “hard” is just another way of saying “possible.” We designed the GetNetworkCredential() method to give you the System.Net.NetworkCredential class required by many network classes in the .NET Framework, so we definitely want it to be possible.

In addition, the Get-Credential cmdlet lets you pass credentials to many other things than just .NET APIs. It can be used for SQL connections, Live IDs (in a hosted Exchange scenario,) as well as anything else that needs a username and password. The Get-Credential cmdlet helps make this as secure of an operation as possible.

You might point out that the password in a credential is a SecureString, so why is it so easy to get access to? To be clear, a SecureString doesn’t protect you from yourself (or anybody using your account,) it protects the credential from people that don’t have access to your user account (but have access to a crash dump, page file, or the like.)

The core point here is that if PowerShell has access to the password in any way, so do you. In fact, getting the plain text of a SecureString is already a one-liner:

[C:\temp]
PS:23 > $secureString = Read-Host -AsSecureString
***********

[C:\temp]
PS:24 > [Runtime.InteropServices.Marshal]::PtrToStringAuto(
    [Runtime.InteropServices.Marshal]::SecureStringToBSTR($secureString))
Hello World

Now, let’s say that you are concerned about calling GetNetworkCredential() while somebody watches over your shoulder, hence exposing your password. For this, you can modify the way we display all types of the System.Net.NetworkCredential class with this view definition:

(Edit: This is now in PowerShell by default)

<View>
    <Name>System.Net.NetworkCredential</Name>
    <ViewSelectedBy>
        <TypeName>System.Net.NetworkCredential</TypeName>
    </ViewSelectedBy>
    <TableControl>
        <TableHeaders>
            <TableColumnHeader>
                <Label>UserName</Label>
                <Width>50</Width>
            </TableColumnHeader>
            <TableColumnHeader>
                <Label>Domain</Label>
                <Width>50</Width>
            </TableColumnHeader>
        </TableHeaders>
        <TableRowEntries>
            <TableRowEntry>
                <TableColumnItems>
                    <TableColumnItem>
                        <PropertyName>UserName</PropertyName>
                    </TableColumnItem>
                    <TableColumnItem>
                        <PropertyName>Domain</PropertyName>
                    </TableColumnItem>
                </TableColumnItems>
            </TableRowEntry>
            </TableRowEntries>
    </TableControl>
</View>        

For more information about how to make custom formatting files, these posts are a useful resource:

http://www.leeholmes.com/blog/AddFileDescriptionsToYourDirectoryListingsDESCRIPTIONInMonad.aspx
http://www.leeholmes.com/blog/DESCRIPTIONSupportInMonadPart2.aspx
http://www.leeholmes.com/blog/DESCRIPTIONSupportInMonadPart3.aspx

And, in action:

[C:\temp]
PS:4 > $cred = Get-Credential

cmdlet Get-Credential at command pipeline position 1
Supply values for the following parameters:
Credential

[C:\temp]
PS:6 > $cred.GetNetworkCredential()

UserName                                           Domain
--------                                           ------
leeholm                                            CONTOSO