In almost every training I give, a question pops up: "How can I have a normal user run elevated processes?" The easy answer to this is: "You can't, unless you hand over an Administrator password to them".
Encrypting Passwords - The Problem
The basic challenge with Windows systems is that they do not isolate read and execute rights. Execution rights always grant read rights, so for someone to launch an elevated process, they must know the secret. So in a lot of scenarios, Admins in their desperation hard-code passwords into their scripts.That of course is a security issue, and it is not a small one.
Even if you decide to encrypt the password, this won't get you a perfect world. You would still have to also submit the secret key that unencrypts the password.
Obfuscating Passwords
In most scenarios, what you really do is obfuscating passwords rather than encryting them. You want to store the password in a way that masks it as much as possible, so someone looking at your script would not discover that there really is an Admin password ready to abuse.
One pretty good approach is to encrypt a secure string with a secure key. When you do that, your script will only contain a byte array and a mangled password that you would not be able to easily reuse otherwise. Have a look:
$password = '76492d1116743f0423413b16050a5345MgB8AG8AdgBYAGQARABBAEcAdQBUAHcANABHAGMAZgA2ADMAYgBwAGkAZQBGAHcAPQA9AHwAZAA3AGYAMAA5ADkAZgBhAGQANQAwADAAMgAzAGYANQA5ADAAOQA1AGQAYgBjAGMAYwBjADcAOQAxADIAOQA5ADAAYwAxADIAMwBlADYAYgBlADYAYwAwADYAYQBiAGQAYwA3AGEAOAAwAGUANgA1ADUAOABmAGYANwAzADcAZAA='
$key = '107 133 121 32 174 13 87 189 153 38 212 235 34 140 224 247 248 153 60 194 234 249 166 65 192 185 102 24 74 59 167 141'
$passwordSecure = ConvertTo-SecureString -String $password -Key ([Byte[]]$key.Split(" "))
$cred = New-Object system.Management.Automation.PSCredential("powershell\psuser", $passwordSecure)
$cred
Get-WmiObject Win32_BIOS -ComputerName myserver -Credential $cred
This script connects to a server called myserver using hard-coded credentials. On first glance, you would not be able to identify the privileged password that was hard coded into this script. Instead, the password consists of the encrypted password in $password and the secret key used to unencrypt it in $key.
Of course, a knowledgeable user would identify the line using ConvertTo-SecureString which unencrypts the password. But even then would the password be unencrypted into a SecureString which again would not reveal the plain text password. The script then takes the password in $passwordSecure and creates a true credential object which in turn can be used to authenticate against all kinds of cmdlets. In this example, the script retrieves BIOS information via WMI from a remote server using the credential (identity) hard-coded in this script.
Creating Encrypted Passwords
This raises the question how to create secret keys and obfuscate a password by encrypting it with the secret key. I created a little script which will take a user name and a password and then auto-generates the script that embeds this identity in a hard coded credential. The autogenerated script then is loaded in ISE. When you run it, you receive a credential object with the password and username you specified. You can then use the credential object to authenticate against WMI or run a process as different user using Start-Process -credential $cred etc.
$path = 'c:\scripts\template.ps1'
New-Item -ItemType File $path -Force -ErrorAction SilentlyContinue
$pwd = Read-Host 'Enter Password' -AsSecureString
$user = Read-Host 'Enter Username'
$key = 1..32 | ForEach-Object { Get-Random -Maximum 256 }
$pwdencrypted = $pwd | ConvertFrom-SecureString -Key $key
$private:ofs = ' '
('$password = "{0}"' -f $pwdencrypted) | Out-File $path
('$key = "{0}"' -f "$key") | Out-File $path -Append
'$passwordSecure = ConvertTo-SecureString -String $password -Key ([Byte[]]$key.Split(" "))' |
Out-File $path -Append
('$cred = New-Object system.Management.Automation.PSCredential("{0}", $passwordSecure)' -f $user) |
Out-File $path -Append
'$cred' | Out-File $path -Append
ise $path
You can download the script here: http://powershell.com/cs/media/p/7968.aspx
No Perfect Security
Be aware that this is just a practical workaround. It is better than hard-coding plain passwords, but at the end of the day the user could still get back the password from the credential object created. I won't reveal how at this point, but knowledgeable users can do it easily. Still, I believe this is a good compromise. Use it with care.
Tobias
Microsoft MVP PowerShell Germany
P.S.
If you live in Germany or other parts of Europe and your company would like to set up a truly great PowerShell training, just contact me! I regularly train mid- to large-size companies. Trainings are always a blast with tons of real-world-examples and solutions. Here's how to get in touch with me: tobias.weltner@scriptinternals.de
Posted
Oct 22 2010, 05:09 PM
by
Tobias