Converta uma string segura em texto simples

87

Estou trabalhando no PowerShell e tenho um código que converte com êxito uma senha inserida pelo usuário em texto simples:

$SecurePassword = Read-Host -AsSecureString  "Enter password" | convertfrom-securestring | out-file C:\Users\tmarsh\Documents\securePassword.txt

Tentei várias maneiras de convertê-lo de volta, mas nenhuma delas parece funcionar corretamente. Mais recentemente, tentei o seguinte:

$PlainPassword = Get-Content C:\Users\tmarsh\Documents\securePassword.txt

#convert the SecureString object to plain text using PtrToString and SecureStringToBSTR
$BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($PlainPassword)
$PlainPassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)
[Runtime.InteropServices.Marshal]::ZeroFreeBSTR($BSTR) #this is an important step to keep things secure

Isso também me dá um erro.

Cannot convert argument "s", with value: "01000000d08c9ddf0115d1118c7a00c04fc297eb0100000026a5b6067d53fd43801a9ef3f8ef9e43000000000200000000000366000
0c0000000100000008118fdea02bfb57d0dda41f9748a05f10000000004800000a000000010000000c50f5093f3b87fbf9ee57cbd17267e0a10000000833d1d712cef01497872a3457bc8
bc271400000038c731cb8c47219399e4265515e9569438d8e8ed", for "SecureStringToBSTR" to type "System.Security.SecureString": "Cannot convert the "01000000
d08c9ddf0115d1118c7a00c04fc297eb0100000026a5b6067d53fd43801a9ef3f8ef9e430000000002000000000003660000c0000000100000008118fdea02bfb57d0dda41f9748a05f10
000000004800000a000000010000000c50f5093f3b87fbf9ee57cbd17267e0a10000000833d1d712cef01497872a3457bc8bc271400000038c731cb8c47219399e4265515e9569438d8e8
ed" value of type "System.String" to type "System.Security.SecureString"."
At C:\Users\tmarsh\Documents\Scripts\Local Admin Script\PlainTextConverter1.ps1:14 char:1
+ $BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($PlainPassw ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodException
    + FullyQualifiedErrorId : MethodArgumentConversionInvalidCastArgument

Cannot find an overload for "PtrToStringAuto" and the argument count: "1".
At C:\Users\tmarsh\Documents\Scripts\Local Admin Script\PlainTextConverter1.ps1:15 char:1
+ $PlainPassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodException
    + FullyQualifiedErrorId : MethodCountCouldNotFindBest

Cannot convert argument "s", with value: "", for "ZeroFreeBSTR" to type "System.IntPtr": "Cannot convert null to type "System.IntPtr"."
At C:\Users\tmarsh\Documents\Scripts\Local Admin Script\PlainTextConverter1.ps1:16 char:1
+ [Runtime.InteropServices.Marshal]::ZeroFreeBSTR($BSTR) #this is an important ste ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodException
    + FullyQualifiedErrorId : MethodArgumentConversionInvalidCastArgument

Password is:  01000000d08c9ddf0115d1118c7a00c04fc297eb0100000026a5b6067d53fd43801a9ef3f8ef9e430000000002000000000003660000c0000000100000008118fdea02bfb57d0dda41f97
48a05f10000000004800000a000000010000000c50f5093f3b87fbf9ee57cbd17267e0a10000000833d1d712cef01497872a3457bc8bc271400000038c731cb8c47219399e4265515e9569
438d8e8ed

Alguém conhece uma maneira que funcione para isso?

Tmarsh
fonte

Respostas:

115

Você está perto, mas o parâmetro que você passa SecureStringToBSTRdeve ser a SecureString. Você parece estar passando o resultado de ConvertFrom-SecureString, que é uma string padrão criptografada. Portanto, ligue ConvertTo-SecureStringantes de passar para SecureStringToBSTR.

$SecurePassword = ConvertTo-SecureString $PlainPassword -AsPlainText -Force
$BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecurePassword)
$UnsecurePassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)
MatthewG
fonte
4
Estou feliz que funcione. Tenha cuidado com sua string, agora, ela é uma variável de string insegura contendo provavelmente algo importante como uma senha - ela não é mais segura em sua memória de processo, etc.
MatthewG
19
De acordo com a documentação Marshal.SecureStringToBSTR : Como esse método aloca a memória não gerenciada necessária para uma string, sempre libere o BSTR quando terminar, chamando o método ZeroFreeBSTR . Então, você tem que executar o seguinte no final: [Runtime.InteropServices.Marshal]::ZeroFreeBSTR($BSTR).
Rosberg Linhares
@RosbergLinhares - Já que estamos (presumivelmente) focados no PowerShell, há algum motivo para você não poder simplesmente $BSTR = $null?
Orangutech
3
@Orangutech Você não pode apenas definir a variável como $null, porque aqui estamos lidando com objetos não gerenciados. Você não receberá um erro imediatamente, mas acho que poderá ter problemas com o passar do tempo.
Rosberg Linhares
1
Além do vazamento de memória resultante da falta de chamada para ZeroFreeBSTR(), conforme declarado, o uso de PtrToStringAuto()sempre foi conceitualmente falho e - agora que o PowerShell é multiplataforma - falha em plataformas do tipo Unix. Sempre deveria ter sido PtrToStringBSTR() - veja esta resposta .
mklement0
81

Você também pode usar PSCredential.GetNetworkCredential ():

$SecurePassword = Get-Content C:\Users\tmarsh\Documents\securePassword.txt | ConvertTo-SecureString
$UnsecurePassword = (New-Object PSCredential "user",$SecurePassword).GetNetworkCredential().Password
Nicolas Melay
fonte
Testei os dois métodos e ainda estão corretos.
Maximilian Burszley
10
Votei esta solução porque é mais Powershelly.
Jim
1
Use System.Management.Automation.PSCredentialem versões mais antigas do PS quando o nome do tipo abreviado não for reconhecido.
março
1
Shorter:[PSCredential]::new(0, $SecurePassword).GetNetworkCredential().Password
majkinetor
Shorter:[System.Net.NetworkCredential]::new("", $SecurePassword).Password
K. Frank
36

A maneira mais fácil de convertê-lo de volta no PowerShell

[System.Net.NetworkCredential]::new("", $SecurePassword).Password
Vladimir Zelenov
fonte
1
Na verdade, não há necessidade de passar pelo PSCredential.
Nicolas Melay
Eu gosto dessa abordagem. Para sua informação, para viciados em compatibilidade, essa sobrecarga de construtor SecureStringfoi introduzida no .Net Framework 4.0. No PowerShell v2 eu tentei, (New-Object -TypeName System.Net.NetworkCredential -ArgumentList "u",$SecureString).Passwordmas infelizmente o SecureStringé silenciosamente convertido em um String. A chamada parece ter sucesso, mas a Passwordpropriedade é o valor literal "System.Security.SecureString". Seja cuidadoso.
John Rees,
17

No PS 7, você pode usar ConvertFrom-SecureStringe -AsPlainText:

 $UnsecurePassword = ConvertFrom-SecureString -SecureString $SecurePassword -AsPlainText

https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.security/ConvertFrom-SecureString?view=powershell-7#parameters

ConvertFrom-SecureString
           [-SecureString] <SecureString>
           [-AsPlainText]
           [<CommonParameters>]
Macke
fonte
3
Isso estava me deixando louca. Eu estava tentando usar essa sintaxe na v5 sem sucesso.
Tony