Skip to content

Commit

Permalink
Merge pull request #178 from TrimarcJake/esc13-detections
Browse files Browse the repository at this point in the history
ESC13 Detections and Issue Description Improvements.
  • Loading branch information
TrimarcJake authored Nov 10, 2024
2 parents 3210fe7 + c72c78b commit dfc0db3
Show file tree
Hide file tree
Showing 23 changed files with 980 additions and 234 deletions.
4 changes: 2 additions & 2 deletions Build/Build-Module.ps1
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
param (
# A CalVer string if you need to manually override the default yyyy.M version string.
# A CalVer string if you need to manually override the default yyyy.M.d version string.
[string]$CalVer
)

Expand All @@ -22,7 +22,7 @@ Import-Module -Name PSPublishModule -Force
Build-Module -ModuleName 'Locksmith' {
# Usual defaults as per standard module
$Manifest = [ordered] @{
ModuleVersion = if ($Calver) {$CalVer} else {(Get-Date -Format yyyy.M)}
ModuleVersion = if ($Calver) {$CalVer} else {(Get-Date -Format yyyy.M.d)}
CompatiblePSEditions = @('Desktop', 'Core')
GUID = 'b1325b42-8dc4-4f17-aa1f-dcb5984ca14a'
Author = 'Jake Hildreth'
Expand Down
584 changes: 480 additions & 104 deletions Invoke-Locksmith.ps1

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Locksmith.psd1
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
Description = 'A small tool to find and fix common misconfigurations in Active Directory Certificate Services.'
FunctionsToExport = @('*')
GUID = 'b1325b42-8dc4-4f17-aa1f-dcb5984ca14a'
ModuleVersion = '2024.11'
ModuleVersion = '2024.11.10'
PowerShellVersion = '5.1'
PrivateData = @{
PSData = @{
Expand Down
2 changes: 1 addition & 1 deletion Private/ConvertFrom-IdentityReference.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ function ConvertFrom-IdentityReference {
#>
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[Parameter(Mandatory)]
[array]$Object
)

Expand Down
21 changes: 18 additions & 3 deletions Private/Export-RevertScript.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,22 @@
.PARAMETER ESC11
An array of ESC11 changes to be reverted.
.PARAMETER ESC13
An array of ESC13 changes to be reverted.
.EXAMPLE
Export-RevertScript -AuditingIssues $auditingIssues -ESC1 $ESC1 -ESC2 $ESC2 -ESC3 $ESC3 -ESC4 $ESC4 -ESC5 $ESC5 -ESC6 $ESC6 -ESC11 $ESC11
$params = @{
AuditingIssues = $AuditingIssues
ESC1 = $ESC1
ESC2 = $ESC2
ESC3 = $ESC3
ESC4 = $ESC4
ESC5 = $ESC5
ESC6 = $ESC6
ESC11 = $ESC11
ESC13 = $ESC13
}
Export-RevertScript @params
Reverts the changes performed by Locksmith using the specified arrays of objects.
#>

Expand All @@ -47,13 +61,14 @@
[array]$ESC4,
[array]$ESC5,
[array]$ESC6,
[array]$ESC11
[array]$ESC11,
[array]$ESC13
)
begin {
$Output = 'Invoke-RevertLocksmith.ps1'
$RevertScript = [System.Text.StringBuilder]::New()
[void]$RevertScript.Append("<#`nScript to revert changes performed by Locksmith`nCreated $(Get-Date)`n#>`n")
$Objects = $AuditingIssues + $ESC1 + $ESC2 + $ESC3 + $ESC4 + $ESC5 + $ESC6 + $ESC11
$Objects = $AuditingIssues + $ESC1 + $ESC2 + $ESC3 + $ESC4 + $ESC5 + $ESC6 + $ESC11 + $ESC13
}
process {
if ($Objects) {
Expand Down
4 changes: 2 additions & 2 deletions Private/Find-AuditingIssue.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@

[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[Parameter(Mandatory)]
[array]$ADCSObjects
)

Expand All @@ -45,7 +45,7 @@
Name = $_.Name
DistinguishedName = $_.DistinguishedName
Technique = 'DETECT'
Issue = "Auditing is not fully enabled on $($_.CAFullName). Current value is $($_.AuditFilter)"
Issue = "Auditing is not fully enabled on $($_.CAFullName). Important security events may go unnoticed."
Fix = @"
certutil.exe -config `'$($_.CAFullname)`' -setreg `'CA\AuditFilter`' 127
Invoke-Command -ComputerName `'$($_.dNSHostName)`' -ScriptBlock {
Expand Down
40 changes: 29 additions & 11 deletions Private/Find-ESC1.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,27 @@
.PARAMETER SafeUsers
Specifies the list of SIDs of safe users who are allowed to have specific rights on the objects. This parameter is mandatory.
.PARAMETER ClientAuthEKUs
A list of EKUs that can be used for client authentication.
.OUTPUTS
The script outputs an array of custom objects representing the matching ADCS objects and their associated information.
.EXAMPLE
$ADCSObjects = Get-ADCSObjects
$SafeUsers = '-512$|-519$|-544$|-18$|-517$|-500$|-516$|-9$|-526$|-527$|S-1-5-10'
$Results = $ADCSObjects | Find-ESC1 -SafeUsers $SafeUsers
$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'
$Results = $ADCSObjects | Find-ESC1 -ADCSObjects $ADCSObjects -SafeUsers $SafeUsers -ClientAuthEKUs $ClientAuthEKUs
$Results
#>
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[Parameter(Mandatory)]
[array]$ADCSObjects,
[Parameter(Mandatory = $true)]
[array]$SafeUsers
[Parameter(Mandatory)]
[array]$SafeUsers,
[Parameter(Mandatory)]
$ClientAuthEKUs
)
$ADCSObjects | Where-Object {
($_.objectClass -eq 'pKICertificateTemplate') -and
Expand All @@ -37,30 +43,42 @@
!($_.'msPKI-Enrollment-Flag' -band 2) -and
( ($_.'msPKI-RA-Signature' -eq 0) -or ($null -eq $_.'msPKI-RA-Signature') )
} | ForEach-Object {
# Write-Host $_; continue
foreach ($entry in $_.nTSecurityDescriptor.Access) {
$Principal = New-Object System.Security.Principal.NTAccount($entry.IdentityReference)
if ($Principal -match '^(S-1|O:)') {
$SID = $Principal
} else {
$SID = ($Principal.Translate([System.Security.Principal.SecurityIdentifier])).Value
}
if ( ($SID -notmatch $SafeUsers) -and ($entry.ActiveDirectoryRights -match 'ExtendedRight') ) {
if ( ($SID -notmatch $SafeUsers) -and ( ($entry.ActiveDirectoryRights -match 'ExtendedRight') -or ($entry.ActiveDirectoryRights -match 'GenericAll') ) ) {
$Issue = [pscustomobject]@{
Forest = $_.CanonicalName.split('/')[0]
Name = $_.Name
DistinguishedName = $_.DistinguishedName
IdentityReference = $entry.IdentityReference
ActiveDirectoryRights = $entry.ActiveDirectoryRights
Issue = "$($entry.IdentityReference) can enroll in this Client Authentication template using a SAN without Manager Approval"
Fix = @"
Issue = @"
$($entry.IdentityReference) can provide a Subject Alternative Name (SAN) while
enrolling in this Client Authentication template, and enrollment does not require
Manager Approval.
The resultant certificate can be used by an attacker to authenticate as any
principal listed in the SAN up to and including Domain Admins, Enterprise Admins,
or Domain Controllers.
"@
Fix = @"
# Enable Manager Approval
`$Object = `'$($_.DistinguishedName)`'
Get-ADObject `$Object | Set-ADObject -Replace @{'msPKI-Certificate-Name-Flag' = 0}
Get-ADObject `$Object | Set-ADObject -Replace @{'msPKI-Enrollment-Flag' = 2}
"@
Revert = @"
Revert = @"
# Disable Manager Approval
`$Object = `'$($_.DistinguishedName)`'
Get-ADObject `$Object | Set-ADObject -Replace @{'msPKI-Certificate-Name-Flag' = 1}
Get-ADObject `$Object | Set-ADObject -Replace @{'msPKI-Enrollment-Flag' = 0}
"@
Technique = 'ESC1'
Technique = 'ESC1'
}
$Issue
}
Expand Down
25 changes: 20 additions & 5 deletions Private/Find-ESC11.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
#>
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[Parameter(Mandatory)]
$ADCSObjects
)
process {
Expand All @@ -41,16 +41,31 @@
Revert = 'N/A'
}
if ($_.InterfaceFlag -eq 'No') {
$Issue.Issue = 'IF_ENFORCEENCRYPTICERTREQUEST is disabled.'
$Issue.Fix = @"
$Issue.Issue = @"
The IF_ENFORCEENCRYPTICERTREQUEST flag is disabled on this Certification
Authority (CA). It is possible to relay NTLM authentication to the RPC interface
of this CA.
If the LAN Manager authentication level of any domain in this forest is 2 or
less, an attacker can coerce authentication from a Domain Controller (DC) to
receive a certificate which can be used to authenticate as that DC.
"@
$Issue.Fix = @"
# Enable the flag
certutil -config $CAFullname -setreg CA\InterfaceFlags +IF_ENFORCEENCRYPTICERTREQUEST
Invoke-Command -ComputerName `"$($_.dNSHostName)`" -ScriptBlock {
# Restart the Ceritification Authority service
Invoke-Command -ComputerName `'$($_.dNSHostName)`' -ScriptBlock {
Get-Service -Name `'certsvc`' | Restart-Service -Force
}
"@
$Issue.Revert = @"
# Disable the flag
certutil -config $CAFullname -setreg CA\InterfaceFlags -IF_ENFORCEENCRYPTICERTREQUEST
Invoke-Command -ComputerName `"$($_.dNSHostName)`" -ScriptBlock {
# Restart the Ceritification Authority service
Invoke-Command -ComputerName `'$($_.dNSHostName)`' -ScriptBlock {
Get-Service -Name `'certsvc`' | Restart-Service -Force
}
"@
Expand Down
91 changes: 91 additions & 0 deletions Private/Find-ESC13.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
function Find-ESC13 {
<#
.SYNOPSIS
This script finds AD CS (Active Directory Certificate Services) objects that have the ESC13 vulnerability.
.DESCRIPTION
The script takes an array of ADCS objects as input and filters them based on the specified conditions.
For each matching object, it creates a custom object with properties representing various information about
the object, such as Forest, Name, DistinguishedName, IdentityReference, ActiveDirectoryRights, Issue, Fix, Revert, and Technique.
.PARAMETER ADCSObjects
Specifies the array of ADCS objects to be processed. This parameter is mandatory.
.PARAMETER SafeUsers
Specifies the list of SIDs of safe users who are allowed to have specific rights on the objects. This parameter is mandatory.
.PARAMETER ClientAuthEKUs
A list of EKUs that can be used for client authentication.
.OUTPUTS
The script outputs an array of custom objects representing the matching ADCS objects and their associated information.
.EXAMPLE
$ADCSObjects = Get-ADCSObjects
$SafeUsers = '-512$|-519$|-544$|-18$|-517$|-500$|-516$|-9$|-526$|-527$|S-1-5-10'
$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'
$Results = $ADCSObjects | Find-ESC13 -ADCSObjects $ADCSObjects -SafeUsers $SafeUsers -ClientAuthEKUs $ClientAuthEKUs
$Results
#>
[CmdletBinding()]
param(
[Parameter(Mandatory)]
[Microsoft.ActiveDirectory.Management.ADEntity[]]$ADCSObjects,
[Parameter(Mandatory)]
[array]$SafeUsers,
[Parameter(Mandatory)]
$ClientAuthEKUs
)

$ADCSObjects | Where-Object {
($_.objectClass -eq 'pKICertificateTemplate') -and
($_.pkiExtendedKeyUsage -match $ClientAuthEKUs) -and
($_.'msPKI-Certificate-Policy')
} | ForEach-Object {
foreach ($policy in $_.'msPKI-Certificate-Policy') {
if ($ADCSObjects.'msPKI-Cert-Template-OID' -contains $policy) {
$OidToCheck = $ADCSObjects | Where-Object 'msPKI-Cert-Template-OID' -eq $policy
if ($OidToCheck.'msDS-OIDToGroupLink') {
foreach ($entry in $_.nTSecurityDescriptor.Access) {
$Principal = New-Object System.Security.Principal.NTAccount($entry.IdentityReference)
if ($Principal -match '^(S-1|O:)') {
$SID = $Principal
} else {
$SID = ($Principal.Translate([System.Security.Principal.SecurityIdentifier])).Value
}
if ( ($SID -notmatch $SafeUsers) -and ($entry.ActiveDirectoryRights -match 'ExtendedRight') ) {
$Issue = [pscustomobject]@{
Forest = $_.CanonicalName.split('/')[0]
Name = $_.Name
DistinguishedName = $_.DistinguishedName
IdentityReference = $entry.IdentityReference
ActiveDirectoryRights = $entry.ActiveDirectoryRights
LinkedGroup = $OidToCheck.'msDS-OIDToGroupLink'
Issue = @"
$($entry.IdentityReference) can enroll in this Client Authentication template
which is linked to the group $($OidToCheck.'msDS-OIDToGroupLink').
If $($entry.IdentityReference) uses this certificate for authentication, they
will gain the rights of the linked group while the group membership appears empty.
"@
Fix = @"
# Enable Manager Approval
`$Object = `'$($_.DistinguishedName)`'
Get-ADObject `$Object | Set-ADObject -Replace @{'msPKI-Enrollment-Flag' = 2}
"@
Revert = @"
# Disable Manager Approval
`$Object = `'$($_.DistinguishedName)`'
Get-ADObject `$Object | Set-ADObject -Replace @{'msPKI-Enrollment-Flag' = 0}
"@
Technique = 'ESC13'
}
$Issue
}
}
}
}
}
}
}
35 changes: 25 additions & 10 deletions Private/Find-ESC2.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,14 @@
#>
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[Parameter(Mandatory)]
[array]$ADCSObjects,
[Parameter(Mandatory = $true)]
[Parameter(Mandatory)]
[string]$SafeUsers
)
$ADCSObjects | Where-Object {
($_.ObjectClass -eq 'pKICertificateTemplate') -and
( (!$_.pkiExtendedKeyUsage) -or ($_.pkiExtendedKeyUsage -match '2.5.29.37.0') )-and
($_.'msPKI-Certificate-Name-Flag' -band 1) -and
( (!$_.pkiExtendedKeyUsage) -or ($_.pkiExtendedKeyUsage -match '2.5.29.37.0') ) -and
!($_.'msPKI-Enrollment-Flag' -band 2) -and
( ($_.'msPKI-RA-Signature' -eq 0) -or ($null -eq $_.'msPKI-RA-Signature') )
} | ForEach-Object {
Expand All @@ -44,21 +43,37 @@
} else {
$SID = ($Principal.Translate([System.Security.Principal.SecurityIdentifier])).Value
}
if ( ($SID -notmatch $SafeUsers) -and ($entry.ActiveDirectoryRights -match 'ExtendedRight') ) {
if ( ($SID -notmatch $SafeUsers) -and ( ($entry.ActiveDirectoryRights -match 'ExtendedRight') -or ($entry.ActiveDirectoryRights -match 'GenericAll') ) ) {
$Issue = [pscustomobject]@{
Forest = $_.CanonicalName.split('/')[0]
Name = $_.Name
DistinguishedName = $_.DistinguishedName
IdentityReference = $entry.IdentityReference
ActiveDirectoryRights = $entry.ActiveDirectoryRights
Issue = "$($entry.IdentityReference) can request a SubCA certificate without Manager Approval"
Fix = @"
Issue = @"
$($entry.IdentityReference) can use this template to request a Subordinate
Certification Authority (SubCA) certificate without Manager Approval.
The resultant certificate can be used by an attacker to instantiate their own
SubCA which is trusted by AD.
By default, certificates created from this attacker-controlled SubCA cannot be
used for authentication, but they can be used for other purposes such as TLS
certs and code signing.
However, if an attacker can modify the NtAuthCertificates object (see ESC5),
they can convert their rogue CA into one trusted for authentication.
"@
Fix = @"
# Enable Manager Approval
`$Object = `'$($_.DistinguishedName)`'
Get-ADObject `$Object | Set-ADObject -Replace @{'msPKI-Certificate-Name-Flag' = 0}
Get-ADObject `$Object | Set-ADObject -Replace @{'msPKI-Enrollment-Flag' = 2}
"@
Revert = @"
Revert = @"
# Disable Manager Approval
`$Object = `'$($_.DistinguishedName)`'
Get-ADObject `$Object | Set-ADObject -Replace @{'msPKI-Certificate-Name-Flag' = 1}
Get-ADObject `$Object | Set-ADObject -Replace @{'msPKI-Enrollment-Flag' = 0}
"@
Technique = 'ESC2'
}
Expand Down
Loading

0 comments on commit dfc0db3

Please sign in to comment.