Skip to content

Commit 09344aa

Browse files
feat: collect delegated managed service accounts
I now classify delegated managed service accounts separately, collect their predecessor links, and emit CreateDMSA rights from access controls on valid OU and container parents. Signed-off-by: Adil Alperen Çiftci <adilalperenciftci@users.noreply.github.com>
1 parent d975701 commit 09344aa

15 files changed

Lines changed: 154 additions & 10 deletions

‎src/CommonLib/DirectoryObjects/DirectoryObjectExtensions.cs‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,15 @@ public static bool IsGMSA(this IDirectoryObject directoryObject) {
2020

2121
return classes.Contains(ObjectClass.GMSAClass, StringComparer.InvariantCultureIgnoreCase);
2222
}
23-
23+
24+
public static bool IsDMSA(this IDirectoryObject directoryObject) {
25+
if (!directoryObject.TryGetArrayProperty(LDAPProperties.ObjectClass, out var classes)) {
26+
return false;
27+
}
28+
29+
return classes.Contains(ObjectClass.DMSAClass, StringComparer.InvariantCultureIgnoreCase);
30+
}
31+
2432
public static bool GetObjectIdentifier(this IDirectoryObject directoryObject, out string objectIdentifier) {
2533
// Builtin container has a SID (always "S-1-5-32"). We use the ObjectGUID as ID like for other containers
2634
if (directoryObject.TryGetArrayProperty(LDAPProperties.ObjectClass, out var objectClasses) &&

‎src/CommonLib/Enums/DataType.cs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,6 @@ public static class DataType
1818
public const string Sites = "sites";
1919
public const string SiteServers = "siteservers";
2020
public const string SiteSubnets = "sitesubnets";
21+
public const string DMSAs = "dmsas";
2122
}
2223
}

‎src/CommonLib/Enums/EdgeNames.cs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ public static class EdgeNames
2626
public const string WritePublicInformation = "WritePublicInformation";
2727
public const string WriteSupersededManagedAccountLink = "WriteSupersededManagedAccountLink";
2828
public const string WriteSupersededServiceAccountState = "WriteSupersededServiceAccountState";
29+
public const string CreateDMSA = "CreateDMSA";
2930
public const string ServerIs = "ServerIs";
3031

3132
//CertAbuse edges

‎src/CommonLib/Enums/LDAPProperties.cs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
public static class LDAPProperties
44
{
55
public const string GroupMSAMembership = "msds-groupmsamembership";
6+
public const string ManagedAccountPrecededByLink = "msds-managedaccountprecededbylink";
67
public const string UserAccountControl = "useraccountcontrol";
78
public const string IsDeleted = "isdeleted";
89
public const string SAMAccountType = "samaccounttype";

‎src/CommonLib/Enums/Labels.cs‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ public enum Label
2121
IssuancePolicy,
2222
Site,
2323
SiteServer,
24-
SiteSubnet
24+
SiteSubnet,
25+
DMSA
2526
}
2627
}

‎src/CommonLib/Enums/ObjectClass.cs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ public static class ObjectClass {
1414
public const string OIDContainerClass = "msPKI-Enterprise-Oid";
1515
public const string GMSAClass = "msds-groupmanagedserviceaccount";
1616
public const string MSAClass = "msds-managedserviceaccount";
17+
public const string DMSAClass = "msds-delegatedmanagedserviceaccount";
1718
public const string SiteClass = "site";
1819
public const string SiteServerClass = "server";
1920
public const string SiteSubnetClass = "subnet";

‎src/CommonLib/LdapQueries/CommonProperties.cs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ public static class CommonProperties
6262
LDAPProperties.MinPwdLength, LDAPProperties.PwdProperties, LDAPProperties.MinPwdAge,
6363
LDAPProperties.MaxPwdAge, LDAPProperties.PwdHistoryLength, LDAPProperties.LockoutDuration,
6464
LDAPProperties.LockoutThreshold, LDAPProperties.LockOutObservationWindow, LDAPProperties.GroupType,
65-
LDAPProperties.PrincipalName
65+
LDAPProperties.PrincipalName, LDAPProperties.ManagedAccountPrecededByLink
6666
};
6767

6868
public static readonly string[] ContainerProps =

‎src/CommonLib/LdapUtils.cs‎

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1166,12 +1166,18 @@ internal static bool ResolveLabel(string objectIdentifier, string distinguishedN
11661166
return true;
11671167
}
11681168

1169-
//Override GMSA/MSA account to treat them as users for the graph
1170-
if (objectClasses != null &&
1171-
(objectClasses.Contains(ObjectClass.MSAClass, StringComparer.OrdinalIgnoreCase) ||
1172-
objectClasses.Contains(ObjectClass.GMSAClass, StringComparer.OrdinalIgnoreCase))) {
1173-
type = Label.User;
1174-
return true;
1169+
if (objectClasses != null) {
1170+
if (objectClasses.Contains(ObjectClass.DMSAClass, StringComparer.OrdinalIgnoreCase)) {
1171+
type = Label.DMSA;
1172+
return true;
1173+
}
1174+
1175+
//Override GMSA/MSA account to treat them as users for the graph
1176+
if (objectClasses.Contains(ObjectClass.MSAClass, StringComparer.OrdinalIgnoreCase) ||
1177+
objectClasses.Contains(ObjectClass.GMSAClass, StringComparer.OrdinalIgnoreCase)) {
1178+
type = Label.User;
1179+
return true;
1180+
}
11751181
}
11761182

11771183
if (samAccountType != null) {
@@ -1344,6 +1350,7 @@ private static string ComputeDisplayName(IDirectoryObject directoryObject, strin
13441350
string displayName;
13451351
switch (label) {
13461352
case Label.User:
1353+
case Label.DMSA:
13471354
case Label.Group:
13481355
case Label.Base:
13491356
if (!string.IsNullOrWhiteSpace(samAccountName)) {

‎src/CommonLib/OutputTypes/DMSA.cs‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
namespace SharpHoundCommonLib.OutputTypes
2+
{
3+
public class DMSA : OutputBase
4+
{
5+
public TypedPrincipal PrecededBy { get; set; }
6+
}
7+
}

‎src/CommonLib/Processors/ACEGuids.cs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ public class ACEGuids
1919
public const string WritePublicInformation = "e48d0154-bcf8-11d1-8702-00c04fb96050";
2020
public const string WriteSupersededManagedAccountLink = "3752e002-43be-48c8-b3ca-2cb2fffbc8a1";
2121
public const string WriteSupersededServiceAccountState = "a4693096-a4c3-4ecd-b8cb-73cd6398b7a2";
22+
public const string DMSAClass = "0feb936f-47b3-49f2-9386-1dedc2c23765";
2223

2324
//Cert abuse ACEs
2425
public const string PKINameFlag = "ea1dddc4-60ff-416e-8cc0-17cee534bce7";

0 commit comments

Comments
 (0)