ActiveDirectory/Find-ADVulnerabilities.ps1

function Find-ADVulnerabilities {
    <#
    .SYNOPSIS
        Detects common Active Directory vulnerabilities and misconfigurations
    .DESCRIPTION
        Scans for AD vulnerabilities including Kerberoasting, AS-REP Roasting,
        weak permissions, and dangerous configurations
    .PARAMETER CheckKerberoasting
        Check for Kerberoastable accounts
    .PARAMETER CheckASREPRoasting
        Check for AS-REP Roastable accounts
    .PARAMETER CheckWeakPermissions
        Check for weak ACL permissions
    .PARAMETER Domain
        Target domain (default: current domain)
    .EXAMPLE
        Find-ADVulnerabilities -CheckKerberoasting -CheckASREPRoasting
        Find-ADVulnerabilities -CheckWeakPermissions -Domain "contoso.com"
    .OUTPUTS
        PSCustomObject with vulnerability findings
    #>

    
    [CmdletBinding()]
    param(
        [Parameter()]
        [switch]$CheckKerberoasting,
        
        [Parameter()]
        [switch]$CheckASREPRoasting,
        
        [Parameter()]
        [switch]$CheckWeakPermissions,
        
        [Parameter()]
        [string]$Domain
    )
    
    begin {
        Write-Host "=== ACTIVE DIRECTORY VULNERABILITY SCAN ===" -ForegroundColor Cyan
        Write-Host "Start Time: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')" -ForegroundColor Yellow
        
        # Check if ActiveDirectory module is available
        if (-not (Get-Module -ListAvailable -Name ActiveDirectory)) {
            Write-Warning "ActiveDirectory module not found. Install RSAT tools."
            Write-Host "To install: Add-WindowsCapability -Online -Name Rsat.ActiveDirectory.DS-LDS.Tools~~~~0.0.1.0" -ForegroundColor Yellow
            throw "ActiveDirectory module required"
        }
        
        Import-Module ActiveDirectory -ErrorAction Stop
        
        # If no domain specified, use current
        if (-not $Domain) {
            $Domain = (Get-ADDomain).DNSRoot
        }
        
        Write-Host "Target Domain: $Domain" -ForegroundColor Yellow
        
        $results = [PSCustomObject]@{
            ScanDate = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
            Domain = $Domain
            Vulnerabilities = @{
                Kerberoasting = @()
                ASREPRoasting = @()
                WeakPermissions = @()
                DangerousConfigurations = @()
            }
            Summary = @{
                TotalVulnerabilities = 0
                CriticalFindings = 0
                HighFindings = 0
                MediumFindings = 0
            }
            Recommendations = @()
        }
    }
    
    process {
        try {
            # 1. Check for Kerberoastable accounts
            if ($CheckKerberoasting) {
                Write-Host "`n[1/3] Checking for Kerberoastable accounts..." -ForegroundColor Cyan
                
                try {
                    # Find accounts with SPN set (@() wraps $null so .Count is safe under strict mode)
                    $kerberoastableUsers = @(Get-ADUser -Filter {ServicePrincipalName -like "*"} -Properties ServicePrincipalName, PasswordLastSet, Enabled, AdminCount -Server $Domain)
                    
                    foreach ($user in $kerberoastableUsers) {
                        $severity = 'Medium'
                        
                        # Elevated severity for privileged accounts
                        if ($user.AdminCount -eq 1) {
                            $severity = 'Critical'
                            $results.Summary.CriticalFindings++
                        } else {
                            $results.Summary.MediumFindings++
                        }
                        
                        # Check password age
                        $passwordAge = if ($user.PasswordLastSet) {
                            (New-TimeSpan -Start $user.PasswordLastSet -End (Get-Date)).Days
                        } else {
                            "Never changed"
                        }
                        
                        $results.Vulnerabilities.Kerberoasting += [PSCustomObject]@{
                            Severity = $severity
                            Username = $user.SamAccountName
                            DisplayName = $user.Name
                            Enabled = $user.Enabled
                            IsPrivileged = ($user.AdminCount -eq 1)
                            SPNs = $user.ServicePrincipalName -join ', '
                            PasswordAge = $passwordAge
                            Description = "Account has SPN set and is vulnerable to Kerberoasting attack"
                        }
                        
                        Write-Host " Found: $($user.SamAccountName) - Severity: $severity" -ForegroundColor $(
                            if ($severity -eq 'Critical') { 'Red' } else { 'Yellow' }
                        )
                    }
                    
                    if ($kerberoastableUsers.Count -eq 0) {
                        Write-Host " No Kerberoastable accounts found" -ForegroundColor Green
                    } else {
                        $results.Recommendations += "Review and remove unnecessary SPNs from accounts"
                        $results.Recommendations += "Use long, complex passwords for accounts with SPNs"
                        $results.Recommendations += "Consider using Group Managed Service Accounts (gMSA)"
                    }
                }
                catch {
                    Write-Warning "Error checking Kerberoasting: $_"
                }
            }
            
            # 2. Check for AS-REP Roastable accounts
            if ($CheckASREPRoasting) {
                Write-Host "`n[2/3] Checking for AS-REP Roastable accounts..." -ForegroundColor Cyan
                
                try {
                    # Find accounts with "Do not require Kerberos preauthentication" (@() wraps $null so .Count is safe under strict mode)
                    $asrepUsers = @(Get-ADUser -Filter {DoesNotRequirePreAuth -eq $true} -Properties DoesNotRequirePreAuth, PasswordLastSet, Enabled, AdminCount -Server $Domain)
                    
                    foreach ($user in $asrepUsers) {
                        $severity = 'High'
                        
                        if ($user.AdminCount -eq 1) {
                            $severity = 'Critical'
                            $results.Summary.CriticalFindings++
                        } else {
                            $results.Summary.HighFindings++
                        }
                        
                        $passwordAge = if ($user.PasswordLastSet) {
                            (New-TimeSpan -Start $user.PasswordLastSet -End (Get-Date)).Days
                        } else {
                            "Never changed"
                        }
                        
                        $results.Vulnerabilities.ASREPRoasting += [PSCustomObject]@{
                            Severity = $severity
                            Username = $user.SamAccountName
                            DisplayName = $user.Name
                            Enabled = $user.Enabled
                            IsPrivileged = ($user.AdminCount -eq 1)
                            PasswordAge = $passwordAge
                            Description = "Account does not require Kerberos pre-authentication (AS-REP Roasting)"
                        }
                        
                        Write-Host " Found: $($user.SamAccountName) - Severity: $severity" -ForegroundColor $(
                            if ($severity -eq 'Critical') { 'Red' } else { 'Yellow' }
                        )
                    }
                    
                    if ($asrepUsers.Count -eq 0) {
                        Write-Host " No AS-REP Roastable accounts found" -ForegroundColor Green
                    } else {
                        $results.Recommendations += "Enable Kerberos pre-authentication for all accounts"
                        $results.Recommendations += "Review accounts with DoesNotRequirePreAuth enabled"
                    }
                }
                catch {
                    Write-Warning "Error checking AS-REP Roasting: $_"
                }
            }
            
            # 3. Check for weak permissions and dangerous configurations
            if ($CheckWeakPermissions) {
                Write-Host "`n[3/3] Checking for weak permissions..." -ForegroundColor Cyan
                
                try {
                    # Check for users with "Password Never Expires"
                    Write-Host " Checking password policies..." -ForegroundColor Yellow
                    $neverExpireUsers = @(Get-ADUser -Filter {PasswordNeverExpires -eq $true -and Enabled -eq $true} -Properties PasswordNeverExpires, AdminCount -Server $Domain)
                    
                    foreach ($user in $neverExpireUsers) {
                        $severity = if ($user.AdminCount -eq 1) { 'High' } else { 'Medium' }
                        
                        if ($severity -eq 'High') {
                            $results.Summary.HighFindings++
                        } else {
                            $results.Summary.MediumFindings++
                        }
                        
                        $results.Vulnerabilities.WeakPermissions += [PSCustomObject]@{
                            Severity = $severity
                            Type = 'Password Policy'
                            Object = $user.SamAccountName
                            Issue = 'Password Never Expires'
                            IsPrivileged = ($user.AdminCount -eq 1)
                            Description = "Account password is set to never expire"
                        }
                    }
                    
                    Write-Host " Found $($neverExpireUsers.Count) accounts with non-expiring passwords" -ForegroundColor $(
                        if ($neverExpireUsers.Count -gt 0) { 'Yellow' } else { 'Green' }
                    )
                    
                    # Check for disabled password complexity
                    Write-Host " Checking domain password policy..." -ForegroundColor Yellow
                    $domainPolicy = Get-ADDefaultDomainPasswordPolicy -Server $Domain
                    
                    if ($domainPolicy.ComplexityEnabled -eq $false) {
                        $results.Vulnerabilities.DangerousConfigurations += [PSCustomObject]@{
                            Severity = 'Critical'
                            Type = 'Password Policy'
                            Issue = 'Password Complexity Disabled'
                            Description = 'Domain password policy does not require complex passwords'
                        }
                        $results.Summary.CriticalFindings++
                        Write-Host " [!] Password complexity is DISABLED" -ForegroundColor Red
                    }
                    
                    if ($domainPolicy.MinPasswordLength -lt 12) {
                        $results.Vulnerabilities.DangerousConfigurations += [PSCustomObject]@{
                            Severity = 'High'
                            Type = 'Password Policy'
                            Issue = "Minimum Password Length: $($domainPolicy.MinPasswordLength)"
                            Description = 'Minimum password length is less than 12 characters'
                        }
                        $results.Summary.HighFindings++
                        Write-Host " [!] Minimum password length is only $($domainPolicy.MinPasswordLength) characters" -ForegroundColor Yellow
                    }
                    
                    # Check for accounts with reversible encryption
                    Write-Host " Checking for reversible encryption..." -ForegroundColor Yellow
                    $reversibleUsers = Get-ADUser -Filter {AllowReversiblePasswordEncryption -eq $true} -Properties AllowReversiblePasswordEncryption -Server $Domain
                    
                    foreach ($user in $reversibleUsers) {
                        $results.Vulnerabilities.DangerousConfigurations += [PSCustomObject]@{
                            Severity = 'Critical'
                            Type = 'Password Storage'
                            Object = $user.SamAccountName
                            Issue = 'Reversible Encryption Enabled'
                            Description = 'Password stored with reversible encryption (plaintext equivalent)'
                        }
                        $results.Summary.CriticalFindings++
                        Write-Host " [!] $($user.SamAccountName) has reversible encryption enabled" -ForegroundColor Red
                    }
                    
                    if ($results.Recommendations -notcontains "Enforce strong password policies") {
                        $results.Recommendations += "Enforce strong password policies (min 12 chars, complexity enabled)"
                        $results.Recommendations += "Regular password rotation for privileged accounts"
                        $results.Recommendations += "Disable reversible encryption for all accounts"
                    }
                }
                catch {
                    Write-Warning "Error checking weak permissions: $_"
                }
            }
            
            # Calculate total vulnerabilities
            $results.Summary.TotalVulnerabilities = $results.Summary.CriticalFindings + 
                                                   $results.Summary.HighFindings + 
                                                   $results.Summary.MediumFindings
            
        }
        catch {
            Write-Error "Error during AD vulnerability scan: $_"
            throw
        }
    }
    
    end {
        Write-Host "`n=== SCAN COMPLETE ===" -ForegroundColor Green
        
        Write-Host "`nVulnerability Summary:" -ForegroundColor Cyan
        Write-Host " Total Vulnerabilities: $($results.Summary.TotalVulnerabilities)" -ForegroundColor White
        Write-Host " Critical: $($results.Summary.CriticalFindings)" -ForegroundColor Red
        Write-Host " High: $($results.Summary.HighFindings)" -ForegroundColor Yellow
        Write-Host " Medium: $($results.Summary.MediumFindings)" -ForegroundColor Yellow
        
        if ($results.Vulnerabilities.Kerberoasting.Count -gt 0) {
            Write-Host "`nKerberoastable Accounts: $($results.Vulnerabilities.Kerberoasting.Count)" -ForegroundColor Yellow
            $results.Vulnerabilities.Kerberoasting | Select-Object -First 5 | ForEach-Object {
                Write-Host " - $($_.Username) [$($_.Severity)]" -ForegroundColor $(
                    if ($_.Severity -eq 'Critical') { 'Red' } else { 'Yellow' }
                )
            }
        }
        
        if ($results.Vulnerabilities.ASREPRoasting.Count -gt 0) {
            Write-Host "`nAS-REP Roastable Accounts: $($results.Vulnerabilities.ASREPRoasting.Count)" -ForegroundColor Yellow
            $results.Vulnerabilities.ASREPRoasting | Select-Object -First 5 | ForEach-Object {
                Write-Host " - $($_.Username) [$($_.Severity)]" -ForegroundColor $(
                    if ($_.Severity -eq 'Critical') { 'Red' } else { 'Yellow' }
                )
            }
        }
        
        if ($results.Recommendations.Count -gt 0) {
            Write-Host "`nRecommendations:" -ForegroundColor Cyan
            $results.Recommendations | Select-Object -Unique | ForEach-Object {
                Write-Host " ! $_" -ForegroundColor Yellow
            }
        }
        
        Write-Host "`nNote: This scan requires domain connectivity and RSAT tools" -ForegroundColor Gray
        
        return $results
    }
}