Ochrona hasłem i szyfrowanie w skryptach PowerShell

Administratorzy często piszą hasła bezpośrednio w treści skryptu PoSh podczas pisania skryptów automatyzacji w PowerShell. Jak wiadomo, jest to wyjątkowo niebezpieczne, gdy jest używane w produktywnym środowisku, ponieważ hasło może być widoczne w czytelnej formie przez innych użytkowników serwera lub administratorów. Dlatego zaleca się stosowanie bezpieczniejszej metody używania haseł w skryptach PowerShell lub szyfrowanie haseł, jeśli nie można użyć interaktywnego wprowadzania.

Można bezpiecznie poprosić użytkownika o interaktywne wprowadzenie hasła w skrypcie za pomocą polecenia cmdlet Uzyskaj poświadczenie. Na przykład żądamy nazwy użytkownika i hasła i zapisujemy je w obiekcie typu Pscredential:

$ Cred = Get-Credential

Podczas uzyskiwania dostępu do właściwości zmiennej można znaleźć nazwę użytkownika, który został określony.

$ Cred.Username

Ale kiedy spróbujesz wyświetlić hasło, zostanie zwrócony tekst System.Security.SecureString, ponieważ hasło jest teraz przechowywane jako SecureString.

$ Cred.Password

Obiekt PSCredential, który zapisaliśmy w zmiennej $ Cred, może być teraz używany w poleceniach cmdlet obsługujących ten typ obiektu.

Parametry $ Cred.Username i $ Cred.Password mogą być używane w poleceniach cmdlet, które nie obsługują obiektów PSCredential, ale wymagają osobnej nazwy użytkownika i hasła.

Możesz również użyć polecenia cmdlet Read-Host z atrybutem AsSecureString, aby zażądać hasła użytkownika:
$ pass = Read-Host „Enter Password” -AsSecureString

W takim przypadku również nie będzie można zobaczyć zawartości zmiennej $ pass, w której przechowywane jest hasło.

W powyższych metodach używania hasła w skryptach PowerShell założono, że hasło zostało wprowadzone interaktywnie podczas wykonywania skryptu. Ale ta metoda nie jest odpowiednia dla różnych scenariuszy uruchamianych automatycznie lub za pomocą programu planującego.

W takim przypadku wygodniej jest zaszyfrować dane konta (nazwę i hasło) i zapisać je w postaci zaszyfrowanej w pliku tekstowym na dysku lub użyć bezpośrednio w skrypcie.

Tak więc za pomocą polecenia cmdlet ConvertFrom-SecureString Możesz przekonwertować hasło z formatu SecureString na zaszyfrowany ciąg (szyfrowanie odbywa się za pomocą interfejsu API ochrony danych systemu Windows - DPAPI). Możesz wyświetlić zaszyfrowane hasło na ekranie lub zapisać je w pliku:

$ Cred.Password | ConvertFrom-SecureString | Ustaw zawartość c: \ ps \ passfile.txt

Aby użyć zaszyfrowanego hasła z pliku, musisz wykonać odwrotną konwersję do formatu Securestring za pomocą polecenia cmdlet ConvertTo-SecureString:

$ username = "corp \ administrator"
$ pass = Get-Content c: \ ps \ passfile.txt | ConvertTo-SecureString
$ creds = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $ nazwa użytkownika, $ pass

Zatem w zmiennej $ creds otrzymaliśmy obiekt PSCredential z poświadczeniami użytkownika.

Jeśli jednak spróbujesz skopiować plik passfile.txt na inny komputer lub użyć go pod innym użytkownikiem (innym niż ten, na którym hasło zostało utworzone), zobaczysz, że zmienna $ creds.password jest pusta i nie zawiera hasła. Faktem jest, że szyfrowanie przy użyciu DPAPI odbywa się przy użyciu kluczy przechowywanych w profilu użytkownika. Bez tych kluczy na innym komputerze nie można odszyfrować pliku za pomocą hasła.
ConvertTo-SecureString: klucza nie można użyć w określonym stanie.
„Nie można przetworzyć argumentu, ponieważ wartość argumentu hasła to NULL.
Podaj wartość inną niż NULL dla argumentu hasła. ”

Dlatego jeśli skrypt będzie uruchamiany na innym koncie (usługowym) lub na innym komputerze, musisz użyć innego mechanizmu szyfrowania, który jest unikalny dla DPAPI. Obcy klucz szyfrowania można określić za pomocą parametrów -Klucz lub -SecureKey.

Na przykład można użyć programu PowerShell do wygenerowania 256-bitowego klucza AES, którego można użyć do odszyfrowania pliku. Zapisz klucz w pliku tekstowym password_aes.key.

$ AESKey = New-Object Byte [] 32
[Security.Cryptography.RNGCryptoServiceProvider] :: Create (). GetBytes ($ AESKey)
$ AESKey | plik wyjściowy C: \ ps \ hasło_aes.key

Teraz możesz zapisać hasło do pliku za pomocą tego klucza:

$ Cred.Password | ConvertFrom-SecureString -Key (get-content C: \ ps \ hasło_aes.key) | Ustaw zawartość c: \ ps \ passfile.txt

Nie zapominaj, że jeśli określisz konto domeny w skrypcie Powershell i masz na nim regularne zasady zmiany hasła, będziesz musiał aktualizować ten plik za każdym razem, gdy hasło zostanie zmienione (możesz utworzyć osobną politykę haseł dla niektórych kont przy użyciu wielu zasad haseł FGPP.

Mamy zatem dwa pliki: plik z zaszyfrowanym hasłem (passfile.txt) i plik z kluczem szyfrującym (hasło_aes.key).

Możesz przenieść je na inny komputer i spróbować uzyskać hasło z pliku z PowerShell (możesz umieścić plik klucza w katalogu sieciowym)

$ pass = Get-Content c: \ ps \ passfile.txt | ConvertTo-SecureString -Key (get-content \\ Server1 \ Share \ password_aes.key)
$ pass

Jeśli nie chcesz zawracać sobie głowy oddzielnym plikiem z kluczem AES, możesz wszyć klucz szyfrujący bezpośrednio w skrypcie. W takim przypadku zamiast klucza w obu przypadkach należy użyć

[Bajt []] $ klucz = (1 ... 16)
$ Cred.Password | ConvertFrom-SecureString -Key $ key | Ustaw zawartość c: \ ps \ passfile.txt

I do deszyfrowania:

[Bajt []] $ klucz = (1 ... 16)
$ pass = Get-Content c: \ ps \ passfile.txt | ConvertTo-SecureString -Key $ klucz

Jak widać, hasło nie jest puste, co oznacza, że ​​zostało pomyślnie odszyfrowane i może być używane na innych komputerach.

Wskazówka. Konieczne jest ograniczenie dostępu do pliku za pomocą klucza AES, aby dostęp do niego miał tylko użytkownik lub konto, na którym uruchamiany jest skrypt. Dokładnie sprawdź uprawnienia NTFS do pliku password_aes.key podczas umieszczania go w katalogu sieciowym.

I w końcu najsmutniejszy moment. Hasło z obiektu PSCredential w postaci zerowej jest wyciągane bardzo prosto:

$ Cred.GetNetworkCredential (). Hasło

Możesz wyodrębnić hasło w formie tekstowej z SecureString:

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

Jak rozumiesz, dlatego niepożądane jest zapisywanie haseł do kont uprzywilejowanych, takich jak Administratorzy domeny, gdziekolwiek poza DC.

Wskazówka Aby chronić rekordy administracyjne przed wyodrębnianiem haseł z pamięci za pomocą narzędzi takich jak Mimikatz, musisz zastosować kompleksowe środki, w tym plan organizacyjny.