TrimarcJake / Locksmith

A small tool built to find and fix common misconfigurations in Active Directory Certificate Services.

Home Page:https://github.com/TrimarcJake/Locksmith

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

SID Translation Error in the Find-ESC4 function

SamErde opened this issue · comments

I just encountered an error during SID translation in the Find-ESC4 function, and I haven't yet figured out what is causing it. This is probably related to something in my environment because we have not encountered these errors before, but I want to log it and figure it out.

[ADMIN]: D:\Files>.\Invoke-Locksmith.ps1 -Forest REDACTED
Gathering AD CS Objects from REDACTED...
Identifying auditing issues...
Identifying AD CS templates with dangerous configurations...
Identifying AD CS template and other objects with poor access control...
Exception calling "Translate" with "1" argument(s): "Some or all identity references could not be translated."
At D:\Files\Invoke-Locksmith.ps1:454 char:13
+             $SID = ($Principal.Translate([System.Security.Principal.S ...
+             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : IdentityNotMappedException

I looked a few lines above this and tried running $Principal = New-Object System.Security.Principal.NTAccount($_.nTSecurityDescriptor.Owner) and this also resulted in an error:

New-Object : A constructor was not found. Cannot find an appropriate constructor for type System.Security.Principal.NTAccount.
At line:1 char:14
+ ... Principal = New-Object System.Security.Principal.NTAccount($_.nTSecur ...
+                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (:) [New-Object], PSArgumentException
    + FullyQualifiedErrorId : CannotFindAppropriateCtor,Microsoft.PowerShell.Commands.NewObjectCommand

For some reason it is failing to get the security principal of the current user and then failing to get the SID of the user. I do want to figure out why, but as an experiment I tried this code to get the SID, and it worked:

Add-Type -AssemblyName System.DirectoryServices.AccountManagement            
$SID = ([System.DirectoryServices.AccountManagement.UserPrincipal]::Current).SID.Value 

Systems Tested:

  • Windows Server 2016
  • Windows Server 2019
  • PowerShell 5.1
  • PowerShell 7.3.2

Privileges Used:

  • Runas Admin
  • Domain Admin

Will add more notes as I have time to reproduce and test. Additional thoughts are welcomed!

My latest testing produces these notes for my test cases:

# Works on PS5.1 and PS7
[array]$AuditingIssues = Find-AuditingIssue -ADCSObjects $ADCSObjects 

# Works on PS5.1, error on PS7
[array]$ESC1 = Find-ESC1 -ADCSObjects $ADCSObjects -SafeUsers $SafeUsers
[array]$ESC2 = Find-ESC2 -ADCSObjects $ADCSObjects -SafeUsers $SafeUsers

# These two fail on PS5.1 and PS7:
[array]$ESC4 = Find-ESC4 -ADCSObjects $ADCSObjects -SafeUsers $SafeUsers -DangerousRights $DangerousRights -SafeOwners $SafeOwners
[array]$ESC5 = Find-ESC5 -ADCSObjects $ADCSObjects -SafeUsers $SafeUsers -DangerousRights $DangerousRights -SafeOwners $SafeOwners

# Works on PS5.1 and PS7
[array]$ESC6 = Find-ESC6 -ADCSObjects $ADCSObjects

Running the script through line ~360 successfully loads the data and creates the ADCSObjects object. Looking at a few of the samples, we found that failing checks were likely due to ADCS objects that had owners with unresolved SIDs. These AD CS objects can be found using the following statement:

($ADCSObjects).Where({ $_.ntSecurityDescriptor.Owner -like "O:*" })

@SamErde I just committed a bugfix for this issue, but I know you already fixed it in your environment!

Great! I just looked and hope to have some time today to dig a little deeper into the SDDL format to make sure we’re effectively handling the cases of unresolved SIDs, regardless of where they show up.

I'm curious but not fully confidence about something yet. Is the "O:" notation indicative of an "ownership" control? I'm looking at the "Security Descriptor String Format" docs and think this may be related. If so, we might need to change this regex depending on which ESC is being checked for (unsafe users vs unsafe owners)--or just update the functions to look for an unresolved SID instead of this specific descriptor.

In my experience, the "O:" is not solely found in the .nTSecurityDescriptor.Owner. It can also be found in .nTSecurityDescriptor.Access. Since we were already checking for unresolved SIDs in all functions using the '^S-1' regex selector, I updated the regex selector in all functions to '^S-1|^O:' which would check for unresolved SIDs of either type.

Side note: I realize now that we use that SID translation code in a bunch of places; it should probably be moved into its own function!

Yes! I noticed a few opportunities for that, too. Thanks for the explanation!

In my experience, the "O:" is not solely found in the .nTSecurityDescriptor.Owner. It can also be found in .nTSecurityDescriptor.Access. Since we were already checking for unresolved SIDs in all functions using the '^S-1' regex selector, I updated the regex selector in all functions to '^S-1|^O:' which would check for unresolved SIDs of either type.

Side note: I realize now that we use that SID translation code in a bunch of places; it should probably be moved into its own function!

Thanks, I finally got around to testing this. We will be ready to roll with one minor fix to your bug fix! The regex selector should be '^(S-1|O:)' instead of '^S-1|^O:' and it will work!

@SamErde Powershell regex is dumb. lol