18 enero, 2019

Cifrar passwords con PowerShell


Con PowerShell podemos generar passwords simétricas y guardarlas cifradas en ficheros.


Esto lo utilizo para cifrar mis copias de seguridad. Hice un repositorio donde hago referencia al código PowerShell utilizado para realizar estas copias de seguridad.

Uno de los pasos en la realización de estas copias era establecer unas passwords y guardarlas en ficheros de forma cifrada. Dejo la referencia al repositorio: https://github.com/adrianlois/Automatizar-Backups-FTP-PowerShell

Crear passwords cifradas con PowerShell para usar desde el mismo usuario

Cuando establecemos una password en Powershell y la volcamos en un fichero, el fichero que contiene la password cifrada solo sería se podría usar desde el usuario que la estableció.

Para establecer una password con Powershell y volcarla a un fichero de forma cifrada convirtiendo la cadena de texto plano establecida a una cadena cifrada segura (ConvertFrom-SecureString).
Read-Host -AsSecureString "Password fichero" | ConvertFrom-SecureString | Set-Content "C:\Passwords\fichero-passwd-cifrada"
Llamar al fichero con la password cifrada almacenada en un script Powershell, convertir la cadena cifrada en texto plano (ConvertTo-SecureString).
Get-Content "C:\Passwords\fichero-passwd-cifrada" | ConvertTo-SecureString
Repositorio donde se muestra este método y un video demo PoC.
https://github.com/adrianlois/Automatizar-Backups-FTP-PowerShell/tree/master/backup-v2.0


Crear passwords cifradas con PowerShell generando un keyfile (portable) para usar desde cualquier usuario o máquina

Otra forma de cifrar la passwords en Powershell sería generar un keyfile (fichero llave único para descifrarlas). De ese modo teniendo el keyfile y referenciándolo en el script de Powershell se pueden cifrar con el keyfile y posteriormente descifrar las password establecida volcada en el fichero.

La ventaja respecto al método anterior, es que se pueden descifrar los ficheros que almacenan las passwords cifradas desde cualquier usuario de la misma máquina o cualquier usuario de otra máquina distina. Pudiendo así transportar los ficheros de passwords y keyfile para ser utilizados por otros usuarios o máquinas.

Generar el keyfile y establecer la password para volvarla a un fichero asociándola al keyfile (Read-Host -AsSecureString , ConvertFrom-SecureString -key).

$CifradoKeyFile = New-Object Byte[] 32
[Security.Cryptography.RNGCryptoServiceProvider]::Create().GetBytes($CifradoKeyFile)
$CifradoKeyFile | out-file "C:\Passwords\CifradoKeyFile.key"

Read-Host -AsSecureString "Password fichero" | ConvertFrom-SecureString -key (Get-Content "C:\Passwords\CifradoKeyFile.key") | set-content "C:\Passwords\fichero-passwd-cifrada"
Concatenar el keyfile para descifrar el fichero password cifrado (ConvertTo-SecureString -Key).
Get-Content "C:\Passwords\fichero-passwd-cifrada" | ConvertTo-SecureString -Key (Get-Content "C:\Passwords\CifradoKeyFile.key")
Repositorio donde se muestra este método con generación de keyfile y un video demo PoC.
https://github.com/adrianlois/Automatizar-Backups-FTP-PowerShell/tree/master/backup-v2.1


Liberar o eliminar las passwords almacenadas en un puntero de memoria

Cuando se crea una cadena tipo SecureString esta es almacenada en un espacio de memoria a parte, donde el recolector de basura de .NET de Powershell (CG - Garbage Collector) no puede acceder por lo que es recomendable vaciar este espacio de memoria que se asigna a un puntero.

ZeroFreeCoTaskMemUnicode: Libera un puntero a una cadena no administrada que se ha asignado con el método.

En el siguiente ejemplo se muestra como se crea una cadena segura y se almacenada en un variable. Se convierte a texto a plano gracias a que conocemos el indicador del puntero en memoria y finalmente liberamos ese puntero. Con esto evitará el almacenamiento en memoria de la credencial almacenada. 
PS C:\> $sec = Read-Host -AsSecureString
*******
PS C:\> $ptr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($sec)
PS C:\> $ptr
114228428
PS C:\> $plaintext = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($ptr)
PS C:\> $plaintext
Abc123.
PS C:\> [System.Runtime.InteropServices.Marshal]::ZeroFreeCoTaskMemUnicode($ptr)
Saludos!

Autor: Adrián Lois

No hay comentarios:

Publicar un comentario