Convierta una cadena segura en texto sin formato

87

Estoy trabajando en PowerShell y tengo un código que convierte correctamente una contraseña ingresada por el usuario en texto sin formato:

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

He probado varias formas de convertirlo de nuevo, pero ninguna parece funcionar correctamente. Más recientemente, probé con lo siguiente:

$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

Esto también me da un error.

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

¿Alguien sabe de una forma que funcione para esto?

tmarsh
fuente

Respuestas:

115

Estás cerca, pero el parámetro al que pasas SecureStringToBSTRdebe ser un SecureString. Parece que está pasando el resultado de ConvertFrom-SecureString, que es una cadena estándar cifrada. Así que invoca ConvertTo-SecureStringesto antes de pasar a SecureStringToBSTR.

$SecurePassword = ConvertTo-SecureString $PlainPassword -AsPlainText -Force
$BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecurePassword)
$UnsecurePassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)
MatthewG
fuente
4
Me alegro de que funcione. Tenga cuidado con su cadena, ahora, es una variable de cadena no segura que contiene presumiblemente algo importante como una contraseña; ya no está segura en su memoria de proceso, etc.
MatthewG
19
De acuerdo con la documentación Marshal.SecureStringToBSTR : debido a que este método asigna la memoria no administrada requerida para una cadena, siempre libere el BSTR cuando termine llamando al método ZeroFreeBSTR . Por lo tanto, usted tiene que ejecutar el siguiente en el final: [Runtime.InteropServices.Marshal]::ZeroFreeBSTR($BSTR).
Rosberg Linhares
@RosbergLinhares - Ya que estamos (presumiblemente) enfocados en powershell, ¿hay alguna razón por la que no puedas simplemente $BSTR = $null?
Orangutech
3
@Orangutech No solo puede establecer la variable en $null, porque aquí estamos tratando con objetos no administrados. No obtendrá un error de inmediato, pero creo que puede tener problemas a medida que pasa el tiempo.
Rosberg Linhares
1
Aparte de la pérdida de memoria resultante de la llamada faltante a ZeroFreeBSTR(), como se indicó, el uso de PtrToStringAuto()siempre fue conceptualmente defectuoso y, ahora que PowerShell es multiplataforma, falla en plataformas similares a Unix. Siempre debería haber sido PtrToStringBSTR() - vea esta respuesta .
mklement0
81

También puede utilizar PSCredential.GetNetworkCredential ():

$SecurePassword = Get-Content C:\Users\tmarsh\Documents\securePassword.txt | ConvertTo-SecureString
$UnsecurePassword = (New-Object PSCredential "user",$SecurePassword).GetNetworkCredential().Password
Nicolas Melay
fuente
He probado ambos métodos y ambos siguen siendo correctos.
Maximilian Burszley
10
Votó a favor esta solución porque es más Powershelly.
Jim
1
Úselo System.Management.Automation.PSCredentialen versiones anteriores de PS cuando no se reconozca el nombre de tipo corto.
marsze
1
Más corto:[PSCredential]::new(0, $SecurePassword).GetNetworkCredential().Password
majkinetor
Más corto:[System.Net.NetworkCredential]::new("", $SecurePassword).Password
K. Frank
36

La forma más sencilla de volver a convertirlo en PowerShell

[System.Net.NetworkCredential]::new("", $SecurePassword).Password
Vladimir Zelenov
fuente
1
De hecho, no es necesario pasar por PSCredential.
Nicolas Melay
Me gusta este enfoque. Para su información, para los adictos a la compatibilidad, esta sobrecarga del constructor SecureStringse introdujo en .Net Framework 4.0. En PowerShell v2 lo intenté, (New-Object -TypeName System.Net.NetworkCredential -ArgumentList "u",$SecureString).Passwordpero desafortunadamente SecureStringse convierte silenciosamente a String. La llamada parece tener éxito, pero la Passwordpropiedad es entonces el valor literal "System.Security.SecureString". Ten cuidado.
John Rees