Skip to content

Commit

Permalink
Prepare domain object attributes for ADCS ESC6 (#94)
Browse files Browse the repository at this point in the history
* Prepare domain object attributes for ADCS ESC6

* Correct property parsing, add produce false properties for uac

* Correct email tests for ReadUser and ReadComputer Properties
  • Loading branch information
definitelynotagoblin authored Jan 19, 2024
1 parent 4988061 commit 79a9b84
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 50 deletions.
78 changes: 33 additions & 45 deletions src/CommonLib/Processors/LDAPPropertyProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -148,42 +148,26 @@ public async Task<UserProperties> ReadUserProperties(ISearchResultEntry entry)
{
var userProps = new UserProperties();
var props = GetCommonProps(entry);


var uacFlags = (UacFlags)0;
var uac = entry.GetProperty(LDAPProperties.UserAccountControl);
bool enabled, trustedToAuth, sensitive, dontReqPreAuth, passwdNotReq, unconstrained, pwdNeverExpires;
if (int.TryParse(uac, out var flag))
{
var flags = (UacFlags)flag;
enabled = (flags & UacFlags.AccountDisable) == 0;
trustedToAuth = (flags & UacFlags.TrustedToAuthForDelegation) != 0;
sensitive = (flags & UacFlags.NotDelegated) != 0;
dontReqPreAuth = (flags & UacFlags.DontReqPreauth) != 0;
passwdNotReq = (flags & UacFlags.PasswordNotRequired) != 0;
unconstrained = (flags & UacFlags.TrustedForDelegation) != 0;
pwdNeverExpires = (flags & UacFlags.DontExpirePassword) != 0;
}
else
{
trustedToAuth = false;
enabled = true;
sensitive = false;
dontReqPreAuth = false;
passwdNotReq = false;
unconstrained = false;
pwdNeverExpires = false;
uacFlags = (UacFlags)flag;
}

props.Add("sensitive", uacFlags.HasFlag(UacFlags.NotDelegated));
props.Add("dontreqpreauth", uacFlags.HasFlag(UacFlags.DontReqPreauth));
props.Add("passwordnotreqd", uacFlags.HasFlag(UacFlags.PasswordNotRequired));
props.Add("unconstraineddelegation", uacFlags.HasFlag(UacFlags.TrustedForDelegation));
props.Add("pwdneverexpires", uacFlags.HasFlag(UacFlags.DontExpirePassword));
props.Add("enabled", !uacFlags.HasFlag(UacFlags.AccountDisable));
props.Add("trustedtoauth", uacFlags.HasFlag(UacFlags.TrustedToAuthForDelegation));

props.Add("sensitive", sensitive);
props.Add("dontreqpreauth", dontReqPreAuth);
props.Add("passwordnotreqd", passwdNotReq);
props.Add("unconstraineddelegation", unconstrained);
props.Add("pwdneverexpires", pwdNeverExpires);
props.Add("enabled", enabled);
props.Add("trustedtoauth", trustedToAuth);
var domain = Helpers.DistinguishedNameToDomain(entry.DistinguishedName);

var comps = new List<TypedPrincipal>();
if (trustedToAuth)
if (uacFlags.HasFlag(UacFlags.TrustedToAuthForDelegation))
{
var delegates = entry.GetArrayProperty(LDAPProperties.AllowedToDelegateTo);
props.Add("allowedtodelegate", delegates);
Expand Down Expand Up @@ -276,27 +260,23 @@ public async Task<ComputerProperties> ReadComputerProperties(ISearchResultEntry
{
var compProps = new ComputerProperties();
var props = GetCommonProps(entry);


var flags = (UacFlags)0;
var uac = entry.GetProperty(LDAPProperties.UserAccountControl);
bool enabled, unconstrained, trustedToAuth;
if (int.TryParse(uac, out var flag))
{
var flags = (UacFlags)flag;
enabled = (flags & UacFlags.AccountDisable) == 0;
unconstrained = (flags & UacFlags.TrustedForDelegation) == UacFlags.TrustedForDelegation;
trustedToAuth = (flags & UacFlags.TrustedToAuthForDelegation) != 0;
}
else
{
unconstrained = false;
enabled = true;
trustedToAuth = false;
flags = (UacFlags)flag;
}

props.Add("enabled", !flags.HasFlag(UacFlags.AccountDisable));
props.Add("unconstraineddelegation", flags.HasFlag(UacFlags.TrustedForDelegation));
props.Add("trustedtoauth", flags.HasFlag(UacFlags.TrustedToAuthForDelegation));
props.Add("isdc", flags.HasFlag(UacFlags.ServerTrustAccount));

var domain = Helpers.DistinguishedNameToDomain(entry.DistinguishedName);

var comps = new List<TypedPrincipal>();
if (trustedToAuth)
if (flags.HasFlag(UacFlags.TrustedToAuthForDelegation))
{
var delegates = entry.GetArrayProperty(LDAPProperties.AllowedToDelegateTo);
props.Add("allowedtodelegate", delegates);
Expand Down Expand Up @@ -332,15 +312,13 @@ public async Task<ComputerProperties> ReadComputerProperties(ISearchResultEntry

compProps.AllowedToAct = allowedToActPrincipals.ToArray();

props.Add("enabled", enabled);
props.Add("unconstraineddelegation", unconstrained);
props.Add("trustedtoauth", trustedToAuth);
props.Add("lastlogon", Helpers.ConvertFileTimeToUnixEpoch(entry.GetProperty(LDAPProperties.LastLogon)));
props.Add("lastlogontimestamp",
Helpers.ConvertFileTimeToUnixEpoch(entry.GetProperty(LDAPProperties.LastLogonTimestamp)));
props.Add("pwdlastset",
Helpers.ConvertFileTimeToUnixEpoch(entry.GetProperty(LDAPProperties.PasswordLastSet)));
props.Add("serviceprincipalnames", entry.GetArrayProperty(LDAPProperties.ServicePrincipalNames));
props.Add("email", entry.GetProperty(LDAPProperties.Email));
var os = entry.GetProperty(LDAPProperties.OperatingSystem);
var sp = entry.GetProperty(LDAPProperties.ServicePack);

Expand Down Expand Up @@ -516,6 +494,16 @@ public static Dictionary<string, object> ReadCertTemplateProperties(ISearchResul
nameFlags.HasFlag(PKICertificateNameFlag.ENROLLEE_SUPPLIES_SUBJECT));
props.Add("subjectaltrequireupn",
nameFlags.HasFlag(PKICertificateNameFlag.SUBJECT_ALT_REQUIRE_UPN));
props.Add("subjectaltrequiredns",
nameFlags.HasFlag(PKICertificateNameFlag.SUBJECT_ALT_REQUIRE_DNS));
props.Add("subjectaltrequiredomaindns",
nameFlags.HasFlag(PKICertificateNameFlag.SUBJECT_ALT_REQUIRE_DOMAIN_DNS));
props.Add("subjectaltrequireemail",
nameFlags.HasFlag(PKICertificateNameFlag.SUBJECT_ALT_REQUIRE_EMAIL));
props.Add("subjectaltrequirespn",
nameFlags.HasFlag(PKICertificateNameFlag.SUBJECT_ALT_REQUIRE_SPN));
props.Add("subjectrequireemail",
nameFlags.HasFlag(PKICertificateNameFlag.SUBJECT_REQUIRE_EMAIL));
}

string[] ekus = entry.GetArrayProperty(LDAPProperties.ExtendedKeyUsage);
Expand Down Expand Up @@ -761,4 +749,4 @@ public class ComputerProperties
public TypedPrincipal[] SidHistory { get; set; } = Array.Empty<TypedPrincipal>();
public TypedPrincipal[] DumpSMSAPassword { get; set; } = Array.Empty<TypedPrincipal>();
}
}
}
2 changes: 1 addition & 1 deletion src/CommonLib/SearchResultEntryWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public ResolvedSearchResult ResolveBloodHoundInfo()
if (int.TryParse(uac, out var flag))
{
var flags = (UacFlags) flag;
if ((flags & UacFlags.ServerTrustAccount) != 0)
if (flags.HasFlag(UacFlags.ServerTrustAccount))
{
_log.LogTrace("Marked {SID} as a domain controller", objectId);
res.IsDomainController = true;
Expand Down
21 changes: 17 additions & 4 deletions test/unit/LDAPPropertyTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,7 @@ public async Task LDAPPropertyProcessor_ReadUserProperties_HappyPath()
{"lastlogon", "132673011142753043"},
{"lastlogontimestamp", "132670318095676525"},
{"homedirectory", @"\\win10\testdir"},
{"mail", "[email protected]"},
{
"serviceprincipalname", new[]
{
Expand Down Expand Up @@ -298,6 +299,8 @@ public async Task LDAPPropertyProcessor_ReadUserProperties_HappyPath()
Assert.Equal(1568693134, (long)props["pwdlastset"]);
Assert.Contains("homedirectory", keys);
Assert.Equal(@"\\win10\testdir", props["homedirectory"] as string);
Assert.Contains("email", keys);
Assert.Equal("[email protected]", props["email"] as string);

//UAC stuff
Assert.Contains("sensitive", keys);
Expand Down Expand Up @@ -397,6 +400,7 @@ public async Task LDAPPropertyProcessor_ReadComputerProperties_HappyPath()
{"lastlogontimestamp", "132670318095676525"},
{"operatingsystem", "Windows 10 Enterprise"},
{"operatingsystemservicepack", "1607"},
{"mail", "[email protected]"},
{"admincount", "c"},
{
"sidhistory", new[]
Expand Down Expand Up @@ -434,11 +438,15 @@ public async Task LDAPPropertyProcessor_ReadComputerProperties_HappyPath()
//UAC
Assert.Contains("enabled", keys);
Assert.Contains("unconstraineddelegation", keys);
Assert.Contains("trustedtoauth", keys);
Assert.Contains("isdc", keys);
Assert.Contains("lastlogon", keys);
Assert.Contains("lastlogontimestamp", keys);
Assert.Contains("pwdlastset", keys);
Assert.True((bool)props["enabled"]);
Assert.False((bool)props["unconstraineddelegation"]);
Assert.True((bool)props["trustedtoauth"]);
Assert.False((bool)props["isdc"]);

Assert.Contains("lastlogon", keys);
Assert.Equal(1622827514, (long)props["lastlogon"]);
Expand All @@ -462,6 +470,8 @@ public async Task LDAPPropertyProcessor_ReadComputerProperties_HappyPath()
Assert.Equal("Windows 10 Enterprise 1607", props["operatingsystem"] as string);
Assert.Contains("description", keys);
Assert.Equal("Test", props["description"] as string);
Assert.Contains("email", keys);
Assert.Equal("[email protected]", props["email"] as string);

//SidHistory
Assert.Contains("sidhistory", keys);
Expand Down Expand Up @@ -700,9 +710,7 @@ public void LDAPPropertyProcessor_ReadCertTemplateProperties()
{"oid", "1.3.6.1.4.1.311.21.8.4571196.1884641.3293620.10686285.12068043.134.1.30"},
{"enrollmentflag", 32},
{"requiresmanagerapproval", false},
{"certificatenameflag", 134217728},
{"enrolleesuppliessubject", false},
{"subjectaltrequireupn", false},
{"certificatenameflag", 0x8000000},
{"ekus", new[]
{"1.3.6.1.5.5.7.3.2"}
},
Expand Down Expand Up @@ -739,6 +747,11 @@ public void LDAPPropertyProcessor_ReadCertTemplateProperties()
Assert.Contains("certificatenameflag", keys);
Assert.Contains("enrolleesuppliessubject", keys);
Assert.Contains("subjectaltrequireupn", keys);
Assert.Contains("subjectaltrequiredns", keys);
Assert.Contains("subjectaltrequiredomaindns", keys);
Assert.Contains("subjectaltrequireemail", keys);
Assert.Contains("subjectaltrequirespn", keys);
Assert.Contains("subjectrequireemail", keys);
Assert.Contains("ekus", keys);
Assert.Contains("certificateapplicationpolicy", keys);
Assert.Contains("authorizedsignatures", keys);
Expand Down Expand Up @@ -833,4 +846,4 @@ public void LDAPPropertyProcessor_ParseAllProperties_CollectionCountOne_NotBadPa
}

}
}
}

0 comments on commit 79a9b84

Please sign in to comment.