@@ -421,10 +421,9 @@ function Find-ESC3Condition2 {
421
421
$ADCSObjects | Where-Object {
422
422
($_.objectClass -eq ' pKICertificateTemplate' ) -and
423
423
($_.pkiExtendedKeyUsage -match $ClientAuthEKU ) -and
424
- ($_ .' msPKI-Certificate-Name-Flag' -band 1 ) -and
425
424
! ($_ .' msPKI-Enrollment-Flag' -band 2 ) -and
426
- ($_ .' msPKI-RA-Application-Policies' -eq ' 1.3.6.1.4.1.311.20.2.1' ) -and
427
- ( ( $_ .' msPKI-RA-Signature' -eq 1 ) )
425
+ ($_ .' msPKI-RA-Application-Policies' -match ' 1.3.6.1.4.1.311.20.2.1' ) -and
426
+ ($_ .' msPKI-RA-Signature' -eq 1 )
428
427
} | ForEach-Object {
429
428
foreach ($entry in $_.nTSecurityDescriptor.Access ) {
430
429
$Principal = New-Object System.Security.Principal.NTAccount($entry.IdentityReference )
@@ -1038,7 +1037,7 @@ function Format-Result {
1038
1037
ESC1 = ' ESC1 - Vulnerable Certificate Template - Authentication'
1039
1038
ESC2 = ' ESC2 - Vulnerable Certificate Template - Subordinate CA'
1040
1039
ESC3 = ' ESC3 - Vulnerable Certificate Template - Enrollment Agent'
1041
- ESC4 = ' ESC4 - Vulnerable Access Control - Certifcate Template'
1040
+ ESC4 = ' ESC4 - Vulnerable Access Control - Certificate Template'
1042
1041
ESC5 = ' ESC5 - Vulnerable Access Control - PKI Object'
1043
1042
ESC6 = ' ESC6 - EDITF_ATTRIBUTESUBJECTALTNAME2 Flag Enabled'
1044
1043
ESC8 = ' ESC8 - HTTP/S Enrollment Enabled'
@@ -1629,7 +1628,7 @@ function Invoke-Scans {
1629
1628
1630
1629
. EXAMPLE
1631
1630
# Perform all scans
1632
- Invoke-Scans
1631
+ Invoke-Scans
1633
1632
1634
1633
. EXAMPLE
1635
1634
# Perform only the 'Auditing' and 'ESC1' scans
@@ -1641,6 +1640,8 @@ function Invoke-Scans {
1641
1640
#>
1642
1641
1643
1642
[CmdletBinding ()]
1643
+ [OutputType ([hashtable ])]
1644
+ [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute (' PSUseSingularNouns' , ' Invoke-Scans' , Justification = ' Performing multiple scans.' )]
1644
1645
param (
1645
1646
# Could split Scans and PromptMe into separate parameter sets.
1646
1647
[Parameter ()]
@@ -1974,17 +1975,35 @@ function Set-AdditionalCAProperty {
1974
1975
1975
1976
begin {
1976
1977
$CAEnrollmentEndpoint = @ ()
1977
- $code = @"
1978
- using System.Net;
1979
- using System.Security.Cryptography.X509Certificates;
1980
- public class TrustAllCertsPolicy : ICertificatePolicy {
1981
- public bool CheckValidationResult(ServicePoint srvPoint, X509Certificate certificate, WebRequest request, int certificateProblem) {
1982
- return true;
1983
- }
1984
- }
1978
+ if (-not ([System.Management.Automation.PSTypeName ]' TrustAllCertsPolicy' ) ) {
1979
+ if ($PSVersionTable.PSEdition -eq ' Desktop' ) {
1980
+ $code = @"
1981
+ using System.Net;
1982
+ using System.Security.Cryptography.X509Certificates;
1983
+ public class TrustAllCertsPolicy : ICertificatePolicy {
1984
+ public bool CheckValidationResult(ServicePoint srvPoint, X509Certificate certificate, WebRequest request, int certificateProblem) {
1985
+ return true;
1986
+ }
1987
+ }
1988
+ "@
1989
+ Add-Type - TypeDefinition $code - Language CSharp
1990
+ [System.Net.ServicePointManager ]::CertificatePolicy = New-Object TrustAllCertsPolicy
1991
+ }
1992
+ else {
1993
+ Add-Type @"
1994
+ using System.Net;
1995
+ using System.Security.Cryptography.X509Certificates;
1996
+ using System.Net.Security;
1997
+ public class TrustAllCertsPolicy {
1998
+ public static bool TrustAllCerts(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) {
1999
+ return true;
2000
+ }
2001
+ }
1985
2002
"@
1986
- Add-Type - TypeDefinition $code - Language CSharp
1987
- [System.Net.ServicePointManager ]::CertificatePolicy = New-Object TrustAllCertsPolicy
2003
+ # Set the ServerCertificateValidationCallback
2004
+ [System.Net.ServicePointManager ]::ServerCertificateValidationCallback = [TrustAllCertsPolicy ]::TrustAllCerts
2005
+ }
2006
+ }
1988
2007
}
1989
2008
1990
2009
process {
@@ -2010,7 +2029,7 @@ public class TrustAllCertsPolicy : ICertificatePolicy {
2010
2029
try {
2011
2030
$FullURL = " https$URL "
2012
2031
$Request = [System.Net.WebRequest ]::Create($FullURL )
2013
-
2032
+
2014
2033
$Request.GetResponse () | Out-Null
2015
2034
$CAEnrollmentEndpoint += @ {
2016
2035
' URL' = $FullURL
@@ -2047,7 +2066,7 @@ public class TrustAllCertsPolicy : ICertificatePolicy {
2047
2066
$CAHostFQDN = (Get-ADObject - Filter { (Name -eq $CAHostName ) -and (objectclass -eq ' computer' ) } - Properties DnsHostname - Server $ForestGC ).DnsHostname
2048
2067
}
2049
2068
$ping = Test-Connection - ComputerName $CAHostFQDN - Quiet - Count 1
2050
- if ($ping ) {
2069
+ if ($ping ) {
2051
2070
try {
2052
2071
if ($Credential ) {
2053
2072
$CertutilAudit = Invoke-Command - ComputerName $CAHostname - Credential $Credential - ScriptBlock { param ($CAFullName ); certutil - config $CAFullName - getreg CA\AuditFilter } - ArgumentList $CAFullName
@@ -2110,6 +2129,7 @@ public class TrustAllCertsPolicy : ICertificatePolicy {
2110
2129
}
2111
2130
2112
2131
function Set-Severity {
2132
+ [OutputType ([string ])]
2113
2133
[CmdletBinding ()]
2114
2134
param (
2115
2135
[Parameter (Mandatory = $true )]
@@ -2145,6 +2165,44 @@ function Set-Severity {
2145
2165
}
2146
2166
}
2147
2167
2168
+ function Show-LocksmithLogo {
2169
+ Write-Host ' %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%'
2170
+ Write-Host ' %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%'
2171
+ Write-Host ' %%%%%%%%%%%%%%%%%#+==============#%%%%%%%%%%%%%%%%%'
2172
+ Write-Host ' %%%%%%%%%%%%%%#=====================#%%%%%%%%%%%%%%'
2173
+ Write-Host ' %%%%%%%%%%%%#=========================#%%%%%%%%%%%%'
2174
+ Write-Host ' %%%%%%%%%%%=============================%%%%%%%%%%%'
2175
+ Write-Host ' %%%%%%%%%#==============+++==============#%%%%%%%%%'
2176
+ Write-Host ' %%%%%%%%#===========#%%%%%%%%%#===========#%%%%%%%%'
2177
+ Write-Host ' %%%%%%%%==========%%%%%%%%%%%%%%%==========%%%%%%%%'
2178
+ Write-Host ' %%%%%%%*=========%%%%%%%%%%%%%%%%%=========*%%%%%%%'
2179
+ Write-Host ' %%%%%%%+========*%%%%%%%%%%%%%%%%%#=========%%%%%%%'
2180
+ Write-Host ' %%%%%%%+========#%%%%%%%%%%%%%%%%%#=========%%%%%%%'
2181
+ Write-Host ' %%%%%%%+========#%%%%%%%%%%%%%%%%%#=========%%%%%%%'
2182
+ Write-Host ' %%%%%%%+========#%%%%%%%%%%%%%%%%%#=========%%%%%%%'
2183
+ Write-Host ' %%%%%%%+========#%%%%%%%%%%%%%%%%%#=========%%%%%%%'
2184
+ Write-Host ' %%%%%%%+========#%%%%%%%%%%%%%%%%%#=========%%%%%%%'
2185
+ Write-Host ' %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%'
2186
+ Write-Host ' #=================================================#'
2187
+ Write-Host ' #=================================================#'
2188
+ Write-Host ' #=================+%%%============================#'
2189
+ Write-Host ' #==================%%%%*==========================#'
2190
+ Write-Host ' #===================*%%%%+========================#'
2191
+ Write-Host ' #=====================#%%%%=======================#'
2192
+ Write-Host ' #======================+%%%%#=====================#'
2193
+ Write-Host ' #========================*%%%%*===================#'
2194
+ Write-Host ' #========================+%%%%%===================#'
2195
+ Write-Host ' #======================#%%%%%+====================#'
2196
+ Write-Host ' #===================+%%%%%%=======================#'
2197
+ Write-Host ' #=================#%%%%%+=========================#'
2198
+ Write-Host ' #==============+%%%%%#============================#'
2199
+ Write-Host ' #============*%%%%%+====+%%%%%%%%%%===============#'
2200
+ Write-Host ' #=============%%*========+********+===============#'
2201
+ Write-Host ' #=================================================#'
2202
+ Write-Host ' #=================================================#'
2203
+ Write-Host ' #=================================================#'
2204
+ }
2205
+
2148
2206
function Test-IsADAdmin {
2149
2207
<#
2150
2208
. SYNOPSIS
@@ -2237,9 +2295,11 @@ function Test-IsMemberOfProtectedUsers {
2237
2295
Active Directory user object, user SID, SamAccountName, etc
2238
2296
2239
2297
. OUTPUTS
2240
- True, False
2298
+ Boolean
2241
2299
#>
2242
2300
2301
+ [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute (' PSUseSingularNouns' , ' Test-IsMemberOfProtectedUsers' , Justification = ' The name of the group we are checking is plural.' )]
2302
+ [OutputType ([Boolean ])]
2243
2303
[CmdletBinding ()]
2244
2304
param (
2245
2305
# User parameter accepts any input that is valid for Get-ADUser
@@ -2318,12 +2378,9 @@ function Test-IsRecentVersion {
2318
2378
Published at: 01/28/2024 12:47:18
2319
2379
Install Module: Install-Module -Name Locksmith
2320
2380
Standalone Script: https://github.com/trimarcjake/locksmith/releases/download/v2.6/Invoke-Locksmith.zip
2321
-
2322
- . NOTES
2323
- Author: Sam Erde
2324
- Date: 02/10/2024
2325
2381
#>
2326
2382
[CmdletBinding ()]
2383
+ [OutputType ([boolean ])]
2327
2384
param (
2328
2385
# Check a specific version number from the script
2329
2386
[Parameter (Mandatory )]
@@ -2568,7 +2625,7 @@ function Invoke-Locksmith {
2568
2625
Finds the most common malconfigurations of Active Directory Certificate Services (AD CS).
2569
2626
2570
2627
. DESCRIPTION
2571
- Locksmith uses the Active Directory (AD) Powershell (PS) module to identify 6 misconfigurations
2628
+ Locksmith uses the Active Directory (AD) Powershell (PS) module to identify 7 misconfigurations
2572
2629
commonly found in Enterprise mode AD CS installations.
2573
2630
2574
2631
. COMPONENT
@@ -2630,17 +2687,30 @@ function Invoke-Locksmith {
2630
2687
2631
2688
[CmdletBinding ()]
2632
2689
param (
2633
- [string ]$Forest ,
2634
- [string ]$InputPath ,
2690
+ # [string]$Forest, # Not used yet
2691
+ # [string]$InputPath, # Not used yet
2692
+
2693
+ # The mode to run Locksmith in. Defaults to 0.
2694
+ [Parameter ()]
2695
+ [ValidateSet (0 , 1 , 2 , 3 , 4 )]
2635
2696
[int ]$Mode = 0 ,
2697
+
2698
+ # The scans to run. Defaults to 'All'.
2636
2699
[Parameter ()]
2637
2700
[ValidateSet (' Auditing' , ' ESC1' , ' ESC2' , ' ESC3' , ' ESC4' , ' ESC5' , ' ESC6' , ' ESC8' , ' All' , ' PromptMe' )]
2638
2701
[array ]$Scans = ' All' ,
2639
- [string ]$OutputPath = (Get-Location ).Path,
2702
+
2703
+ # The directory to save the output in (defaults to the current working directory).
2704
+ [Parameter ()]
2705
+ [ValidateScript ({ Test-Path - Path $_ - PathType Container })]
2706
+ [string ]$OutputPath = $PWD ,
2707
+
2708
+ # The credential to use for working with ADCS.
2709
+ [Parameter ()]
2640
2710
[System.Management.Automation.PSCredential ]$Credential
2641
2711
)
2642
2712
2643
- $Version = ' 2024.8 '
2713
+ $Version = ' 2024.10 '
2644
2714
$LogoPart1 = @"
2645
2715
_ _____ _______ _ _ _______ _______ _____ _______ _ _
2646
2716
| | | | |____/ |______ | | | | | |_____|
@@ -2670,10 +2740,13 @@ function Invoke-Locksmith {
2670
2740
# Exit if running in restricted admin mode without explicit credentials
2671
2741
if (! $Credential -and (Get-RestrictedAdminModeSetting )) {
2672
2742
Write-Warning " Restricted Admin Mode appears to be in place, re-run with the '-Credential domain\user' option"
2673
- break ;
2743
+ break
2674
2744
}
2675
2745
2676
2746
# ## Initial variables
2747
+ # For output filenames
2748
+ [string ]$FilePrefix = " Locksmith $ ( Get-Date - Format ' yyyy-MM-dd hh-mm-ss' ) "
2749
+
2677
2750
# Extended Key Usages for client authentication. A requirement for ESC1
2678
2751
$ClientAuthEKUs = ' 1\.3\.6\.1\.5\.5\.7\.3\.2|1\.3\.6\.1\.5\.2\.3\.4|1\.3\.6\.1\.4\.1\.311\.20\.2\.2|2\.5\.29\.37\.0'
2679
2752
@@ -2723,18 +2796,20 @@ function Invoke-Locksmith {
2723
2796
2724
2797
# ## Generated variables
2725
2798
# $Dictionary = New-Dictionary
2799
+
2800
+ $Forest = Get-ADForest
2726
2801
$ForestGC = $ (Get-ADDomainController - Discover - Service GlobalCatalog - ForceDiscover | Select-Object - ExpandProperty Hostname) + " :3268"
2727
- # $DNSRoot = [string]((Get-ADForest) .RootDomain | Get-ADDomain).DNSRoot
2728
- $EnterpriseAdminsSID = ([string ](( Get-ADForest ) .RootDomain | Get-ADDomain ).DomainSID) + ' -519'
2802
+ # $DNSRoot = [string]($Forest .RootDomain | Get-ADDomain).DNSRoot
2803
+ $EnterpriseAdminsSID = ([string ]($Forest .RootDomain | Get-ADDomain ).DomainSID) + ' -519'
2729
2804
$PreferredOwner = [System.Security.Principal.SecurityIdentifier ]::New($EnterpriseAdminsSID )
2730
- # $DomainSIDs = (Get-ADForest) .Domains | ForEach-Object { (Get-ADDomain $_).DomainSID.Value }
2805
+ # $DomainSIDs = $Forest .Domains | ForEach-Object { (Get-ADDomain $_).DomainSID.Value }
2731
2806
2732
2807
# Add SIDs of (probably) Safe Users to $SafeUsers
2733
2808
Get-ADGroupMember $EnterpriseAdminsSID | ForEach-Object {
2734
2809
$SafeUsers += ' |' + $_.SID.Value
2735
2810
}
2736
2811
2737
- ( Get-ADForest ) .Domains | ForEach-Object {
2812
+ $Forest .Domains | ForEach-Object {
2738
2813
$DomainSID = (Get-ADDomain $_ ).DomainSID.Value
2739
2814
<#
2740
2815
-517 = Cert Publishers
@@ -2837,7 +2912,7 @@ function Invoke-Locksmith {
2837
2912
Format-Result $ESC8 ' 1'
2838
2913
}
2839
2914
2 {
2840
- $Output = ' ADCSIssues.CSV'
2915
+ $Output = Join-Path - Path $OutputPath - ChildPath " $FilePrefix ADCSIssues.CSV"
2841
2916
Write-Host " Writing AD CS issues to $Output ..."
2842
2917
try {
2843
2918
$AllIssues | Select-Object Forest, Technique, Name, Issue | Export-Csv - NoTypeInformation $Output
@@ -2848,7 +2923,7 @@ function Invoke-Locksmith {
2848
2923
}
2849
2924
}
2850
2925
3 {
2851
- $Output = ' ADCSRemediation.CSV'
2926
+ $Output = Join-Path - Path $OutputPath - ChildPath " $FilePrefix ADCSRemediation.CSV"
2852
2927
Write-Host " Writing AD CS issues to $Output ..."
2853
2928
try {
2854
2929
$AllIssues | Select-Object Forest, Technique, Name, DistinguishedName, Issue, Fix | Export-Csv - NoTypeInformation $Output
@@ -2867,5 +2942,4 @@ function Invoke-Locksmith {
2867
2942
}
2868
2943
2869
2944
2870
- # Export functions and aliases as required
2871
2945
Invoke-Locksmith - Mode $Mode - Scans $Scans
0 commit comments