The passwords of local administrative accounts should be changed regularly and these passwords should be different from one computer to the next. But how can this been done securely and conveniently? How can it scale to thousands of computers? And how can this be done for free?
The Securing Windows and Resisting APT Malware course at SANS (course SEC505) includes free PowerShell scripts to manage local account passwords. Download the scripts in the SEC505 zip file, then look inside that zip archive for the \Day2-Admins\UpdatePasswords\ folder.
These PowerShell scripts are intended to be relatively easy to understand and modify, you don't have to be a PowerShell guru. Error checking was kept to a minimum to reduce code clutter, but it should be adequate for troubleshooting (feel free to add more error handling). Like all scripts in the SEC505 zip file, these scripts are in the public domain too.
If you would prefer a non-PowerShell commercial product to manage admin passwords, here are few to consider:
- ManageEngine Password Manager Pro
- Cyber-Ark Privileged Identity/Session Management
- Lieberman Software Password Manager
- Thycotic Secret Server
- PasswordCourier Password Management
- NetWrix Privileged Account Manager
- AutoCipher
Solution
A trusted administrator should obtain a certificate and private key, then export that certificate to a .CER file into a shared folder (\\server\share\cert.cer). Any certificate from any source for any intended purpose will do, but a 2048-bit RSA public key (or larger) from one's own PKI is preferred.
Copy the Update-PasswordArchive.ps1 script into that shared folder (\\server\share).
Using Group Policy, SCCM, a third-party EMS, schtasks.exe or some other technique, create a scheduled job on every computer that runs once per week (or every night) under Local System context which executes the following command:
powershell.exe \\server\share\update-passwordarchive.ps1 `
-certificatefilepath \\server\share\cert.cer `
-passwordarchivepath \\server\share `
-localusername Administrator
This resets the password on the local Administrator account (or whatever account is specified at the command line) with a 15-25 character, random complex password. The password is encrypted in memory with the public key of the certificate (cert.cer) and saved to an archive file to the specified share (\\server\share).
When a password for a computer (for example, laptop47) needs to be recovered, the trusted administrator should run the following PowerShell script at their local computer:
recover-passwordarchive.ps1 -passwordarchivepath \\server\share `
-computername laptop47 -username administrator
This downloads the necessary encrypted files, decrypts them locally in memory using the private key of the administrator, then outputs the plaintext password within PowerShell. The password can then be piped into other commands to open an RDP session, copy files, execute another command, etc.
Requirements
PowerShell 2.0 or later must be installed on both the computer with the local user account whose password is to be reset and also on the administrators' computers who will recover these passwords in plaintext.
The Update-PasswordArchive.ps1 script, which resets the password, must run with administrative or Local System privileges.
Testing Example
From the SEC505 zip file, copy the \Day2-Admins\UpdatePasswords folder to your hard drive.
In File Explorer, double-click the "Password-is-password.pfx" file to import the test certificate and private key into your current user store (accept all the defaults). The password is "password".
Open PowerShell with administrative privileges and run this command to reset the password on the Guest account:
.\Update-PasswordArchive.ps1 -LocalUserName Guest -CertificateFilePath .\PublicKeyCert.cer
Do a "dir" listing and you will see a new file with a very long name, similar to the following:
MYCOMPUTER+Guest+635108515647128197+F5FF0247B0CF6A81148CE83D2EBA4A141CB095F3
If you open the file in Notepad or a hex editor, you'll see that it has been encrypted with the public key in the PublicKeyCert.cer file. The private key for this public key has already been imported into your local user certificate store, hence, you can use your private key to extract the password from the encrypted file. Unless hackers have stolen your private key, they will not be able to decrypt the file and obtain the password inside it.
To obtain the plaintext password, run this command:
.\Recover-PasswordArchive.ps1 -ComputerName $env:computername -UserName Guest
The output is an object with the plaintext password and other properties, similar to this:
ComputerName : MYCOMPUTER
FilePath : MYCOMPUTER+Guest+635108515647128197+F5FF0247B0CF6A81148CE83D2EBA4A141CB095F3
UserName : Guest
TimeStamp : 7/31/2013 7:12:44 AM
Thumbprint : F5FF0247B0CF6A81148CE83D2EBA4A141CB095F3
Valid : True
Password : TheRandomComplexPassword
The password property can now be piped into other commands or copied into the wetware clipboard through your retina.
To see the full help for this script, run:
get-help -full .\Update-PasswordArchive.ps1
Notes
The password is never sent over the network in plaintext, never saved to disk in plaintext, and never exposed as a command-line argument, either when resetting the password or when recovering it later. The new password is generated randomly in the memory of the PowerShell process running on the computer where the password is reset. The process runs for less than a second as Local System as a background process.
Different certificates can be used at different times, as long as their private keys are available to the administrator. When recovering a password, the correct certificate and private key will be used automatically, even if multiple certificates are in use. A smart card can be used too. The script has been successfully tested with the Common Access Card (CAC) used by the U.S. military and DoD.
If the shared folder is not accessible to the computer when the scheduled job runs, the password is not reset.
If multiple administrators must be able to recover the plaintext passwords, export the relevant certificate and private key to a PFX file and import it into each administrator's local profile. Because this is not a certificate used to uniquely identify a person or device (non-repudiation is not an intended feature), everyone on the help desk could have a copy of its private key.
To delegate authority to different administrators over different computers, then simply use different public/private key pairs. When using Group Policy to create the scheduled job on the machines in an organizational unit, for example, any certificate can be specified, and this does not have to be the same certificate used for all machines in a domain. The corresponding private keys can be shared with whatever subset of administrators is desired. If the private key is on a smart card, that card can be physically protected from unauthorized admins.
The password update script writes to the local Application event log on the machine where it runs (Source: PasswordArchive, Event ID: 9013). When the password is used to log into the computer, this can also be logged if the appropriate audit policies are enabled. The SEC505 zip file includes another script (SendTo-SysLog.ps1) if you'd like to modify the update script to also send a syslog message whenever the script runs.
The script can only be used to reset the passwords of local accounts, not domain accounts in Active Directory, though it could be modified for this purpose.
Threats
Keep the private key for the certificate used to encrypt the password archive files secure, such as on a smart card. This is the most important factor. Do not use the sample keys provided here for anything other than testing.
If the private key for the certificate is compromised, create a new key pair, replace the certificate file (.CER) in the shared folder, and immediately remotely trigger the scheduled job on all machines using Group Policy, schtasks.exe or some other technique. Once all passwords have been changed, the fact that the old private key has been compromised does not mean any current passwords are known.
Prevent modification of the Update-PasswordArchive.ps1 script itself by digitally signing the script, enforcing script signature requirements, and using restrictive NTFS permissions. Only allow NTFS read access to the script to those identities (computer accounts) which need to run it. Use NTFS auditing to track changes to the script.
Attackers may try to delete or corrupt the existing password archive files to prevent access to current passwords. It's best to store the certificate and archive files in a shared folder whose NTFS permissions only allow the client computer accounts the following permissions:
Principal: Domain Computers
Apply to: This folder, subfolders and files
Allow: Full Control
Deny: Delete subfolders and files
Deny: Delete
Deny: Change permissions
Deny: Take ownership
Deny: Create folders/append data
Principal: Domain Computers
Apply to: Files only
Deny: Create files/write data
The trusted administrators can be granted Full Control to the archive files, certificates, and scripts as needed of course. The above permissions are for just for Domain Computers.
An attacker might try to generate millions of spoofed archive files and add them to the shared folder. This is possible because the script and public key would be accessible to the attacker too. NTFS auditing on the share can log which computer(s) added the spoofed files and when. The archive files might be digitally signed, but with what key? We must assume the attacker can extract any signing keys from kernel memory on the computers they have already compromised. Realistically, though, a DoS attack in which millions of new archive files are created would likely be of low value for the attacker since it would be easy to detect, easy to log the name or IP of the machine creating the new files, easy to use timestamps in the share to identify post-attack files, nightly backups of the archive files can be retained for 30+ days, and the DoS attack would not allow the hacker to expand their existing powers to new machines. Besides, the benefit to us of managing local administrative account passwords correctly far exceeds the potential negative of this sort of DoS attack.
IPSec permissions which limit access to the SMB ports of the file server is recommended, but not for the encryption, but for restricting access to the SMB ports (TCP 139/445) based on group memberhips, e.g., domain computer, administrators, help desk personnel, etc.
Tips
The output of the Recover-PasswordArchive.ps1 script can be piped into other scripts to automate other tasks which require the plaintext password, such as executing commands, doing WMI queries, opening an RDP session, or immediately resetting the password again when finished.
When recovering a password, you can pipe the password into the built-in clip.exe utility to put the password into the clipboard, like this:
\\controller\password-archives\Recover-PasswordArchive.ps1 `
-PasswordArchivePath \\controller\password-archives -ComputerName laptop47 `
-UserName Administrator | select-object -expandproperty password | clip.exe
What prevents an endless accumulation of encrypted password archive files in the shared folder? The CleanUp-PasswordArchives.ps1 script will remove older or obsolete archive files which are no longer needed. Run this script as a scheduled job once per month. See the help in that script for its command-line parameters to customize what it deletes, e.g., by default it keeps the last five password archive files for each computer and username combination, but this can be changed.
To optimize the performance of the Recover-PasswordArchive.ps1 script when there are more than 100,000 files in the folder containing the password archives, disable 8.3 file name generation and strip all current 8.3 names on the volume containing that folder. Search the Internet on "fsutil.exe 8dot3name" to see how.
To maximize fault tolerance and scalability, use Distributed File System (DFS) shared folders across two or more servers, and back up the folder at least weekly. With DFS and Group Policy management of the scheduled jobs, the solution can scale to large networks.
The solution works on stand-alone computers as well, but the scheduled task, shared folder, and permissions will need to handled appropriately; for example, a wrapper script will likely be needed to automate the creation of the scheduled task and the copying of the encrypted password file to some kind of archival server, perhaps via FTP or secure copy.
You can also perform an immediate password update with commands like these, but wrapped in a function or placed in another script:
Copy-Item -Path .\PublicKeyCert.cer -Destination \\laptop47\c$
Invoke-Command -ComputerName laptop47 -filepath .\Update-PasswordArchive.ps1 -argumentlist "C:\publickeycert.cer","Administrator","c:\"
Copy-Item -Path \\laptop47\c$\laptop47+Administrator+* -Destination C:\LocalFolder
Remove-Item -Path \\laptop47\c$\PublicKeyCert.cer
Remove-Item -Path \\laptop47\c$\laptop47+Administrator+*
The above Invoke-Command can be done by specifying UNC paths instead, but this requires delegation of credentials to the remote computer, which is not ideal for limiting token abuse attacks, so the certificate and archive files should be copied back-and-forth manually. Besides, wrapped in a function or script with some error-handling code, all these steps would be hidden from us anyway.
Do not use the sample certificate and private key provided with these scripts. You must obtain your own key pair and never share your private keys with outsiders.
Each password archive file name includes a ticks timestamp number. To manually convert the ticks timestamp in the file name (e.g., 635093865618276588) to a human-readable date and time in PowerShell, run this command:
[DateTime][Int64] 635093865618276588
If all the password archive files are moved to another volume, it would be convenient to reset the NTFS LastWriteTime property of the archive files to match the ticks timestamp in the archive file names themselves, such as with this command:
dir *+*+* | foreach { $_.LastWriteTime = [DateTime][Int64] $(($_.Name -split '\+')[2]) }Update History
24.Sep.2013: Thanks to Timothy Carroll for uncovering a formatting bug in the password generator found in Update-PasswordArchive.ps1. The fix does not affect compatibility with earlier versions of the other scripts or with previously-created encrypted password files.
25.Sep.2013: Added support for the minimum and maximum length of the random password generated.
Caveats & Legal Disclaimers
The scripts are free and in the public domain, you may use it for any purpose whatsoever without restriction. However, that being said...
THESE SCRIPTS ARE PROVIDED "AS IS" WITH NO WARRANTIES OR GUARANTEES OF ANY KIND, INCLUDING BUT NOT LIMITED TO MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. ALL RISKS OF DAMAGE REMAINS WITH THE USER, EVEN IF THE AUTHOR, SUPPLIER OR DISTRIBUTOR HAS BEEN ADVISED OF THE POSSIBILITY OF ANY SUCH DAMAGE. IF YOUR STATE DOES NOT PERMIT THE COMPLETE LIMITATION OF LIABILITY, THEN DO NOT DOWNLOAD OR USE THE SCRIPTS. NO TECHNICAL SUPPORT WILL BE PROVIDED.

Posted September 05, 2013 at 12:47 PM | Permalink | Reply
OldguardMD
Would it be more secure to encrypt with ECDH based keys (Elliptic Curve) instead of RSA... I have not seen an example of how to encrypt using ECHD using Powershell, but hope to find one and amend the script you have supplied in this article.
Posted September 09, 2013 at 4:09 PM | Permalink | Reply
Jason Fossen
Hi OldguardMD:
I haven't tested this, but an EC certificate should work just fine. The testing certificate provided in the zip file happens to be RSA, but it's just an example. A 4096-bit RSA certificate could also be used if one's organization couldn't use an EC cert for some reason.
Cheers,
Jason