Przekonwertuj bezpieczny ciąg na zwykły tekst

87

Pracuję w PowerShell i mam kod, który pomyślnie konwertuje hasło wprowadzone przez użytkownika na zwykły tekst:

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

Wypróbowałem kilka sposobów, aby go przywrócić, ale żaden z nich nie wydaje się działać poprawnie. Ostatnio próbowałem z następującymi rozwiązaniami:

$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

To również daje mi błąd.

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

Czy ktoś zna sposób, który to zadziała?

tmarsh
źródło

Odpowiedzi:

115

Jesteś blisko, ale przekazywany parametr SecureStringToBSTRmusi mieć wartość SecureString. Wygląda na to, że przekazujesz wynik ConvertFrom-SecureString, który jest zaszyfrowanym standardowym ciągiem. Więc zadzwoń ConvertTo-SecureStringdo tego przed przejściem do SecureStringToBSTR.

$SecurePassword = ConvertTo-SecureString $PlainPassword -AsPlainText -Force
$BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecurePassword)
$UnsecurePassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)
MatthewG
źródło
4
Cieszę się, że to działa. Uważaj na swój ciąg, teraz jest to niezabezpieczona zmienna łańcuchowa zawierająca prawdopodobnie coś ważnego, na przykład hasło - nie jest już bezpieczna w pamięci procesu itp.
MatthewG
19
Zgodnie z dokumentacją Marshal.SecureStringToBSTR : Ponieważ ta metoda przydziela niezarządzaną pamięć wymaganą dla ciągu, zawsze zwalniaj BSTR po zakończeniu, wywołując metodę ZeroFreeBSTR . Tak, trzeba wykonać następujące czynności w celu: [Runtime.InteropServices.Marshal]::ZeroFreeBSTR($BSTR).
Rosberg Linhares
@RosbergLinhares - Skoro (prawdopodobnie) koncentrujemy się na PowerShell, czy jest jakiś powód, dla którego nie mogłeś po prostu $BSTR = $null?
Orangutech
3
@Orangutech Nie możesz ustawić zmiennej tylko na $null, bo tutaj mamy do czynienia z niezarządzanymi obiektami. Nie otrzymasz od razu błędu, ale myślę, że z biegiem czasu możesz mieć problemy.
Rosberg Linhares
1
Oprócz wycieku pamięci wynikającego z brakującego wywołania ZeroFreeBSTR(), jak wspomniano, użycie programu PtrToStringAuto()było zawsze koncepcyjnie wadliwe, a - teraz, gdy PowerShell jest wieloplatformowy - zawodzi na platformach typu Unix. Powinien był zawsze PtrToStringBSTR() - zobacz tę odpowiedź .
mklement0
81

Możesz także użyć PSCredential.GetNetworkCredential ():

$SecurePassword = Get-Content C:\Users\tmarsh\Documents\securePassword.txt | ConvertTo-SecureString
$UnsecurePassword = (New-Object PSCredential "user",$SecurePassword).GetNetworkCredential().Password
Nicolas Melay
źródło
Przetestowałem obie metody i obie są nadal poprawne.
Maximilian Burszley
10
Głosowałem za tym rozwiązaniem, ponieważ jest bardziej Powershelly.
Jim
1
Użyj System.Management.Automation.PSCredentialw starszych wersjach PS, gdy krótka nazwa typu nie jest rozpoznawana.
marsze
1
Krótszy:[PSCredential]::new(0, $SecurePassword).GetNetworkCredential().Password
majkinetor
Krótszy:[System.Net.NetworkCredential]::new("", $SecurePassword).Password
K. Frank
36

Najłatwiejszy sposób na przywrócenie go w PowerShell

[System.Net.NetworkCredential]::new("", $SecurePassword).Password
Vladimir Zelenov
źródło
1
Rzeczywiście, nie ma potrzeby przechodzenia przez PSCredential.
Nicolas Melay
Podoba mi się to podejście. FYI dla maniaków kompatybilności, to przeciążenie konstruktora SecureStringzostało wprowadzone w .Net Framework 4.0. Próbowałem na PowerShell v2, (New-Object -TypeName System.Net.NetworkCredential -ArgumentList "u",$SecureString).Passwordale niestety SecureStringjest po cichu konwertowany na String. Wydaje się, że wywołanie powiedzie się, ale Passwordwłaściwość jest wówczas wartością literalną „System.Security.SecureString”. Bądź ostrożny.
John Rees
17

W PS 7 możesz używać ConvertFrom-SecureStringi -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
źródło
3
To doprowadzało mnie do szału. Próbowałem użyć tej składni w wersji 5 bezskutecznie.
Tony