Адміністратори часто при написанні сценаріїв автоматизації на PowerShell зберігають паролі безпосередньо в тілі PoSh скрипта. Як ви розумієте, це вкрай небезпечно при використанні в продуктивної середовищі, тому що пароль у відкритому вигляді можуть побачити інші користувачі сервера або адміністратори. Тому бажано використовувати більш безпечний метод використання паролів в скриптах PowerShell, або шифрувати паролі, якщо не можна користуватися інтерактивним введенням.
Безпечно можна запросити від користувача ввести пароль в скрипті інтерактивно за допомогою командлета Get-Credential. Наприклад, запитаємо ім'я і пароль користувача і збережемо його в об'єкті типу PSCredential:
$ Cred = Get-Credential
При зверненні до властивостей змінної можна дізнатися ім'я ползователей, яка була вказана.
$ Cred.Username
Але при спробі вивести пароль, повернеться текст System.Security.SecureString, тому що пароль тепер зберігається у вигляді SecureString.
$ Cred.Password
Об'єкт PSCredential, який ми зберегли в змінній $ Cred тепер можна використовуватися в Командлети, які підтримують даний вид об'єктів.
Параметри $ Cred.Username і $ Cred.Password можна використовувати в Командлети, які не підтримують об'єкти PSCredential, але вимагають окремого введення імені і пароля користувача.
Також для запиту пароля користувача можна використовувати команлет Read-Host з атрибутом AsSecureString:$ Pass = Read-Host "Введіть пароль" -AsSecureString
В даному випадку, ви також не зможете побачити вміст змінної $ pass, в якій зберігається пароль.
У розглянутих вище способах використання пароля в скриптах PowerShell передбачався інтерактивний введення пароля при виконанні скрипта. Але цей спосіб не підійде для різних сценаріїв, що запускаються автоматично або через планувальник.
В цьому випадку зручніше зашифрувати дані облікового запису (ім'я та пароль) і зберегти їх в зашифрованому вигляді в текстовий файл на диску або використовувати безпосередньо в скрипті.
Отже, за допомогою комадлета ConvertFrom-SecureString можна перетворити пароль з формату SecureString в шифровану рядок (шифрування виконується за допомогою Windows Data Protection API - DPAPI). Ви можете вивести шифрований пароль на екран або зберегти в файл:
$ Cred.Password | ConvertFrom-SecureString | Set-Content c: \ ps \ passfile.txt
Щоб використовувати зашифрований пароль з файлу потрібно виконати зворотне перетворення в формат Securestring за допомогою командлета ConvertTo-SecureString:
$ Username = "corp \ administrator"
$ Pass = Get-Content c: \ ps \ passfile.txt | ConvertTo-SecureString
$ Creds = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $ username, $ pass
Таким чином в змінній $ creds ми отримали об'єкт PSCredential з обліковими даними користувача.
Однак, якщо спробувати скопіювати файл passfile.txt на інший комп'ютер або використовувати його під іншим користувачем (не тим, під яким створювався пароль), ви побачите, що змінна $ creds.password порожня і не містить пароля. Справа в тому, що шифруванням за допомогою DPAPI виконується за допомогою ключів, що зберігаються в профілі користувача. Без цих ключів на іншому комп'ютері ви не зможете розшифрувати файл з паролем.ConvertTo-SecureString: Ключ не може бути використаний в зазначеному стані.
"Неможливо обробити аргумент, так як значенням аргументу" password "є NULL.
Вкажіть для аргументу "password" значення, відмінне від NULL. "
Таким чином, якщо скрипт буде запускатися під іншим (сервісним) аккаунтом або на іншому комп'ютері, необхідно використовувати інший механізм шифрування, отдічний від DPAPI. Зовнішній ключ шифрування можна вказати за допомогою параметрів -Key або -SecureKey.
Наприклад, ви можете за допомогою PowerShell згенерувати 256 бітний AES ключ, який можна використовувати для розшифровки файлу. Збережемо ключ в текстовий файл password_aes.key.
$ AESKey = New-Object Byte [] 32
[Security.Cryptography.RNGCryptoServiceProvider] :: Create (). GetBytes ($ AESKey)
$ AESKey | out-file C: \ ps \ password_aes.key
Тепер можна зберегти пароль в файл за допомогою даного ключа:
$ Cred.Password | ConvertFrom-SecureString -Key (get-content C: \ ps \ password_aes.key) | Set-Content c: \ ps \ passfile.txt
Таким чином у нас вийшло два файли: файл із зашифрованим паролем (passfile.txt) і файл з ключем шифрування (password_aes.key).
Їх можна перенести на інший комп'ютер і спробувати з PowerShell отримати пароль з файлу (можна розмістити файл ключа в мережевому каталозі)
$ Pass = Get-Content c: \ ps \ passfile.txt | ConvertTo-SecureString -Key (get-content \\ Server1 \ Share \ password_aes.key)
$ pass
Якщо не хочеться морочитися з окремим файлом з AES ключем, можна зашити ключ шифрування прямо в скрипт. У цьому випадку замість ключа в обох випадках потрібно використовувати
[Byte []] $ key = (1 ... 16)
$ Cred.Password | ConvertFrom-SecureString -Key $ key | Set-Content c: \ ps \ passfile.txt
А для розшифровки:
[Byte []] $ key = (1 ... 16)
$ Pass = Get-Content c: \ ps \ passfile.txt | ConvertTo-SecureString -Key $ key
Як ви бачите пароль не порожній, значить він був успішно розшифрований і може бути використаний на інших комп'ютерах.
Порада. Необхідно обмежити доступ до файлу з AES ключем, щоб тільки користувач або аккаунт, під яким запускається скрипт мав до нього доступ. Уважно перевірте NTFS дозволу на файл password_aes.key при розміщенні його в мережевому каталозі.І наостанок, найсумніший момент. Пароль з об'єкта PSCredential у відкритому вигляді витягується дуже просто:
$ Cred.GetNetworkCredential (). Password
Можна витягти пароль в текстовому вигляді і з SecureString:
$ BSTR = [System.Runtime.InteropServices.Marshal] :: SecureStringToBSTR ($ pass)
[System.Runtime.InteropServices.Marshal] :: PtrToStringAuto ($ BSTR)
Як ви розумієте, саме тому небажано зберігати паролі привілейованих облікових записів, таких як Domain Admins де б то не було крім DC.
Порада. Для захисту адміністративних врахованих записів від добування паролів з пам'яті за допомогою утиліт подібних Mimikatz потрібно використовувати комплексні заходи, в тому числі організаційного плану.