Skip to content

Commit e43023a

Browse files
authored
Merge pull request #250 from jakehildreth/testing
2025.5.26 Release
2 parents fdfc0dc + 7f6f900 commit e43023a

22 files changed

Lines changed: 1380 additions & 278 deletions

Build/Build-Module.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ Build-Module -ModuleName 'Locksmith' {
129129

130130
# The scans to run. Defaults to 'All'.
131131
[Parameter()]
132-
[ValidateSet('Auditing', 'ESC1', 'ESC2', 'ESC3', 'ESC4', 'ESC5', 'ESC6', 'ESC8', 'ESC11', 'ESC13', 'ESC15', 'EKUwu', 'All', 'PromptMe')]
132+
[ValidateSet('Auditing', 'ESC1', 'ESC2', 'ESC3', 'ESC4', 'ESC5', 'ESC6', 'ESC7', 'ESC8', 'ESC9', 'ESC11', 'ESC13', 'ESC15', 'EKUwu', 'ESC16', 'All', 'PromptMe')]
133133
[array]$Scans = 'All'
134134
)
135135
}

Invoke-Locksmith.ps1

Lines changed: 699 additions & 136 deletions
Large diffs are not rendered by default.

Locksmith.psd1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
FunctionsToExport = 'Invoke-Locksmith'
99
GUID = 'b1325b42-8dc4-4f17-aa1f-dcb5984ca14a'
1010
HelpInfoURI = 'https://raw.githubusercontent.com/jakehildreth/Locksmith/main/en-US/'
11-
ModuleVersion = '2025.4.20'
11+
ModuleVersion = '2025.5.26'
1212
PowerShellVersion = '5.1'
1313
PrivateData = @{
1414
PSData = @{

Private/Find-ESC1.ps1

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,12 +92,14 @@ Get-ADObject `$Object | Set-ADObject -Replace @{'msPKI-Enrollment-Flag' = 0}
9292
Technique = 'ESC1'
9393
}
9494

95-
if ( $Mode -in @(1, 3, 4) ) {
96-
Update-ESC1Remediation -Issue $Issue
97-
}
9895
if ($SkipRisk -eq $false) {
9996
Set-RiskRating -ADCSObjects $ADCSObjects -Issue $Issue -SafeUsers $SafeUsers -UnsafeUsers $UnsafeUsers
10097
}
98+
99+
if ( $Mode -in @(1, 3, 4) ) {
100+
Update-ESC1Remediation -Issue $Issue
101+
}
102+
101103
$Issue
102104
}
103105
}

Private/Find-ESC16.ps1

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
function Find-ESC16 {
2+
<#
3+
.SYNOPSIS
4+
This script finds Active Directory Certificate Services (AD CS) Certification Authorities (CA) that have the ESC16 vulnerability.
5+
6+
.DESCRIPTION
7+
The script takes an array of ADCS objects as input and filters them based on objects that have the objectClass
8+
'pKIEnrollmentService' and the szOID_NTDS_CA_SECURITY_EXT disabled. For each matching object, it creates a custom object with
9+
properties representing various information about the object, such as Forest, Name, DistinguishedName, Technique,
10+
Issue, Fix, and Revert.
11+
12+
.PARAMETER ADCSObjects
13+
Specifies the array of AD CS objects to be processed. This parameter is mandatory.
14+
15+
.OUTPUTS
16+
The script outputs an array of custom objects representing the matching ADCS objects and their associated information.
17+
#>
18+
[CmdletBinding()]
19+
param(
20+
[Parameter(Mandatory)]
21+
[Microsoft.ActiveDirectory.Management.ADEntity[]]$ADCSObjects,
22+
[Parameter(Mandatory)]
23+
[string]$UnsafeUsers,
24+
[switch]$SkipRisk
25+
)
26+
process {
27+
$ADCSObjects | Where-Object {
28+
($_.objectClass -eq 'pKIEnrollmentService') -and
29+
($_.DisableExtensionList -ne 'No')
30+
} | ForEach-Object {
31+
$Issue = [pscustomobject]@{
32+
Forest = $_.CanonicalName.split('/')[0]
33+
Name = $_.Name
34+
DistinguishedName = $_.DistinguishedName
35+
Issue = $_.DisableExtensionList
36+
Fix = 'N/A'
37+
Revert = 'N/A'
38+
Technique = 'ESC16'
39+
}
40+
if ($_.DisableExtensionList -eq 'Yes') {
41+
$Issue.Issue = @"
42+
The Certification Authority (CA) $($_.CAFullName) has the szOID_NTDS_CA_SECURITY_EXT security extension disabled. When
43+
this extension is disabled, every certificate issued by this CA will be unable to to reliably map a certificate to a
44+
user or computer account's SID for authentication.
45+
46+
More info:
47+
- https://github.com/ly4k/Certipy/wiki/06-%E2%80%90-Privilege-Escalation#esc16-security-extension-disabled-on-ca-globally
48+
49+
"@
50+
$Issue.Fix = @"
51+
# Enable the flag
52+
# TODO
53+
54+
# Restart the Certificate Authority service
55+
Invoke-Command -ComputerName '$($_.dNSHostName)' -ScriptBlock {
56+
Get-Service -Name certsvc | Restart-Service -Force
57+
}
58+
"@
59+
$Issue.Revert = @"
60+
# Disable the flag
61+
TODO
62+
63+
# Restart the Certificate Authority service
64+
Invoke-Command -ComputerName '$($_.dNSHostName)' -ScriptBlock {
65+
Get-Service -Name certsvc | Restart-Service -Force
66+
}
67+
"@
68+
}
69+
if ($SkipRisk -eq $false) {
70+
Set-RiskRating -ADCSObjects $ADCSObjects -Issue $Issue -SafeUsers $SafeUsers -UnsafeUsers $UnsafeUsers
71+
}
72+
$Issue
73+
}
74+
}
75+
}

Private/Find-ESC3C1.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@
6060
$($entry.IdentityReference) can use this template to request an Enrollment Agent
6161
certificate without Manager Approval.
6262
63-
The resulting certificate can be used to enroll in any template that requires
63+
The resulting certificate can be used to enroll in any template that allows
6464
an Enrollment Agent to submit the request.
6565
6666
More info:

Private/Find-ESC4.ps1

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -173,12 +173,14 @@ Set-Acl -Path 'AD:$($_.DistinguishedName)' -AclObject `$ACL
173173
Technique = 'ESC4'
174174
}
175175

176-
if ( $Mode -in @(1, 3, 4) ) {
177-
Update-ESC4Remediation -Issue $Issue
178-
}
179176
if ($SkipRisk -eq $false) {
180177
Set-RiskRating -ADCSObjects $ADCSObjects -Issue $Issue -SafeUsers $SafeUsers -UnsafeUsers $UnsafeUsers
181178
}
179+
180+
if ( $Mode -in @(1, 3, 4) ) {
181+
Update-ESC4Remediation -Issue $Issue
182+
}
183+
182184
$Issue
183185
}
184186
}

Private/Find-ESC6.ps1

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
$Issue = [pscustomobject]@{
3838
Forest = $_.CanonicalName.split('/')[0]
3939
Name = $_.Name
40+
CAFullname = $CAFullName
4041
DistinguishedName = $_.DistinguishedName
4142
Issue = $_.SANFlag
4243
Fix = 'N/A'

Private/Find-ESC7.ps1

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
function Find-ESC7 {
2+
<#
3+
.SYNOPSIS
4+
This script finds Active Directory Certificate Services (AD CS) Certificate Authorities (CA) that have the ESC7 vulnerability.
5+
6+
.DESCRIPTION
7+
The script takes an array of AD CS objects as input and filters them based on objects that have the objectClass
8+
'pKIEnrollmentService'. If the CA objects have non-standard/unsafe principals as administrators or managers, an issue is created.
9+
10+
.PARAMETER ADCSObjects
11+
Specifies the array of AD CS objects to be processed. This parameter is mandatory.
12+
13+
.PARAMETER UnsafeUsers
14+
Principals that should never be granted control of a CA.
15+
16+
.PARAMETER SafeUsers
17+
Principals that are generally recognized as safe to control a CA.
18+
19+
.PARAMETER SkipRisk
20+
Switch used when processing second-order risks.
21+
22+
.OUTPUTS
23+
The script outputs an array of custom objects representing the matching AD CS objects and their associated information.
24+
25+
#>
26+
[CmdletBinding()]
27+
param(
28+
[Parameter(Mandatory)]
29+
[Microsoft.ActiveDirectory.Management.ADEntity[]]$ADCSObjects,
30+
[Parameter(Mandatory)]
31+
[string]$UnsafeUsers,
32+
[Parameter(Mandatory)]
33+
[string]$SafeUsers,
34+
[switch]$SkipRisk
35+
)
36+
process {
37+
Write-Output $ADCSObjects -PipelineVariable object | Where-Object {
38+
($object.objectClass -eq 'pKIEnrollmentService') -and $object.CAHostDistinguishedName -and
39+
( ($object.CAAdministrator) -or ($object.CertificateManager) )
40+
} | ForEach-Object {
41+
Write-Output $object.CAAdministrator -PipelineVariable admin | ForEach-Object {
42+
$SID = Convert-IdentityReferenceToSid -Object $admin
43+
if ($SID -notmatch $SafeUsers) {
44+
$Issue = [pscustomobject]@{
45+
Forest = $object.CanonicalName.split('/')[0]
46+
Name = $object.Name
47+
DistinguishedName = $object.DistinguishedName
48+
IdentityReference = $admin
49+
IdentityReferenceSID = $SID
50+
Right = 'CA Administrator'
51+
Issue = @"
52+
$admin has been granted CA Administrator rights on this Certification Authority (CA).
53+
54+
$admin has full control over this CA.
55+
56+
More info:
57+
- https://posts.specterops.io/certified-pre-owned-d95910965cd2
58+
59+
"@
60+
Fix = "Revoke CA Administrator rights from ${admin}."
61+
Revert = "Restore CA Administrator rights to ${admin}."
62+
Technique = 'ESC7'
63+
}
64+
65+
if ($SkipRisk -eq $false) {
66+
Set-RiskRating -ADCSObjects $ADCSObjects -Issue $Issue -SafeUsers $SafeUsers -UnsafeUsers $UnsafeUsers
67+
}
68+
69+
if ( $Mode -in @(1, 3, 4) ) {
70+
Update-ESC7Remediation -Issue $Issue
71+
}
72+
73+
$Issue
74+
}
75+
}
76+
77+
Write-Output $object.CertificateManager -PipelineVariable admin | ForEach-Object {
78+
$SID = Convert-IdentityReferenceToSid -Object $admin
79+
if ($SID -notmatch $SafeUsers) {
80+
$Issue = [pscustomobject]@{
81+
Forest = $object.CanonicalName.split('/')[0]
82+
Name = $object.Name
83+
DistinguishedName = $object.DistinguishedName
84+
IdentityReference = $admin
85+
IdentityReferenceSID = $SID
86+
Right = 'Certificate Manager'
87+
Issue = @"
88+
$admin has been granted Certificate Manager rights on this Certification Authority (CA).
89+
90+
$admin can approve pending certificate requests on this CA.
91+
92+
More info:
93+
- https://posts.specterops.io/certified-pre-owned-d95910965cd2
94+
95+
"@
96+
Fix = "Revoke Certificate Manager rights from ${admin}."
97+
Revert = "Restore Certificate Manager rights to ${admin}."
98+
Technique = 'ESC7'
99+
}
100+
101+
if ($SkipRisk -eq $false) {
102+
Set-RiskRating -ADCSObjects $ADCSObjects -Issue $Issue -SafeUsers $SafeUsers -UnsafeUsers $UnsafeUsers
103+
}
104+
105+
if ( $Mode -in @(1, 3, 4) ) {
106+
Update-ESC7Remediation -Issue $Issue
107+
}
108+
109+
$Issue
110+
}
111+
}
112+
}
113+
}
114+
}

0 commit comments

Comments
 (0)