People often ask me why we decided to store password in clear text in AD when implementing LAPS. Let's answer the question now and give guidelines on how to deal with passwords of local administrator accounts stored in AD.
Main reason for the decision to store password in AD as clear text was simplicity of the solution: focus was on implementation of Client Side GPO extension that manages local administrator account on local machine, and get the result (password and expiration timestamp to AD. Administrators can then use tools provided with the solution (PowerShell cmdlet of LAPS UI client), or built-in tool (such as dsa.msc) to retrieve the password.
When considering encryption of password in AD, implementation needs to decide how to protect and distribute decryption key:
- Symmetric encryption/decryption algorithms are not good here: key would also be used for encryption, so it would need to be known by all managed machines that are expected to encrypt password using it, plus administrators who need it for decryption of password. Not good. Maybe separate key for each machine? A lot of keys would be needed, which is not good, and still there is a need to make sure that only approved admins have access to the key to perform decryption of password
- Asymmetric encryption/decryption algorithm? Probably a better solution: encryption would use public key, so all managed machines can easily use the same key, but still, there is a challenge to solve: how to make distribute private key to administrators who need it for password decryption. Probably best way would be to implement a central service that would be owner of private key and used it for password decryption. This would work, but it's far from simple design that was the original goal
Actually, there are 2 sides of story when speaking about password stored as clear text in AD:
- Password protection while stored in AD
- Password protection during the transport to end user who needs it
Password protection when stored in AD
Permission to read the password from AD
As you probably know, ms-Mcs-AdmPwd attribute that stores password in AD is marked as Confidential in AD - this means that users need to have extra permission (CONTROL_ACCESS permission) to read the value - Read permission is not enough. AD honors the read request for confidential attribute value when at least one of the following is true:
- Caller is granted 'Full Control' permission
- Caller is granted 'All Extended Rights' permission
- Caller is granted 'Control Access' on the attribute permission (this is what LAPS PowerShell uses to grant the permission)
So it's important that AD administrators detect who has permission to read the password before managed machines start reporting password to AD and align permissions with desired administration model to prevent password reads by people who should not be allowed to.
There is LAPS PowerShell cmdlet that helps identify who effectively has permission to read password, so IT admins can change permission delegation model to remove the read password permission from people who should not have it – cmdlet name is Find-AdmPwdExtendedRights
Theft of Domain controller and harvesting for passwords stored there
Yes, theft can happen. AD database itself is one of biggest security assets of company and as such, needs to be protected properly. Protect your AD backups and you will protect local administrator passwords stored there as well.
For physically insecure environments, consider using Read Only Domain Controllers (RODC). ms-Mcs-AdmPwd attribute is flagged not to replicate its value to RODC, so theft of RODC will not reveal any local administrator passwords to the thief.
Also, ms-Mcs-AdmPwd attribute is flagged so as DC does not audit change of values - so harvesting of security logs of domain controllers will not reveal any local administrator passwords.
Password protection during transit
LAPS tools have built-in protection for password transport implemented. Protection is based on ‘Kerberos encryption’ that’s available out of box for domain joined machines for a few protocols including LDAP. Both LAPS PowerShell and LAPS UI use this protection to make sure that password is protected during transit.
However, it’s important to understand, that this protection cannot be enforced from DC side, and it always needs to be initiated from client side, so keep this in mind when you choose to use different tools or decide to develop own tools instead.
Support for encryption from tools available on platform
Recent versions of common MS tools do a good job in terms of securing data during transport:
- Dsa.msc: uses encrypted connection by default
- Adsiedit.exe: uses encrypted connection, even when configured not to use LDAP/SSL
- Ldp.exe: offers to use encrypted connection by default, when binding:
However, with LDP, you can connect unencrypted if you want to, provided you know what you’re doing
Recommendation: always use SW that encrypts traffic when retrieving data from AD – either Kerberos encryption, or – if your DCs have a SSL certificate – use SSL connections whenever possible.
Your own code
Let’s see below on typical approaches for AD data retrieval and how to make sure that data is protected during transport
Simple PowerShell script using ADSI is usually a bad choice:
This script reveals password on the network. Never use ADSI this way. If you must use ADSI, always use IADsOpenDSObject interface and specify USE_SIGNING and USE_SEALING in OpenDSObject method. See https://msdn.microsoft.com/en-us/library/aa706065(v=vs.85).aspx for more details.
Get-ADComputer cmdlet uses AD WS rather than LDAP, and connection uses SSL, so password is protected during transport
System.DirectoryServices namespace in .NET Framework
Objects is this namespace are based on ADSI, so generally, it tends not to protect transmitted data by default. To ensure protection, make sure you turn it on before touching a directory object, as shown on simple PowerShell script below:
$comp.AuthenticationType=$comp.AuthenticationType -bor [System.DirectoryServices.AuthenticationTypes]::Sealing
$comp.AuthenticationType=$comp.AuthenticationType -bor [System.DirectoryServices.AuthenticationTypes]::Secure
System.DirectoryServices.Protocols in .NET Framework
Personally, API of my choice for managed programming; robust and powerful (see my sample on how to use it in PowerShell here: https://gallery.technet.microsoft.com/Using-SystemDirectoryServic-0adf7ef5).. However, encryption needs to be turned on explicitly on LdapConnection object, as shown on PowerShell script below:
[System.Reflection.Assembly]::LoadWithPartialName("System.DirectoryServices.Protocols") | Out-Null
$directory=new-object System.DirectoryServices.Protocols.LdapDirectoryIdentifier("MyDC.MyDomain.com", 389)
Even when password is stored as clear text in AD by LAPS, still the solution provides significant amount of security:
- Password is protected by ACL
- Password is not replicated to RODC and is not revealed in audit logs on DC
- Is protected in transit by LAPS tools
You only need to understand how the password is protected and use the solution a proper way to keep the password secure