As the Identity and Authentication source of most Enterprises, Active Directory is the backbone of local and federated authentication. Coupled with the prevalence of Cloud computing, organizations are depending more-and-more on federated authentication and expanding their Active Directory into the Cloud.

While most organizations upgrade their Active Directory through Domain Controller OS upgrades, AD by design is meant to be as backwards compatible as possible, and therefore leaves many legacy protocols and configuration settings enabled. Many Domains originated long ago, and have been upgraded throughout the years, but the legacy protocols and settings enabled from the onset were never disabled. Attackers have developed automated tools to exploit these weaknesses, that while legitimate, are insecure none the less.

The firewall and network perimeter can no longer be considered the security boundary. You must assume that an internal user will inadvertently click on something and become compromised. The workstation is now the security boundary, and the older the origins of the AD network, the easier it becomes for an attacker to perform reconnaissance, compromise network traffic, sniff passwords, and move throughout your network.

With each new OS release from Microsoft come a series of improvements, many aimed at the stability and recoverability of Active Directory, but many are only enabled once extra steps are taken to configure and implement them. The audit outlined below will report what’s currently enabled, what should be disabled, ensures AD health, and provides recommendations for further securing AD based on your unique environment.

“An ounce of prevention is better than having to rebuild your entire Domain from backup.”
– Benjamin Franklin

Requirements

RSAT Tools
PowerSploit (Recon and Exfiltration)

Group Policy

  • Run Powershell GP-Link report
    • Shows OU tree and applied GP
  • Backup all GPOs
    • Backup-GPO -All -Path c:\GPOBackup
  • Check CentralStore for ADMX storage
    • Test-Path \\<DC_Name>\SYSVOL\<YOURDOMAIN>\Policies\PolicyDefinitions
  • Are there ADM GPOs or have all been converted to ADMX
    • dir/W *.adm /S on DC SYSVOL
  • Check SYSVOL
    • Contents consistent across DCs?
      • Only on Server 2012R2 or 2016 DFL
        • Open GPMC > Domain Name > Status tab: Detect Now
    • FRS or DFSR in use?
      • Run dfsrmig /getmigrationstate on a Domain Controller
      • State ‘Eliminated’ means DFSR is in use
    • Check DFSR health
      • This DFS and SYSVOL Monitor script will count GPO objects.
        • Run ./Get-DomainDFSHealth.ps1 to load function into memory
        • RunGet-DomainDFSHealth function to generate the report
  • Is DFSR configured for automated recovery?
    • Default as of 2008R2 is to disable AutoRecover - this is to prevent data loss from unsynchronized upstream server
    • http://wiki.ledhed.net/index.php?title=DFS_AutoRecovery
    • Get-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Services\DFSR\Parameters\"" | select StopReplicationOnAutoRecovery
      • Run this on a DC. “0” or no key means disabled.
  • Audit Group Policy creators and permissions
    • The owner has the right to change GP. If a delegated Admin created the policy and it was moved, they retain permissions
      • Get-GPO -All | Select DisplayName,Owner
    • PowerView provides a quick way to scan all the permissions for all domain GPOs:
      • Get-NetGPO | %{Get-ObjectAcl -ResolveGUIDs -Name $_.Name} |select ObjectDN, IdentityReference, ActiveDirectoryRights > GP_Permissions.txt
  • Use PolicyAnalyzer from the Security Compliance Toolkit to compare GP to Microsoft recommendations
  • Check for orphaned GPOs
  • Check existing password Policy
    • Get-ADDefaultDomainPasswordPolicy
  • Check User Rights Assignment in Default Domain Controller Policy
    • Easiest way is to use GPMC to show policy settings, highlight and copy, paste into notepad and open in excel
  • Check GPO local group assignment
    • Get-NetGPOGroup gets all GPOs in a domain that set “Restricted Groups” on on target machines
  • Check GPOs for stored passwords
    • Get-GPPPassword
    • Get-GPPAutologon
    • Most of the time, the following XML files will contain credentials: groups.xml, scheduledtasks.xml, & Services.xml.
    • The credentials are AES-256 bit encrypted but Microsoft has published the AES encryption key on MSDN which can be used to decrypt the password.
    • Since authenticated users (any domain user or users in a trusted domain) have read access to SYSVOL, anyone in the domain can search the SYSVOL share for XML files containing “cpassword” which is the value that contains the AES encrypted password.

Domain Controllers

  • Get a list of all DCs, verify all are Global Catalog servers
    • Get-ADDomainController -Filter * | Select Domain,Name,IPv4Address,IsGlobalCatalog,Site,OperatingSystem
  • Disable any unused network adapters - DCs should only have a single adapter
    • netsh interface ipv4 show interfaces
  • Check for correct DNS client configuration
    • Point to partner as primary and self as secondary
    • netsh interface ipv4 show dnsservers
  • Check for existence of Backups
    • Full image backup
      • Date of last restoration test?
      • In a secure location?
      • Using third-party software?
    • System State backup - easily accessible during recovery
      • wbadmin get versions (and repadmin /showbackup)
  • Eventlog entries
    • PS script to identify most worrisome IDs
    • PS Script to show all record counts
      • Get-WinEvent -ListLog * -EA silentlycontinue | where {$_.RecordCount} | sort RecordCount -Descending
    • PS script to list last 5 errors in all logs
      • Get-WinEvent -ListLog * -EA silentlycontinue | Where-Object {$_.recordcount -AND $_.lastwritetime -ge [datetime]::today} | ForEach-Object {Get-WinEvent -LogName $_.logname -MaxEvents 5 | Where-Object {$_.LevelDisplayName -eq "Error"} } | ft -AutoSize
    • PS script to grab all errors and warnings and sort them by count
      • Get-WinEvent -ListLog * -EA silentlycontinue | Where-Object { $_.recordcount } | ForEach-Object { Get-WinEvent -FilterHashTable @{LogName=$_.logname; StartTime=(get-date).AddDays(-5) } –MaxEvents 1000 | where-object {$_.LevelDisplayName -like 'Error' -OR $_.LevelDisplayName -like 'Warning'} }
  • Check for installed patches
    • get-hotfix 3011780 #Server 2012 and earlier
    • And all other patches
  • Check running agents
    • Autoruns and Process Explorer
  • Check services
    • Get-Service | where {$_.Status -eq "Running"}
  • Check Service Accounts
    • Get-WmiObject win32_service | where {($_.startname -ne "LocalSystem") -and ($_.startname -ne "NT AUTHORITY\NetworkService") -and ($_.startname -ne "NT AUTHORITY\NETWORK SERVICE") -and ($_.startname -ne "NT AUTHORITY\LocalService") } | FT name, startname, startmode
  • Check installed Roles and Features
    • Get-WindowsFeature | Where {$_.installed -eq "True"}
  • Check for additional software running on the DC.
    • Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* | select DisplayName,Publisher,InstallDate | Sort DisplayName
  • Do you know the DSRM password?
  • Check for correct IPv6 settings
    • Don’t just uncheck the protocol on the adapter, set registry to “Prefer IPv4 over IPv6”
    • Get-ItemProperty HKLM:\SYSTEM\CurrentControlSet\Services\Tcpip6\Parameters\
      • Key DisabledComponents should read 32 for “Prefer IPv4 over IPv6” or 255 to “Disable IPv6”
  • Check time configuration
    • Have DCs synchronize their time from PDC, and have PDC synchronize via NTP
    • Configure the PDC to automatically synchronize time via GPO or just set manually
    • Get-ItemProperty HKLM:\SYSTEM\CurrentControlSet\Services\W32Time\Parameters\ | select Type, NtpServer
      • Servers should report NT5DS (use Domain to find PDC Emulator), and PDC should report NTP
    • w32tm /query /status and w32tm /query /configuration for more info
    • AD Summary report also has time settings
  • Check Replication and DC Health (from elevated prompt)
    • dcdiag /v /c /d /e /s:DC_Name
    • dcdiag /e /test:DNS /DNSAll
    • repadmin /queue
    • repadmin /replsummary
    • repadmin /showrepl
    • Get-ADReplicationFailure -Target contoso.com -Scope Domain
  • Harden config

Active Directory

  • Run Powershell AD Summary Report
    • Identify FSMO holders
    • Identify DFL and FFL
    • Is the AD Recycle Bin enabled?
    • Are there Trusts in place
    • Check site links and replication in a multi-site environment
  • Take an AD Explorer snapshot
    • Snapshot comparison can be done in the future
  • Check tombstone lifetime (if blank value is 60)
    • (Get-ADObject -Identity “CN=Directory Service,CN=Windows NT,CN=Services,$((Get-ADRootDSE).configurationNamingContext)” -Properties tombstoneLifetime).tombstoneLifetime
  • Further check on trusts and the relationship mapping
    • Invoke-MapDomainTrust recursively maps all reachable domain and forests trusts
  • Audit service accounts and remove unused ones
    • Find accounts that have never logged on
      • Get-ADUser -Filter {(lastlogontimestamp -notlike "*") -and (enabled -eq $true)} | Select Name,DistinguishedName
    • Audit accounts with non-expiring passwords Get-ADUser -filter * -properties Name, PasswordNeverExpires | where { $_.passwordNeverExpires -eq "true" } | where {$_.enabled -eq "true"} | fl Name,SamAccountName,PasswordNeverExpires
    • Set long (20+ char) passwords on used service accounts - prevents Kerbroasting
    • Consider using Group Managed Service Accounts
      • Find existing Managed Service Accounts: Get-ADServiceAccount -Filter * -Properties *
  • Find accounts with AdminCount set to “1”
    • Get-ADUser -filter {AdminCount -eq 1} -Properties * | select Name,DistinguishedName,LastLogonDate,Enabled,PasswordNeverExpires,MemberOf
  • Search AD for interesting accounts and groups
    • Get-ADUser -Filter {name -like "*adm*"} -Properties name | Select-Object Name
    • Get-ADGroup -Filter {name -like "*adm*"} -Properties name | Select-Object Name
  • Audit Group membership
    • Schema Admins should be empty, Enterprise Admins has Administrator
      • Get-NetGroup "Enterprise Admins" | Get-NetGroupMember | Select GroupName,MemberName
      • Get-NetGroup "Schema Admins" | Get-NetGroupMember | Select GroupName,MemberName
      • Get-NetGroup "Domain Admins" | Get-NetGroupMember | Select GroupName,MemberName
      • Get-NetGroup "Administrators" | Get-NetGroupMember | Select GroupName,MemberName
      • Get-NetGroup "Backup Operators" | Get-NetGroupMember | Select GroupName,MemberName
      • Get-NetGroup "Account Operators" | Get-NetGroupMember | Select GroupName,MemberName
      • Get-NetGroup "DNS Admins" | Get-NetGroupMember | Select GroupName,MemberName
      • Get-NetGroup "Print Operators" | Get-NetGroupMember | Select GroupName,MemberName
      • Get-NetGroup "Server Operators" | Get-NetGroupMember | Select GroupName,MemberName
      • Get-NetGroup "Group Policy Creator Owners" | Get-NetGroupMember | Select GroupName,MemberName
      • Get-NetGroup "Protected Users" | Get-NetGroupMember | Select GroupName,MemberName
  • Eventlog
    • Ideally implement some form of automated log parsing and alerting
    • Monitor Group Membership, Account creation
    • Requires the correct audit settings
  • AD Account cleanup
    • Remove accounts that are no longer being used (LastLogonTime)
    • Find accounts where password is older than the password policy deadline. This script will show pwd expiration date for all users.
      • Get-ADUser -filter {Enabled -eq $True -and PasswordNeverExpires -eq $False -and PasswordLastSet -gt 0 } ` -Properties "Name", "msDS-UserPasswordExpiryTimeComputed" | sort msDS-UserPasswordExpiryTimeComputed | Select-Object -Property "Name", ` @{Name = "PasswordExpiry"; Expression = {[datetime]::FromFileTime($_."msDS-UserPasswordExpiryTimeComputed").tolongdatestring() }}
  • Run ADACLScanner to view CSV of AD ACL permissions and create baseline for later on
    • Are there any delegated admins?
    • Compare to results of previous run or download template of default permissions
      • Compare to default “Each NC root combined” template to see permission differences for AdminSDHolder and every AD partition
    • Also run ACLight, it will focus on finding privileged access
  • Find accounts with the SIDHistory attribute set
    • Get-ADUser -Filter * -Property sIDHistory | Where sIDHistory | Select-Object name, sIDHistory -ExpandProperty sidHistory | Format-Table name, sIDHistory –AutoSize
    • Powershell module for working with SID History
      • Copy to PS Modules Dir, Import-Module sidhistory, Export-SIDMapping
    • Since the user’s SID changes when the new account is created, the old SID needs to map to the new one. When a user in Domain A is migrated to Domain B, a new user account is created in DomainB and DomainA user’s SID is added to DomainB’s user account’s SID History attribute. This ensures that DomainB user can still access resources in DomainA.
  • Check for computers with Unconstrained Delegation
    • Use Search-KerbDelegatedAccounts.ps1 from Github
    • Get-ADcomputer -Filter {(TrustedForDelegation -eq $True) -AND (PrimaryGroupID -eq 515)} -Properties TrustedForDelegation,TrustedToAuthForDelegation,servicePrincipalName,Description
  • Consider adding Admin accounts to Protected Users.
    • Place user accounts in the group - but until thoroughly tested do not add all Administrative accounts so you don’t lock out all accounts.
      • All DCs must be 2008 or later
    • This group blocks its members from using Kerberos delegation, blocks NTLM, forces AES, disables cached logon, and more.
      • If not, at least check the box “Account is sensitive and cannot be delegated”. This ensures that an account’s credentials cannot be forwarded to other computers or services on the network by a trusted application.

DNS

  • dnscmd /enumzones
    • Check for proper replication partition placement of each zone
      • Domain zone in Domain Partition
      • _msdcs.Domain.com in Forest Partition
  • Check Forwarders and Root Hints
  • Check for proper registration of NS and SRV records and cleanup old stale records
    • Get-DnsServerResourceRecord -RRType SRV -ZoneName "contoso.com" | sort Hostname | ft -AutoSize | Out-File -filepath C:\DNS_Records.txt -NoClobber -Width 200
    • Get-DnsServerResourceRecord -RRType SRV -ZoneName "_msdcs.contoso.com" | sort Hostname | ft -AutoSize | Out-File -filepath C:\DNS_Records.txt -Append -Width 200
    • Get-DnsServerResourceRecord -RRType NS -ZoneName "contoso.com" | sort Hostname | ft -AutoSize | Out-File -filepath C:\DNS_Records.txt -Append -Width 200
    • Get-DnsServerResourceRecord -RRType NS -ZoneName "_msdcs.contoso.com" | sort Hostname | ft -AutoSize | Out-File -filepath C:\DNS_Records.txt -Append -Width 200
  • Check if scavenging enabled on each zone
    • Only configure on a single server
    • dnscmd <DCName> /info
  • Check if Secure updates are enabled to other Non-AD DNS servers
  • External DNS Check
  • NetBIOS and WINS setup
    • Either disable NetBIOS or have a WINS server to prevent broadcasts
    • Who is Browse Master? Start Computer Browser service on a server on each subnet otherwise a workstation will win election
    • Disable NetBIOS through DHCP (workstations) or with a script (servers)

Misc Checks

  • Look into disabling legacy protocols: LLMNR, WDigest, WPAD, LM & NTLM auth
  • Are there other servers that need secured: Certificate servers, Azure AD connect server, password vaults
    • Is Azure AD Connect up-to-date?
  • Deploy LAPS or make local admin passwords unique and not based on a pattern
  • Set separate auditing policies in Default Domain and Default Domain Controller Group Policies
  • What is the Powershell execution policy set to?
    • Get-ExecutionPolicy
    • Enable Powershell Module Logging
      • Computer Configuration > Policies > Administrative Templates > Windows Components > Windows PowerShell
  • SPN scanning
  • Reset your KRBTGT password using scripts available from Microsoft
    • Prevents Golden Ticket attack
    • ONLY use Microsoft’s scripts for this, or you could break your domain for 10+ hours
    • Password has to be changed twice to ensure there is no password history maintained
    • Microsoft states that resetting the KRBTGT account password is only supported in a Windows Server 2008 Domain Functional Level (DFL) or higher. When the DFL is raised from 2003 to 2008 (or higher), the KRBTGT account password is changed automatically
  • Disable NetBIOS (insecure legacy protocol)
    • has to be done for each network adapter or through DHCP settings
  • Blocking Net Session Enumeration with NetCease
    • Authenticated Users are granted NetSessionEnumeration privileges by default, allowing any user to see who has an established session on another machine in the Domain, allowing targeting. This tool removes this permission from Authenticated Users. If you run this, capture BloodHound info before and after
  • Hyper-V - enable shielded VMs for DCs
  • Disable SMBv1, enable SMBv2 and v3
    • Can use NMAP SMB scripts to discover machine info over the network
    • SMBv2 was introduced with Server 2008, SMBv1 still needed for XP and 2003
    • Disable manually or with Group Policy
      • Use Wireshark to listen for any SMB traffic
        • tcp.port eq 445 or tcp.port eq 139
        • don’t go by column in capture window, must look inside packet for version details
      • You can audit SMBv1 in Windows 10, Windows Server 2016, and Windows Server 2012 R2 via an update. That way you can configure your Windows Servers to see if disabling SMB1 would break someone:
        • Set-SmbServerConfiguration –AuditSmb1Access $true
          • Then just examine the SMBServer\Audit event log on the systems
      • Need to set keys for both client and server
  • Applocker - Out of the box application whitelisting. Can start in audit mode. Austrailian Cyber Defense Hardening Win10 doc has a good starting rule base.
  • If you have remote logging and alerting enabled consider running Sysmon on remote endpoints to capture more activity
  • Bitlocker
  • Have AD admin, Server admin, and workstation admin groups
  • Separate Admin accounts from user accounts (Admins get 2 accounts)
    • Does it need to be a Domain Admin all the time? Maybe just have it as a member of a Server Admin group
    • Be mindful of where you login - you can restrict where an account can logon
      • Invoke-UserHunter (PowerSploit) enumerates sessions and logged in users and matches the result with a list of targeted users
        • See what other workstations Domain Admins have been logging into. Uses NetSessionEnumeration in the background
      • Separate physical workstation is best but virtual can work also (PAW)
        • If virtual
          • login to workstation as user, run a local VM for user applications, RDP from host to servers as AD admin
        • If physical
          • they are not admins on those workstations
          • no running agents, manual patching
          • restrictive firewall policy - only admin traffic
  • The workstation is the security boundary
    • Implement Device Guard and Credential Guard
      • Needs compatible hardware
      • Device Guard is a group of key features, designed to harden a computer system against malware. Its focus is preventing malicious code from running by ensuring only known good code can run. Can be difficult to implement, only for mission critical servers
      • Credential Guard is a specific feature that is not part of Device Guard that aims to isolate and harden key system and user secrets against compromise, helping to minimize the impact and breadth of a Pass the Hash style attack. Isolates LSASS.
      • Check if these are running by launching MSINFO32.EXE and looking under System Summary
  • Implement AD Health Check emails

TOOLS

  • Bloodhound audit
    • Allows collecting information on privileges, AD ACLs, logged-on sessions, group membership, GPO rights assignment
    • Map paths of privilege escalation
    • Running NetCease above will help mitigate
  • PowerSploit Recon Scripts
  • responder.py - Responder an LLMNR, NBT-NS and MDNS poisoner. It allows you to MITM SMB requests
  • Mimikatz
    • Download to users workstation, does AV detect it?
  • Most organizations use Group Policy to add an Active Directory group to a local group on computers (typically the Administrators group).
    • Using PowerView, we can easily discover the AD groups that have admin rights on workstations and servers (which is the typical use case).
    • Get-NetGPOGroup
  • We can also use PowerView to identify what AD groups have admin rights on computers by OU.
    • Find-GPOComputerAdmin -OUName "OU=Workstation,DC=lab,DC=contoso,DC=com"
  • PowerView provides the ability to to search AD permissions for interesting rights.
    • Invoke-AclScanner -ResolveGUIDs -ADSpath 'OU=Accounts,DC=contoso,DC=com' | where {$_.ActiveDirectoryRights -eq 'GenericAll'}
    • Invoke-AclScanner -ResolveGUIDs -ADSpath 'OU=Accounts,DC=contoso,DC=com' | where {$_.ActiveDirectoryRights -eq 'GenericWrite'}
    • Invoke-AclScanner -ResolveGUIDs -ADSpath 'OU=Accounts,DC=contoso,DC=com' | where {$_.ActiveDirectoryRights -eq 'WriteDACL'}
    • Invoke-AclScanner -ResolveGUIDs -ADSpath 'OU=Accounts,DC=contoso,DC=com' | where {$_.ActiveDirectoryRights -eq 'WriteOwner'}
  • An attacker is most interested in permissions that provide privileged actions. These ACLs include:
    • Replicating Directory Changes
    • GenericAll: GenericAll = Full Control
    • GenericWrite: Provides write access to all properties.
    • WriteDACL: Provides the ability to modify security on an object which can lead to Full Control of the object.
    • WriteOwner:: Provides the ability to take ownership of an object.
    • Extended Right: This is an interesting one because if provides additional rights beyond the obvious.