A History of Active Directory Security

During the Summer of 2024, I had a talk at Troopers called “A Decade of Active Directory Attacks:
What We’ve Learned & What’s Next
” (Slides & Video). I focused on the key milestones of Active Directory security. This post covers this in some detail which was correlated with public information and GitHub release information. This article breaks down the notable attacks into a timeline.
If you are interested in the history of Active Directory, this is the article for you.

If you have anything to add or update, please email me: sean[@]adsecurity[dot]org.

“Baby Steps” (2000 – 2009)

We start with a time period I call “Baby Steps” (2000 – 2009). This is where some of the key attack capability still in use today was developed.

April, 1997: Paul Ashton posted to NTBugtraq about “‘Pass the Hash’ with Modified SMB Client” leveraging the username and LanMan hash against NT.

March, 2021: Sir Dystic of Cult of the Dead Cow (cDc) releases SMBRelay and SMBRelay2

2007: NBNSpoof tool created by Robert Wesley McGrew (LLMNR/NBT-NS)

July 2008: Hernan Ochoa publishes the “Pass-the-Hash Toolkit“ (later called WCE and was the inspiration for Mimikatz)

“The Wonder Years” (2010 – 2014)

The next time period I call “The Wonder Years” (2010 – 2014) which is where some key Active Directory attack elements are created.

March 2010: Windows Credentials Editor (WCE) & RootedCon presentation by Hernan Ochoa. WCE was the first tool that provided capability to dump in-memory credentials without running code inside of LSASS. ID: S0005

May 2011: First version of the Mimikatz tool released by Benjamin Delpy. ID: S0002
ADSecurity Unofficial Guide to Mimikatz (no longer updated)

2012: Exploiting Windows 2008 Group Policy Preferences by Emilien Giraul. ID: T1552.006

May 2012: Chris Campbell’s post on GPP Passwords. ID: T1552.006
ADSecurity article on Group Policy Preference Passwords

October 2012: Responder v1 tool released by Laurent Gaffie. Responder was a tool that leveraged LLMNR and Netbios protocol weaknesses enabling password hash capture on the network. ID: S0174

October 2013: Invoke-Mimikatz PowerShell version of Mimikatz released by Joe Bialek

August 2014: “Abusing Microsoft Kerberos sorry you guys don’t get it” Black Hat presentation by Benjamin Delpy & Skip Duckwell which covered Golden Tickets (ID: T1558.001), Overpass-the-hash, and Pass-the-ticket (ID: T1550.003) techniques.
Golden Ticket attack description

September 2014: PAC Validation, The 20 Minute Rule and Exceptions (BHUSA 2014 part deux) blog post about Silver Tickets (ID: T1558.002) by Skip Duckwell
ADSecurity article on Silver Tickets

September 2014: Kerberoast released by Tim Medin at DerbyCon. ID: T1558.003
Kerberoast attack description

December 2014: PowerView tool released by Will Schroeder

The Golden Years (2015 – 2019)

Following the “Wonder Years” is the time period I call “The Golden Years” (2015 – 2019) where most of the attacks came from.

2015: DSInternals tool released by Michael Grafnetter

2015: Kekeo tool released by Benjamin Delpy

2015: PowerSploit toolset released by Matt Graeber. ID: S0194
PowerShell attack tool detection

May 2015: Impacket tool released by Alberto Solino (asolino). ID: S0357

May 2015: Method to Detect Golden Tickets

August 2015: PowerShell Empire released by Will @Hrmj0y & Justin Warner. ID: S0363

August 2015DCSync update to Mimikatz by Vincent Le Toux & Benjamin Delpy. ID: T1003.006
DCSync capability & detection

August 2015: Black Hat 2015 presentation by Sean Metcalf:  Unconstrained Delegation &
Golden Tickets more powerful & Active Directory Persistence using AdminSDHolder

September 2015: CrackMapExec v1.0.0 tool released by Marcello aka byt3bl33d3r. ID: S0488

September 2015: DerbyCon 2015 presentation by Sean Metcalf: Attacking DSRM

December 2015: Attacking  Group Managed Service Accounts (GMSAs) by Michael Grafnetter

August 2016: Bloodhound tool released at DEFCON 23 originally written by Will Schroeder, Rohan Vazarkar, & Andy Robbins. ID: S0521

February 2017: Detect Kerberoasting with No false positives

May 2017: DNSAdmin to Domain Admin by Shay Ber
ADSecurity article on this

May 2017: Death Star python script released by byt3bl33d3r

May 2017: Ntlmrelayx tool released by Fox-IT

August 2017: ACE up the Sleeve Black Hat 2017 presentation by Andy Robbins and Will Schroeder which covered 5 primary items: A Hidden DCSync Backdoor, AdminSDHolder, Exploitation, Exchange Strikes Back, and Abusing GPOs.

September 2017: Sharphound tool release

2018: Ldapdomaindump tool released by Dirk-jan Molema

February 2018: Bloodhound.py tool released by Dirk-jan Molema (Python based Bloodhound ingester)

July 2018: GhostPack released  as a collection of C# ports of popular PowerShell tools and collects these tools together

August 2018: DCShadow attack by Vincent Le Toux & Benjamin Delpy. ID: T1207

September 2018: Rubeus tool released by Will Schroeder (port of Kekeo and added to GhostPack). ID: S1071

October 2018: “Printer Bug” AD priv esc talk at DerbyCon by Will Schroeder, Lee Christensen, & Matt Nelson
ADSecurity article on this

“The Third Age” (2020 – Present)

We are currently in what I refer to as the “Third Age” which is mostly refinements of existing techniques and tools with some notable novel techniques thrown in for good measure.

December 2020: Adalanche tool released by Lars Karlslund

April 2021: RemotePotato0 tool released by antonioCoco & article by Antonio Cocomazzi and Andrea Pierini

July 2021: PetitPotam tool released

August 2021: Certified Pre-Owned (ADCS Attacks) Black Hat talk by Will Schroeder & Lee Christensen
whitepaper download

August 2021: Certify ADCS tool released by Will Schroeder & Lee Christensen (in GhostPack)

October 2021: Kerberos Relay Attack by James Forshaw

October 2021: Certipy tool released by Oliver Lyak (ly4k) – Python port of the Certify tool

November 2021: “Is This My Domain Controller” Black Hat talk by Sagi Sheinfeld (@sagish1233), Eyal Karni (@eyal_karni), & Yaron Zinar (@YaronZi)

April 2022: KrbRelayUp tool released by Dec0ne

October 2023: CrackMapExec continues as NetExec (nxc)

That’s my list of notable techniques and tools. If you have anything to add or correct, please email me sean[@]adsecurity[dot]org.

Active Directory Security Tip #11: Print Service on Domain Controllers

The Print Spooler service is a default service on Windows Servers and is set to run at startup. There are a number of attacks that are enabled by having the Print Spooler service running on Domain Controllers (ex.: Printer Bug: https://adsecurity.org/?p=4056)


At this point it’s best to configure a GPO to disable the Print Spooler service on Domain Controllers (2nd & 3rd screenshot show the GPO settings). There shouldn’t be anything affected by this change. No one should be using their Domain Controller as a print server and the only thing this service does by default is manage automatic Printer object pruning, but there needs to be a GPO to configure this. We have only seen this a total of 2 times over 8 years of performing Active Directory Security Assessments (ADSAs)


PowerShell code to check if the Print Spooler service is running in the current domain (requires DC admin rights, so domain Administrator or equivalent):

$Domain = $env:userdnsdomain
$DomainDC = (Get-ADDomainController -Discover -DomainName $Domain).Name

$DomainDCs = Get-ADDomainController -Filter * -Server $DomainDC | Sort HostName 
ForEach ($DomainDCItem in $DomainDCs) 
 { 
     $ServiceStatusArray = Get-service -Name 'spooler' -ComputerName $DomainDCItem.HostName 
     switch ($ServiceStatusArray.Status) 
      { 
         "Running" { Write-host "$($DomainDCItem.HostName): Print Spooler Service is RUNNING" -ForegroundColor Red } 
         "Stopped" { Write-host "$($DomainDCItem.HostName): Print Spooler Service is stopped" -ForegroundColor Green } 
         default { Write-host "$($DomainDCItem.HostName): Test failed" -ForegroundColor Yellow } 
      } 
 }

Active Directory Security Tip #10: FSMO Roles

Getting Microsoft supported backups of Domain Controllers is an important part of recovery strategy.

A best practice is to locate all Flexible Master Single Operator (FSMO) roles on a single DC in the domain. That way you can more easily target the DC that hosts the FSMOs for backup.


PowerShell code to check for FSMO role holders for the forest & current domain:

$ADForestArray = Get-ADForest 
$ADForestArray | Select-Object SchemaMaster,DomainNamingMaster 
ForEach ($ADForestArrayDomain in $ADForestArray.Domains)
 {
    $DomainDC = (Get-ADDomainController -Discover -DomainName $ADForestArrayDomain).Name
    Get-ADDomain -Server $DomainDC | Select-Object PDCEmulator,RIDMaster,InfrastructureMaster
 }

Active Directory Security Tip #9: Active Directory Backups

Microsoft supported backups of Active Directory are very important to have. For backing up Domain Controllers, this is typically a System State backup.

Why a Microsoft supported backup? If you are using a backup solution that isn’t fully AD aware, performing a restore may involve getting Microsoft involved and that costs $$.

I know companies that have used ####### (redacted) to backup their AD and there was no System State and the backup wasn’t a full AD aware backup so they ended up paying ###### $$$ and Microsoft $$$. Just get a System State backup of the DCs that host your FSMO roles about every month and be prepared for a scenario where you may have to restore AD.

Determining if a recent supported backup has been performed is easy since these backups update a bit in each partition.

PowerShell code to check the current domain for the last Microsoft supported AD backup:

$ContextType = [System.DirectoryServices.ActiveDirectory.DirectoryContextType]::Domain
$Context = New-Object System.DirectoryServices.ActiveDirectory.DirectoryContext($ContextType,(Get-ADDomain).DNSRoot)
$DomainController = [System.DirectoryServices.ActiveDirectory.DomainController]::findOne($Context)
    
[string[]]$Partitions = (Get-ADRootDSE).namingContexts
 foreach ($Partition in $Partitions) 
  {
    $dsaSignature = $DomainController.GetReplicationMetadata($Partition).Item("dsaSignature")
    Write-Host "$Partition was backed up $($dsaSignature.LastOriginatingChangeTime.DateTime)" 
   }

Active Directory Security Tip #8: The Domain Kerberos Service Account – KRBTGT

The domain Kerberos service account, KRBTGT (https://adsecurity.org/?p=483), is an important account since it is used to sign & encrypt Kerberos tickets. The account is disabled and the password doesn’t change except when moving from Windows 2000/2003 to Windows Server 2008 (or newer).

This is a highly privileged account and if an attacker can gain knowledge of the account’s password hash (or password), they can create forged Kerberos tickets (aka Golden Tickets: https://adsecurity.org/?p=1640).

Most AD forests have this account lingering with old passwords. The KRBTGT account stores two passwords, the current one and the previous one and checks them both to validate Kerberos tickets. This means that to ensure that the KRBTGT passwords are fully changed, the password must be changed twice. If an attacker can capture a DC backup that is as old as one of the KRBTGT account passwords (say 15 years), then they can compromise the environment even if the backup is 15 years old!

We can use the “msds-keyversionnumber” attribute to determine how many times the KRBTGT password has changed. The formula n – 2 works to calculate how many times the password has changed. If this value is 2 it hasn’t changed since it was originally set when the domain was created. If the value is 9, then it has changed 7 times (9 – 2 = 7). Sometimes this value is very large, like 100003. In that case we just use the last digit (3) to calculate the number of times it has changed: n – 2 = 1, so it has changed 1x.

We recommend changing the password once, then waiting at least a week, and then changing the password again. When you set the password, a process on the DC actually changes the KRBTGT password to a fully random password.


PowerShell code to report on the KRBTGT account for the current domain:

$Domain = $env:userdnsdomain
$DomainDC = (Get-ADDomainController -Discover -DomainName $Domain).Name
$DomainKRBTGTAccount = Get-ADUser 'krbtgt' -Properties DistinguishedName,'msds-keyversionnumber',Created,PasswordLastSet -Server $DomainDC    
$DomainKRBTGTAccount | Select DistinguishedName,Created,PasswordLastSet,'msds-keyversionnumber' | Format-Table -AutoSize

Active Directory Security Tip #7: The Tombstone Lifetime

The Tombstone lifetime (TSL) in Active Directory is the limit as to how long a deleted object can remain in AD. The original value was 60 (days). Windows versions since Windows 2003 SP2 have this set to 180 (days). Note that this also affects backups, how long a backup is valid and replication – if a DC doesn’t replicate with its partner(s) within the TSL, the other DCs will ignore it. https://adsecurity.org/?p=81

If you have an environment with it still set to 60, I recommend you update it to 180 days. This may slightly bloat AD since deleted objects will linger longer, but it does provide a fail-safe of sorts if you need to recover going back >60 days.


PowerShell code using the AD PowerShell module to determine the Tombstone lifetime:

$ADRootDSE = Get-ADRootDSE
$ADConfigurationNamingContext = $ADRootDSE.configurationNamingContext
    
$TombstoneObjectInfo = Get-ADObject -Identity "CN=Directory Service,CN=Windows NT,CN=Services,$ADConfigurationNamingContext" -Partition "$ADConfigurationNamingContext" -Properties * 
[int]$TombstoneLifetime = $TombstoneObjectInfo.tombstoneLifetime

IF ($TombstoneLifetime -eq 0) 
 { $TombstoneLifetime = 60 }

Write-Host "The AD Forest Tombstone lifetime is set to $TombstoneLifetime days."

Active Directory Security Tip #6: Domain Controller Operating System Versions

Ensuring proper Domain Controller configuration is key for Active Directory security.

Part of this is making sure they are running supported versions of Windows. At this point, DCs should be running at least Windows Server 2016, preferably Windows Server 2019 or 2022.

Hold off on deploying Windows Server 2025 DCs for now due to the dMSA issue (https://akamai.com/blog/security-research/abusing-dmsa-for-privilege-escalation-in-active-directory).


Active Directory PowerShell code for Domain Controller operating system versions & site location for the current domain:

$Domain = $env:userdnsdomain
$DomainDC = (Get-ADDomainController -Discover -DomainName $Domain).Name
$DomainDCs = Get-ADDomainController -Filter * -Server $DomainDC
$DomainDCs | Select HostName,IPv4Address,OperatingSystem,Site | Sort HostName | Format-Table -AutoSize

Active Directory Security Tip #5: The Default Domain Administrator Account

In every Active Directory domain, there’s the default domain Administrator account.
Here are some key items to check:

  • Do you know when the last time the Administrator account was used (logged into)?
  • The last time its password was changed? Is it current?
  • How the password is managed and stored?
  • Does it have an associated Kerberos Service Principal Name (SPN)? (it shouldn’t)
  • Is it enabled? (it’s probably fine if it is)


PowerShell for current domain using the AD PowerShell cmdlets:

$Domain = $env:userdnsdomain
$DomainDC = (Get-ADDomainController -Discover -DomainName $Domain).Name
Get-ADUser "$((Get-ADDomain).DomainSID)-500" -Properties Name,Enabled,Created,PasswordLastSet,LastLogonDate,ServicePrincipalName,SID -Server $DomainDC


Active Directory Security Tip #4: Default/Built-In Active Directory Groups

There are several default/built-in privileged groups that should be reviewed:

  • Account Operators – should be empty per Microsoft due to highly privileged access in AD.
  • Backup operators – should only contain backup service accounts to backup and restore Active Directory.
  • Cert Publishers – should only contain PKI related accounts (CAs & related service accounts) since it can publish certificates for AD users.
  • DNSAdmins – typically only used when admins other than ADAs perform DNS administration. Use sparingly. * Enterprise Key Admins – have admin rights on key objects in AD.
  • Event Log Readers – should only include accounts that require access to Domain Controller event logs.
  • Group Policy Creator Owners – can modify Group Policies in the domain. Membership should be empty and rights delegated instead.
  • Print Operators – used only when a Domain Controller is used as a print server (which shouldn’t happen). Group has the ability to logon to Domain Controllers and install drivers which makes this group highly privileged. Group should be empty.
  • Server Operators – effectively local admin on Domain Controllers. Use sparingly.
  • Schema Admins – should be empty except when updating the AD schema.

https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/manage/understand-security-groups


PowerShell Script leveraging the Active Directory PowerShell module:
https://github.com/PyroTek3/Misc/blob/main/Get-ADBuiltInAdmins.ps1

Active Directory Lab Build Script

Over the summer, I rebuilt my Active Directory lab environment with multiple regional domains. Instead of manually configuring common issues, I decided to create a PowerShell script to do this for me.

Continue reading

Load more