@@ -280,6 +280,11 @@ Get-ADObject `$Object | Set-ADObject -Replace @{'msPKI-Enrollment-Flag' = 0}
280
280
"@
281
281
Technique = ' ESC1'
282
282
}
283
+
284
+ if ( $Mode -in @ (1 , 3 , 4 ) ) {
285
+ Update-ESC1Remediation - Issue $Issue
286
+ }
287
+
283
288
$Issue
284
289
}
285
290
}
@@ -2648,7 +2653,7 @@ function Set-AdditionalCAProperty {
2648
2653
$Cache = [System.Net.CredentialCache ]::New()
2649
2654
$Cache.Add ([System.Uri ]::new($FullURL ), $Auth , [System.Net.CredentialCache ]::DefaultNetworkCredentials)
2650
2655
$Request.Credentials = $Cache
2651
- $Request.Timeout = 3000
2656
+ $Request.Timeout = 1000
2652
2657
$Request.GetResponse () | Out-Null
2653
2658
$CAEnrollmentEndpoint += @ {
2654
2659
' URL' = $FullURL
@@ -2657,9 +2662,13 @@ function Set-AdditionalCAProperty {
2657
2662
}
2658
2663
catch {
2659
2664
try {
2665
+ $Auth = ' NTLM'
2660
2666
$FullURL = " https$URL "
2661
2667
$Request = [System.Net.WebRequest ]::Create($FullURL )
2662
-
2668
+ $Cache = [System.Net.CredentialCache ]::New()
2669
+ $Cache.Add ([System.Uri ]::new($FullURL ), $Auth , [System.Net.CredentialCache ]::DefaultNetworkCredentials)
2670
+ $Request.Credentials = $Cache
2671
+ $Request.Timeout = 1000
2663
2672
$Request.GetResponse () | Out-Null
2664
2673
$CAEnrollmentEndpoint += @ {
2665
2674
' URL' = $FullURL
@@ -2672,8 +2681,9 @@ function Set-AdditionalCAProperty {
2672
2681
$FullURL = " https$URL "
2673
2682
$Request = [System.Net.WebRequest ]::Create($FullURL )
2674
2683
$Cache = [System.Net.CredentialCache ]::New()
2675
- $Cache.Add ([System.Uri ]::new($FullURL ), ' Negotiate ' , [System.Net.CredentialCache ]::DefaultNetworkCredentials)
2684
+ $Cache.Add ([System.Uri ]::new($FullURL ), $Auth , [System.Net.CredentialCache ]::DefaultNetworkCredentials)
2676
2685
$Request.Credentials = $Cache
2686
+ $Request.Timeout = 1000
2677
2687
$Request.GetResponse () | Out-Null
2678
2688
$CAEnrollmentEndpoint += @ {
2679
2689
' URL' = $FullURL
@@ -2780,6 +2790,52 @@ function Set-AdditionalCAProperty {
2780
2790
}
2781
2791
}
2782
2792
2793
+ function Set-AdditionalTemplateProperty {
2794
+ <#
2795
+ . SYNOPSIS
2796
+ Sets additional properties on a template object.
2797
+
2798
+ . DESCRIPTION
2799
+ This script sets additional properties on a template object.
2800
+ It takes an array of AD CS Objects as input, which includes the templates to be processed and CA objects that
2801
+ detail which templates are published.
2802
+ The script filters the AD CS Objects based on the objectClass property and performs the necessary operations
2803
+ to set the additional properties.
2804
+
2805
+ . PARAMETER ADCSObjects
2806
+ Specifies the array of AD CS Objects to be processed. This parameter is mandatory and supports pipeline input.
2807
+
2808
+ . PARAMETER Credential
2809
+ Specifies the PSCredential object to be used for authentication when accessing the CA objects.
2810
+ If not provided, the script will use the current user's credentials.
2811
+
2812
+ . EXAMPLE
2813
+ $ADCSObjects = Get-ADCSObject -Targets (Get-Target)
2814
+ Set-AdditionalTemplateProperty -ADCSObjects $ADCSObjects -ForestGC 'dc1.ad.dotdot.horse:3268'
2815
+ #>
2816
+
2817
+ [CmdletBinding (SupportsShouldProcess )]
2818
+ param (
2819
+ [parameter (Mandatory , ValueFromPipeline )]
2820
+ [array ]$ADCSObjects
2821
+ )
2822
+
2823
+ $ADCSObjects | Where-Object objectClass -Match ' pKICertificateTemplate' - PipelineVariable template | ForEach-Object {
2824
+ Write-Host " [?] Checking if template `" $ ( $template.Name ) `" is published on any Certification Authority." - ForegroundColor Blue
2825
+ $Published = $false
2826
+ $PublishedOn = @ ()
2827
+ foreach ($ca in ($ADCSObjects | Where-Object objectClass -EQ ' pKIEnrollmentService' )) {
2828
+ if ($ca.certificateTemplates -contains $template.Name ) {
2829
+ $Published = $true
2830
+ $PublishedOn += $ca.Name
2831
+ }
2832
+
2833
+ $template | Add-Member - NotePropertyName Published - NotePropertyValue $Published - Force
2834
+ $template | Add-Member - NotePropertyName PublishedOn - NotePropertyValue $PublishedOn - Force
2835
+ }
2836
+ }
2837
+ }
2838
+
2783
2839
function Set-Severity {
2784
2840
[OutputType ([string ])]
2785
2841
[CmdletBinding ()]
@@ -3113,6 +3169,109 @@ function Test-IsRSATInstalled {
3113
3169
$false
3114
3170
}
3115
3171
}
3172
+ function Update-ESC1Remediation {
3173
+ <#
3174
+ . SYNOPSIS
3175
+ This function asks the user a set of questions to provide the most appropriate remediation for ESC1 issues.
3176
+
3177
+ . DESCRIPTION
3178
+ This function takes a single ESC1 issue as input then asks a series of questions to determine the correct
3179
+ remediation.
3180
+
3181
+ Questions:
3182
+ TODO: Is this template published?
3183
+ 1. Does the identified principal need to enroll in this template? [Yes/No/Unsure]
3184
+ 2. Is this certificate widely used and/or frequently requested? [Yes/No/Unsure]
3185
+
3186
+ Depending on answers to these questions, the Issue and Fix attributes on the Issue object are updated.
3187
+
3188
+ . PARAMETER Issue
3189
+ A pscustomobject that includes all pertinent information about the ESC1 issue.
3190
+
3191
+ . OUTPUTS
3192
+ This function updates ESC1 remediations customized to the user's needs.
3193
+
3194
+ . EXAMPLE
3195
+ $Targets = Get-Target
3196
+ $ADCSObjects = Get-ADCSObject -Targets $Targets
3197
+ $SafeUsers = '-512$|-519$|-544$|-18$|-517$|-500$|-516$|-9$|-526$|-527$|S-1-5-10'
3198
+ $ESC1Issues = Find-ESC1 -ADCSObjects $ADCSObjects -SafeUsers $SafeUsers
3199
+ foreach ($issue in $ESC1Issues) { Update-ESC1Remediation -Issue $Issue }
3200
+ #>
3201
+ [CmdletBinding ()]
3202
+ param (
3203
+ $Issue
3204
+ )
3205
+
3206
+ $Header = " `n [!] ESC1 Issue detected in $ ( $Issue.Name ) "
3207
+ Write-Host $Header - ForegroundColor Yellow
3208
+ Write-Host $ (' -' * $Header.Length ) - ForegroundColor Yellow
3209
+ Write-Host " $ ( $Issue.IdentityReference ) can provide a Subject Alternative Name (SAN) while enrolling in this"
3210
+ Write-Host " template. Manager approval is not required for a certificate to be issued.`n "
3211
+ Write-Host ' To provide the most appropriate remediation for this issue, Locksmith will now ask you a few questions.'
3212
+
3213
+ $Enroll = ' '
3214
+ do {
3215
+ $Enroll = Read-Host " `n Does $ ( $Issue.IdentityReference ) need to Enroll in the $ ( $Issue.Name ) template? [y/n/unsure]"
3216
+ } while ( ($Enroll -ne ' y' ) -and ($Enroll -ne ' n' ) -and ($Enroll -ne ' unsure' ))
3217
+
3218
+ if ($Enroll -eq ' y' ) {
3219
+ $Frequent = ' '
3220
+ do {
3221
+ $Frequent = Read-Host " `n Is the $ ( $Issue.Name ) certificate frequently requested? [y/n/unsure]"
3222
+ } while ( ($Frequent -ne ' y' ) -and ($Frequent -ne ' n' ) -and ($Frequent -ne ' unsure' ))
3223
+
3224
+ if ($Frequent -ne ' n' ) {
3225
+ $Issue.Fix = @"
3226
+ # Locksmith cannot currently determine the best remediation course.
3227
+ # Remediation Options:
3228
+ # 1. If $ ( $Issue.IdentityReference ) is a group, remove its Enroll/AutoEnroll rights and grant those rights
3229
+ # to a smaller group or a single user/service account.
3230
+
3231
+ # 2. Remove the ability to submit a SAN (aka disable "Supply in the request").
3232
+ `$ Object = `' $ ( $_.DistinguishedName ) `'
3233
+ Get-ADObject `$ Object | Set-ADObject -Replace @{'msPKI-Certificate-Name-Flag' = 0}
3234
+
3235
+ # 3. Enable Manager Approval
3236
+ `$ Object = `' $ ( $_.DistinguishedName ) `'
3237
+ Get-ADObject `$ Object | Set-ADObject -Replace @{'msPKI-Enrollment-Flag' = 2}
3238
+ "@
3239
+
3240
+ $Issue.Revert = @"
3241
+ # 1. Replace Enroll/AutoEnroll rights from the smaller group/single user/service account and grant those rights
3242
+ # back to $ ( $Issue.IdentityReference ) .
3243
+
3244
+ # 2. Restore the ability to submit a SAN.
3245
+ `$ Object = `' $ ( $_.DistinguishedName ) `'
3246
+ Get-ADObject `$ Object | Set-ADObject -Replace @{'msPKI-Certificate-Name-Flag' = 1}
3247
+
3248
+ # 3. Disable Manager Approval
3249
+ `$ Object = `' $ ( $_.DistinguishedName ) `'
3250
+ Get-ADObject `$ Object | Set-ADObject -Replace @{'msPKI-Enrollment-Flag' = 0}
3251
+ "@
3252
+ }
3253
+ }
3254
+ elseif ($Enroll -eq ' n' ) {
3255
+ $Issue.Fix = @"
3256
+ # 1. Open the Certification Templates Console: certtmpl.msc
3257
+ # 2. Double-click the $ ( $Issue.Name ) template to open its Properties page.
3258
+ # 3. Select the Security tab.
3259
+ # 4. Select the entry for $ ( $Issue.IdentityReference ) .
3260
+ # 5. Uncheck the "Enroll" and/or "Autoenroll" boxes.
3261
+ # 6. Click OK.
3262
+ "@
3263
+
3264
+ $Issue.Revert = @"
3265
+ # 1. Open the Certification Templates Console: certtmpl.msc
3266
+ # 2. Double-click the $ ( $Issue.Name ) template to open its Properties page.
3267
+ # 3. Select the Security tab.
3268
+ # 4. Select the entry for $ ( $Issue.IdentityReference ) .
3269
+ # 5. Check the "Enroll" and/or "Autoenroll" boxes depending on your specific needs.
3270
+ # 6. Click OK.
3271
+ "@
3272
+ }
3273
+ }
3274
+
3116
3275
function Update-ESC4Remediation {
3117
3276
<#
3118
3277
. SYNOPSIS
@@ -3121,8 +3280,8 @@ function Update-ESC4Remediation {
3121
3280
. DESCRIPTION
3122
3281
This function takes a single ESC4 issue as input. It then prompts the user if the principal with the ESC4 rights
3123
3282
administers the template in question.
3124
- If the principal is an admin of the template, the Issue attribute to indicate this configuration is expected, and
3125
- the Fix attribute for the issue is updated to indicate no remediation is needed.
3283
+ If the principal is an admin of the template, the Issue attribute is updated to indicate this configuration is
3284
+ expected, and the Fix attribute for the issue is updated to indicate no remediation is needed.
3126
3285
If the the principal is not an admin of the template AND the rights assigned is GenericAll, Locksmith will ask
3127
3286
if Enroll or AutoEnroll rights are needed.
3128
3287
Depending on the answers to the listed questions, the Fix attribute is updated accordingly.
@@ -3134,14 +3293,14 @@ function Update-ESC4Remediation {
3134
3293
This function updates ESC4 remediations customized to the user's needs.
3135
3294
3136
3295
. EXAMPLE
3137
- $Target = Get-Target
3138
- $ADCSObjects = Get-ADCSObject -Target $Target
3296
+ $Targets = Get-Target
3297
+ $ADCSObjects = Get-ADCSObject -Targets $Targets
3139
3298
$DangerousRights = @('GenericAll', 'WriteProperty', 'WriteOwner', 'WriteDacl')
3140
3299
$SafeOwners = '-512$|-519$|-544$|-18$|-517$|-500$'
3141
3300
$SafeUsers = '-512$|-519$|-544$|-18$|-517$|-500$|-516$|-9$|-526$|-527$|S-1-5-10'
3142
3301
$SafeObjectTypes = '0e10c968-78fb-11d2-90d4-00c04f79dc55|a05b8cc2-17bc-4802-a710-e7c15ab866a2'
3143
3302
$ESC4Issues = Find-ESC4 -ADCSObjects $ADCSObjects -DangerousRights $DangerousRights -SafeOwners $SafeOwners -SafeUsers $SafeUsers -SafeObjectTypes $SafeObjectTypes
3144
- foreach ($issue in $ESCIssues ) { Update-ESC4Remediation -Issue $Issue }
3303
+ foreach ($issue in $ESC4Issues ) { Update-ESC4Remediation -Issue $Issue }
3145
3304
#>
3146
3305
[CmdletBinding ()]
3147
3306
param (
@@ -3376,7 +3535,7 @@ function Invoke-Locksmith {
3376
3535
[System.Management.Automation.PSCredential ]$Credential
3377
3536
)
3378
3537
3379
- $Version = ' 2024.11.23 '
3538
+ $Version = ' 2024.12.5 '
3380
3539
$LogoPart1 = @"
3381
3540
_ _____ _______ _ _ _______ _______ _____ _______ _ _
3382
3541
| | | | |____/ |______ | | | | | |_____|
@@ -3508,16 +3667,18 @@ function Invoke-Locksmith {
3508
3667
if ($Credential ) {
3509
3668
$ADCSObjects = Get-ADCSObject - Targets $Targets - Credential $Credential
3510
3669
Set-AdditionalCAProperty - ADCSObjects $ADCSObjects - Credential $Credential - ForestGC $ForestGC
3511
- $ADCSObjects += Get-CAHostObject - ADCSObjects $ADCSObjects - Credential $Credential - ForestGC $ForestGC
3512
3670
$CAHosts = Get-CAHostObject - ADCSObjects $ADCSObjects - Credential $Credential - ForestGC $ForestGC
3671
+ $ADCSObjects += $CAHosts
3513
3672
}
3514
3673
else {
3515
3674
$ADCSObjects = Get-ADCSObject - Targets $Targets
3516
3675
Set-AdditionalCAProperty - ADCSObjects $ADCSObjects - ForestGC $ForestGC
3517
- $ADCSObjects += Get-CAHostObject - ADCSObjects $ADCSObjects - ForestGC $ForestGC
3518
3676
$CAHosts = Get-CAHostObject - ADCSObjects $ADCSObjects - ForestGC $ForestGC
3677
+ $ADCSObjects += $CAHosts
3519
3678
}
3520
3679
3680
+ Set-AdditionalTemplateProperty - ADCSObjects $ADCSObjects
3681
+
3521
3682
# Add SIDs of CA Hosts to $SafeUsers
3522
3683
$CAHosts | ForEach-Object { $SafeUsers += ' |' + $_.objectSid }
3523
3684
@@ -3574,10 +3735,12 @@ function Invoke-Locksmith {
3574
3735
Write-Host @"
3575
3736
[!] You ran Locksmith in Mode 0 which only provides an high-level overview of issues
3576
3737
identified in the environment. For more details including:
3738
+
3577
3739
- DistinguishedName of impacted object(s)
3578
- - Remediation code
3579
- - Revert code (in case remediation breaks something!)
3580
- run Locksmith in Mode 1:
3740
+ - Remediation guidance and/or code
3741
+ - Revert guidance and/or code (in case remediation breaks something!)
3742
+
3743
+ Run Locksmith in Mode 1!
3581
3744
3582
3745
# Module version
3583
3746
Invoke-Locksmith -Mode 1
0 commit comments