My BSides NoVa talk slides are now posted. My BSides NoVA talk was called “10 Ways to Improve Entra ID Security Quickly” and I focused on the areas that tend to be missed in Entra ID.

Oct 12 2025
My BSides NoVa talk slides are now posted. My BSides NoVA talk was called “10 Ways to Improve Entra ID Security Quickly” and I focused on the areas that tend to be missed in Entra ID.
Oct 12 2025
A couple years ago, the Microsoft Security Experts Blog interviewed me regarding Azure Active Directory (Entra ID) security.
Oct 08 2025
Review the membership of groups for accounts and groups from another Active Directory forest (technically another domain, but using forest here). These are called “Foreign Security Principals” (FSPs) like the ones highlighted in the image. These FSPs are accounts that exist in another forest but have rights in the AD forest.
Any FSPs should be scrutinized and removed if not required. It’s important to review and strictly control these since they may be highly privileged. In this example, compromise of another AD forest (TRDNET) would result in compromise of the current AD forest (Trd.com).
PowerShell script to scan privileged groups for FSPs:
https://github.com/PyroTek3/Misc/blob/main/Invoke-FindPrivilegedFSPs.ps1
Oct 06 2025
I have mentioned in several presentations that Kerberos delegation is impersonation. Kerberos delegation is used when a service (ex. web server) needs to impersonate a user when connecting to a resource (ex. database).
There are a 4 types of Kerberos delegation:
Unconstrained delegation should be converted to constrained delegation due to security concerns. Any Kerberos delegation that is no longer required should be removed. If there’s no associated Kerberos service principal name, Kerberos authentication isn’t working and this should be fixed or removed.
PowerShell code using the Active Directory PowerShell module:
https://github.com/PyroTek3/Misc/blob/main/Get-ADKerberosDelegation.ps1
Oct 04 2025
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) where I focused on the key milestones of Active Directory security (history). This article covers my “decade of Active Directory attacks” in some detail which was correlated with public information and GitHub release information. This Active Directory security history article breaks down the notable attacks into a timeline starting with Active Directory’s release in 2000 and continuing until the present day in late 2025.
If you are interested in the history of Active Directory, this is the article for you.
If you have anything to add or update on the History of Active Directory Security, please email me: sean[@]adsecurity[dot]org.
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 Windows NT.
February 17, 2000: Active Directory released as part of Windows 2000 (RTM was December 5, 1999 while retail release was February 17, 2000).
March, 2001: 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).
Continue readingOct 03 2025
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 }
}
}
Oct 01 2025
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
}
Sep 29 2025
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)"
}
Sep 20 2025
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
Sep 19 2025
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."
Recent Comments