Perlindungan kata sandi dan enkripsi dalam skrip PowerShell

Administrator sering menulis kata sandi langsung di tubuh skrip PoSh ketika menulis skrip otomatisasi di PowerShell. Seperti yang Anda tahu, ini sangat tidak aman ketika digunakan di lingkungan yang produktif kata sandi dapat dilihat dalam bentuk yang jelas oleh pengguna server atau administrator lainnya. Oleh karena itu, disarankan untuk menggunakan metode yang lebih aman untuk menggunakan kata sandi dalam skrip PowerShell, atau untuk mengenkripsi kata sandi jika Anda tidak dapat menggunakan input interaktif.

Aman untuk meminta pengguna memasukkan kata sandi dalam skrip secara interaktif menggunakan cmdlet Dapatkan kredensial. Misalnya, kami meminta nama pengguna dan kata sandi dan menyimpannya di objek jenis Pscredential:

$ Cred = Dapatkan-Credential

Saat mengakses properti variabel, Anda bisa mengetahui nama pengguna yang ditentukan.

$ Cred.Username

Tetapi ketika Anda mencoba untuk menampilkan kata sandi, teks System.Security.SecureString akan dikembalikan, karena kata sandi sekarang disimpan sebagai SecureString.

$ Cred.Password

Objek PSCredential yang kami simpan dalam variabel $ Cred sekarang dapat digunakan dalam cmdlet yang mendukung jenis objek ini.

Parameter $ Cred.Username dan $ Cred.Password dapat digunakan dalam cmdlet yang tidak mendukung objek PSCredential, tetapi memerlukan nama pengguna dan kata sandi yang terpisah.

Anda juga dapat menggunakan cmdlet Read-Host dengan atribut AsSecureString untuk meminta kata sandi pengguna:
$ pass = Baca-Host "Masukkan Kata Sandi" -AsSecureString

Dalam hal ini, Anda juga tidak akan dapat melihat isi dari variabel $ pass, tempat kata sandi disimpan.

Dalam metode di atas menggunakan kata sandi dalam skrip PowerShell, diasumsikan bahwa kata sandi dimasukkan secara interaktif ketika skrip dieksekusi. Tetapi metode ini tidak cocok untuk berbagai skenario yang berjalan secara otomatis atau melalui penjadwal.

Dalam hal ini, lebih mudah untuk mengenkripsi data akun (nama dan kata sandi) dan menyimpannya dalam bentuk terenkripsi ke file teks pada disk atau digunakan langsung dalam skrip.

Jadi, gunakan cmdlet ConvertFrom-SecureString Anda dapat mengonversi kata sandi dari format SecureString ke string terenkripsi (enkripsi dilakukan menggunakan API Perlindungan Data Windows - DPAPI). Anda dapat menampilkan kata sandi terenkripsi di layar atau menyimpannya ke file:

$ Cred.Password | ConvertFrom-SecureString | Set-Konten c: \ ps \ passfile.txt

Untuk menggunakan kata sandi terenkripsi dari file, Anda perlu melakukan konversi terbalik ke format Securestring menggunakan cmdlet ConvertTo-SecureString:

$ username = "corp \ administrator"
$ pass = Dapatkan-Konten c: \ ps \ passfile.txt | ConvertTo-SecureString
$ creds = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $ username, $ pass

Jadi, dalam variabel $ creds, kami mendapat objek PSCredential dengan kredensial pengguna.

Namun, jika Anda mencoba menyalin file passfile.txt ke komputer lain atau menggunakannya di bawah pengguna yang berbeda (bukan yang digunakan untuk membuat kata sandi), Anda akan melihat bahwa variabel $ creds.password kosong dan tidak mengandung kata sandi. Faktanya adalah enkripsi menggunakan DPAPI dilakukan menggunakan kunci yang disimpan dalam profil pengguna. Tanpa kunci ini di komputer lain, Anda tidak dapat mendekripsi file dengan kata sandi.
ConvertTo-SecureString: Kunci tidak dapat digunakan di negara yang ditentukan.
"Tidak dapat memproses argumen karena nilai argumen kata sandi adalah NULL.
Tentukan nilai non-NULL untuk argumen kata sandi. "

Jadi, jika skrip akan dijalankan di bawah akun (layanan) yang berbeda atau di komputer lain, Anda harus menggunakan mekanisme enkripsi berbeda yang unik untuk DPAPI. Kunci enkripsi asing dapat ditentukan menggunakan parameter -Kunci atau -SecureKey.

Misalnya, Anda bisa menggunakan PowerShell untuk menghasilkan kunci AES 256-bit yang bisa Anda gunakan untuk mendekripsi file. Simpan kunci ke file teks password_aes.key.

$ AESKey = Byte Objek-Baru [] 32
[Security.Cryptography.RNGCryptoServiceProvider] :: Create (). GetBytes ($ AESKey)
$ AESKey | keluar file C: \ ps \ password_aes.key

Sekarang Anda dapat menyimpan kata sandi ke file menggunakan kunci ini:

$ Cred.Password | ConvertFrom-SecureString -Key (dapatkan-konten C: \ ps \ password_aes.key) | Set-Konten c: \ ps \ passfile.txt

Jangan lupa bahwa jika Anda menentukan akun domain dalam skrip Powershell dan memiliki kebijakan perubahan kata sandi reguler, Anda harus memperbarui file ini setiap kali kata sandi diubah (Anda dapat membuat kebijakan kata sandi terpisah untuk akun tertentu menggunakan beberapa kebijakan kata sandi FGPP.

Jadi, kami mendapat dua file: file dengan kata sandi terenkripsi (passfile.txt) dan file dengan kunci enkripsi (password_aes.key).

Anda dapat mentransfernya ke komputer lain dan mencoba mendapatkan kata sandi dari file dari PowerShell (Anda dapat menempatkan file kunci di direktori jaringan)

$ pass = Dapatkan-Konten c: \ ps \ passfile.txt | ConvertTo-SecureString -Key (dapatkan-konten \\ Server1 \ Bagikan \ password_aes.key)
$ pass

Jika Anda tidak ingin repot dengan file terpisah dengan kunci AES, Anda dapat menjahit kunci enkripsi langsung ke skrip. Dalam hal ini, alih-alih kunci dalam kedua kasus, Anda harus menggunakan

[Byte []] $ key = (1 ... 16)
$ Cred.Password | ConvertFrom-SecureString -Key $ key | Set-Konten c: \ ps \ passfile.txt

Dan untuk dekripsi:

[Byte []] $ key = (1 ... 16)
$ pass = Dapatkan-Konten c: \ ps \ passfile.txt | ConvertTo-SecureString -Key $ key

Seperti yang Anda lihat, kata sandi tidak kosong, yang berarti telah berhasil didekripsi dan dapat digunakan di komputer lain.

Kiat. Penting untuk membatasi akses ke file dengan kunci AES sehingga hanya pengguna atau akun yang menjalankan skrip yang memiliki akses ke file tersebut. Periksa izin NTFS dengan hati-hati pada file password_aes.key saat menempatkannya di direktori jaringan.

Dan akhirnya, saat yang paling menyedihkan. Kata sandi dari objek PSCredential di clear ditarik sangat sederhana:

$ Cred.GetNetworkCredential (). Kata sandi

Anda dapat mengekstrak kata sandi dalam bentuk teks dari SecureString:

$ BSTR = [System.Runtime.InteropServices.Marshal] :: SecureStringToBSTR ($ pass)
[System.Runtime.InteropServices.Marshal] :: PtrToStringAuto ($ BSTR)

Seperti yang Anda pahami, itu sebabnya tidak diinginkan untuk menyimpan kata sandi untuk akun istimewa, seperti Admin Domain, di mana pun kecuali DC.

Kiat. Untuk melindungi catatan administratif dari penggalian kata sandi dari memori menggunakan utilitas seperti Mimikatz, Anda perlu menggunakan langkah-langkah komprehensif, termasuk rencana organisasi.