Public/Invoke-Locksmith2.ps1
|
function Invoke-Locksmith2 { <# .SYNOPSIS Performs comprehensive AD CS security audit scanning for known ESC vulnerabilities. .DESCRIPTION Invoke-Locksmith2 audits Active Directory Certificate Services (AD CS) infrastructure for security misconfigurations documented as ESC (Escalation) techniques. It scans: - Certificate templates (ESC1, ESC2, ESC3, ESC4, ESC9) - Certification Authorities (ESC6, ESC7a, ESC7m, ESC11, ESC16) - PKI container objects (ESC5) The function initializes four module-level stores: - PrincipalStore: Caches resolved SIDs and NTAccount principals - AdcsObjectStore: Stores all AD CS objects (templates, CAs, OIDs, etc.) - DomainStore: Caches domain information - IssueStore: Collects discovered vulnerabilities by technique Results are returned as structured LS2Issue objects containing vulnerability details, affected principals, and PowerShell remediation scripts. .PARAMETER Forest Fully qualified domain name of the forest/domain/domain controller to audit. If not specified, prompts interactively for the target forest. .PARAMETER Credential PSCredential object for authenticating to the target forest. If not specified, prompts interactively for username and password. Username should be in NTAccount format (DOMAIN\username). .PARAMETER SkipVersionCheck Skips checking for module updates from PowerShell Gallery. Use when running in air-gapped environments or to speed up execution. .PARAMETER SkipPowerShellCheck Skips validation and remediation of PowerShell environment settings. Use if you've already validated PowerShell profile and encoding settings. .PARAMETER Mode Specifies the output mode for displaying scan results. If not specified, returns LS2Issue objects to the pipeline without formatting. - Mode 0: Identify issues, output to console in table format - Mode 1: Identify issues and fixes, output to console in list format .PARAMETER SkipForestCheck Reserved for future use. Currently not implemented. .PARAMETER ExpandGroups Expands issues where the IdentityReference is a group into individual issues for each direct member of the group. This allows attribution of vulnerabilities to individual users rather than just showing group permissions. .PARAMETER Rescan Forces a fresh vulnerability scan even if IssueStore is already populated. Clears and regenerates the IssueStore with current AD CS configuration. .INPUTS None. This function does not accept pipeline input. .OUTPUTS Hashtable Returns four hashtables: - PrincipalStore: All resolved principals by SID - DomainStore: All domains in the audited forest - AdcsObjectStore: All AD CS objects - IssueStore: All discovered vulnerabilities grouped by technique .EXAMPLE Invoke-Locksmith2 Runs interactive audit and returns LS2Issue objects to the pipeline. .EXAMPLE $cred = Get-Credential CONTOSO\admin Invoke-Locksmith2 -Forest 'dc01.contoso.com' -Credential $cred Audits contoso.com forest and returns LS2Issue objects to the pipeline. .EXAMPLE Invoke-Locksmith2 -Forest 'contoso.com' -Credential $cred -SkipPowerShellCheck Runs audit skipping PowerShell environment validation. .EXAMPLE Invoke-Locksmith2 -Mode 0 Runs audit and displays results in table format (default behavior). .EXAMPLE Invoke-Locksmith2 -Mode 1 Runs audit and displays results in list format with fix scripts. .EXAMPLE Invoke-Locksmith2 -ExpandGroups Runs audit and expands group issues into individual per-member issues. .LINK https://github.com/jakehildreth/Locksmith2 .LINK Find-LS2VulnerableCA .LINK Find-LS2VulnerableTemplate .LINK Find-LS2VulnerableObject .LINK Get-LS2Stores .NOTES Author: Jake Hildreth (@jakehildreth) Requires PowerShell 5.1 or later Requires appropriate AD permissions to read Public Key Services container #> [CmdletBinding()] param ( [string]$Forest, [System.Management.Automation.PSCredential]$Credential, [ValidateSet(0, 1)] [Nullable[int]]$Mode, [switch]$SkipVersionCheck, [switch]$SkipPowerShellCheck, [switch]$SkipForestCheck, [switch]$ExpandGroups, [switch]$Rescan ) #requires -Version 5.1 Show-Logo if (-not $SkipPowerShellCheck) { Test-PowerShellEnvironment | Repair-PowerShellEnvironment | Out-Null } Write-Verbose "Starting Locksmith2 AD CS security audit..." # Initialize and optionally rescan # Only pass Forest/Credential if explicitly provided by user $initParams = @{} if ($PSBoundParameters.ContainsKey('Forest')) { $initParams['Forest'] = $Forest } if ($PSBoundParameters.ContainsKey('Credential')) { $initParams['Credential'] = $Credential } if ($Rescan) { $initParams['Rescan'] = $true } $initResult = Initialize-LS2Scan @initParams if (-not $initResult) { Write-Error "Failed to initialize scan. Verify credentials and forest connectivity." return } Write-Verbose "`nScan complete. Issue summary:" $techniques = @( 'ESC1', 'ESC2', 'ESC3c1', 'ESC3c2', 'ESC4a', 'ESC4o', 'ESC5a', 'ESC5o', 'ESC6', 'ESC7a', 'ESC7m', 'ESC9', 'ESC11', 'ESC16' ) foreach ($technique in $techniques) { $issueCount = Get-IssueCount -Technique $technique Write-Verbose " $($technique): $issueCount issue(s)" } # Get all flattened issues $allIssues = Get-FlattenedIssues # Expand groups if requested if ($ExpandGroups) { Write-Verbose "Expanding group memberships into individual issues..." $allIssues = $allIssues | ForEach-Object { Expand-IssueByGroup $_ } Write-Verbose "Expansion complete. Total issues: $($allIssues.Count)" } # Output based on whether Mode was specified if ($PSBoundParameters.ContainsKey('Mode')) { # Display issues in console using specified mode Show-IssueReport -Issues $allIssues -Mode $Mode } else { # Return LS2Issue objects to pipeline $allIssues } } |