From 3cb3855ce05afb58f556cc1caabc4b0900f81503 Mon Sep 17 00:00:00 2001 From: Lars Karlslund Date: Thu, 6 Oct 2022 14:47:00 +0200 Subject: [PATCH] Fix for swapping the wrong UUID, added AutoEnroll permission and VoodooBit detector --- modules/engine/securitydescriptor.go | 56 +++++++++++-------- .../activedirectory/analyze/analyze-ad.go | 48 ++++++++++++++-- modules/integrations/activedirectory/pwns.go | 4 +- 3 files changed, 78 insertions(+), 30 deletions(-) diff --git a/modules/engine/securitydescriptor.go b/modules/engine/securitydescriptor.go index 270cfca..c5cc9ad 100644 --- a/modules/engine/securitydescriptor.go +++ b/modules/engine/securitydescriptor.go @@ -174,7 +174,7 @@ func ParseACLentry(odata []byte) (ACE, []byte, error) { if err != nil { return ace, data, err } - ace.InheritedObjectType = util.SwapUUIDEndianess(ace.InheritedObjectType) + ace.ObjectType = util.SwapUUIDEndianess(ace.ObjectType) data = data[16:] } if ace.Flags&INHERITED_OBJECT_TYPE_PRESENT != 0 { @@ -182,7 +182,7 @@ func ParseACLentry(odata []byte) (ACE, []byte, error) { if err != nil { return ace, data, err } - ace.ObjectType = util.SwapUUIDEndianess(ace.ObjectType) + ace.InheritedObjectType = util.SwapUUIDEndianess(ace.InheritedObjectType) data = data[16:] } } @@ -194,6 +194,9 @@ func ParseACLentry(odata []byte) (ACE, []byte, error) { return ace, odata[acesize:], nil } +var ExtendedRightCertificateEnroll, _ = uuid.FromString("0e10c968-78fb-11d2-90d4-00c04f79dc55") +var ExtendedRightCertificateAutoEnroll, _ = uuid.FromString("a05b8cc2-17bc-4802-a710-e7c15ab866a2") + func (a ACL) IsObjectClassAccessAllowed(index int, testObject *Object, mask Mask, guid uuid.UUID, ao *Objects) bool { if a.Entries[index].Type == ACETYPE_ACCESS_DENIED || a.Entries[index].Type == ACETYPE_ACCESS_DENIED_OBJECT { return false @@ -269,6 +272,9 @@ func (a ACE) matchObjectClassAndGUID(o *Object, requestedAccess Mask, g uuid.UUI // This ACE only applies to some kinds of attributes / extended rights? if !a.ObjectType.IsNil() { typematch := a.ObjectType == g + if typematch && requestedAccess == RIGHT_DS_CONTROL_ACCESS { + typematch = true + } if !typematch { // Lets chack if this requested guid is part of a group which is allowed cachedset, found := objectSecurityGUIDcache.Load(g) @@ -341,7 +347,7 @@ func (a ACE) String(ao *Objects) string { if a.Flags&OBJECT_TYPE_PRESENT != 0 { // ui.Debug().Msgf("Looking for right %v", a.ObjectType) - result += "OBJECT_TYPE_PRESENT " + result += " OBJECT_TYPE_PRESENT" av := AttributeValueGUID(a.ObjectType) if ao != nil { if o, found := ao.Find(RightsGUID, av); found { @@ -382,65 +388,69 @@ func (a ACE) String(ao *Objects) string { result += fmt.Sprintf("MASK %08x", a.Mask) var rights []string - if a.Mask&RIGHT_GENERIC_READ != 0 { + if a.Mask&RIGHT_GENERIC_READ == RIGHT_GENERIC_READ { rights = append(rights, "GENERIC_READ") } - if a.Mask&RIGHT_GENERIC_WRITE != 0 { + if a.Mask&RIGHT_GENERIC_WRITE == RIGHT_GENERIC_WRITE { rights = append(rights, "GENERIC_WRITE") } - if a.Mask&RIGHT_GENERIC_EXECUTE != 0 { + if a.Mask&RIGHT_GENERIC_EXECUTE == RIGHT_GENERIC_EXECUTE { rights = append(rights, "GENERIC_EXECUTE") } - if a.Mask&RIGHT_GENERIC_ALL != 0 { + if a.Mask&RIGHT_GENERIC_ALL == RIGHT_GENERIC_ALL { rights = append(rights, "GENERIC_ALL") } - if a.Mask&RIGHT_MAXIMUM_ALLOWED != 0 { + if a.Mask&RIGHT_MAXIMUM_ALLOWED == RIGHT_MAXIMUM_ALLOWED { rights = append(rights, "MAXIMUM_ALLOWED") } - if a.Mask&RIGHT_ACCESS_SYSTEM_SECURITY != 0 { + if a.Mask&RIGHT_ACCESS_SYSTEM_SECURITY == RIGHT_ACCESS_SYSTEM_SECURITY { rights = append(rights, "ACCESS_SYSTEM_SECURITY") } - if a.Mask&RIGHT_SYNCRONIZE != 0 { + if a.Mask&RIGHT_SYNCRONIZE == RIGHT_SYNCRONIZE { rights = append(rights, "SYNCRONIZE") } - if a.Mask&RIGHT_WRITE_OWNER != 0 { + if a.Mask&RIGHT_WRITE_OWNER == RIGHT_WRITE_OWNER { rights = append(rights, "WRITE_OWNER") } - if a.Mask&RIGHT_WRITE_DACL != 0 { + if a.Mask&RIGHT_WRITE_DACL == RIGHT_WRITE_DACL { rights = append(rights, "WRITE_DACL") } - if a.Mask&RIGHT_READ_CONTROL != 0 { + if a.Mask&RIGHT_READ_CONTROL == RIGHT_READ_CONTROL { rights = append(rights, "READ_CONTROL") } - if a.Mask&RIGHT_DELETE != 0 { + if a.Mask&RIGHT_DELETE == RIGHT_DELETE { rights = append(rights, "DELETE") } - if a.Mask&RIGHT_DS_CONTROL_ACCESS != 0 { + if a.Mask&RIGHT_DS_CONTROL_ACCESS == RIGHT_DS_CONTROL_ACCESS { rights = append(rights, "DS_CONTROL_ACCESS") } - if a.Mask&RIGHT_DS_LIST_OBJECT != 0 { + if a.Mask&RIGHT_DS_VOODOO_BIT == RIGHT_DS_VOODOO_BIT { + rights = append(rights, "DS_VOODOO_BIT") + } + + if a.Mask&RIGHT_DS_LIST_OBJECT == RIGHT_DS_LIST_OBJECT { rights = append(rights, "DS_LIST_OBJECT") } - if a.Mask&RIGHT_DS_DELETE_TREE != 0 { + if a.Mask&RIGHT_DS_DELETE_TREE == RIGHT_DS_DELETE_TREE { rights = append(rights, "DS_DELETE_TREE") } - if a.Mask&RIGHT_DS_WRITE_PROPERTY != 0 { + if a.Mask&RIGHT_DS_WRITE_PROPERTY == RIGHT_DS_WRITE_PROPERTY { rights = append(rights, "DS_WRITE_PROPERTY") } - if a.Mask&RIGHT_DS_READ_PROPERTY != 0 { + if a.Mask&RIGHT_DS_READ_PROPERTY == RIGHT_DS_READ_PROPERTY { rights = append(rights, "DS_READ_PROPERTY") } - if a.Mask&RIGHT_DS_WRITE_PROPERTY_EXTENDED != 0 { + if a.Mask&RIGHT_DS_WRITE_PROPERTY_EXTENDED == RIGHT_DS_WRITE_PROPERTY_EXTENDED { rights = append(rights, "DS_WRITE_PROPERTY_EXTENDED") } - if a.Mask&RIGHT_DS_LIST_CONTENTS != 0 { + if a.Mask&RIGHT_DS_LIST_CONTENTS == RIGHT_DS_LIST_CONTENTS { rights = append(rights, "DS_LIST_CONTENTS") } - if a.Mask&RIGHT_DS_DELETE_CHILD != 0 { + if a.Mask&RIGHT_DS_DELETE_CHILD == RIGHT_DS_DELETE_CHILD { rights = append(rights, "DS_DELETE_CHILD") } - if a.Mask&RIGHT_DS_CREATE_CHILD != 0 { + if a.Mask&RIGHT_DS_CREATE_CHILD == RIGHT_DS_CREATE_CHILD { rights = append(rights, "DS_CREATE_CHILD") } result += " " + strings.Join(rights, " | ") diff --git a/modules/integrations/activedirectory/analyze/analyze-ad.go b/modules/integrations/activedirectory/analyze/analyze-ad.go index a97f90e..af6e6f9 100644 --- a/modules/integrations/activedirectory/analyze/analyze-ad.go +++ b/modules/integrations/activedirectory/analyze/analyze-ad.go @@ -16,7 +16,7 @@ import ( // Interesting permissions on AD var ( - ResetPwd = uuid.UUID{0x00, 0x29, 0x95, 0x70, 0x24, 0x6d, 0x11, 0xd0, 0xa7, 0x68, 0x00, 0xaa, 0x00, 0x6e, 0x05, 0x29} + ResetPwd, _ = uuid.FromString("{00299570-246d-11d0-a768-00aa006e0529}") DSReplicationGetChanges = uuid.UUID{0x11, 0x31, 0xf6, 0xaa, 0x9c, 0x07, 0x11, 0xd1, 0xf7, 0x9f, 0x00, 0xc0, 0x4f, 0xc2, 0xdc, 0xd2} DSReplicationGetChangesAll = uuid.UUID{0x11, 0x31, 0xf6, 0xad, 0x9c, 0x07, 0x11, 0xd1, 0xf7, 0x9f, 0x00, 0xc0, 0x4f, 0xc2, 0xdc, 0xd2} DSReplicationSyncronize = uuid.UUID{0x11, 0x31, 0xf6, 0xab, 0x9c, 0x07, 0x11, 0xd1, 0xf7, 0x9f, 0x00, 0xc0, 0x4f, 0xc2, 0xdc, 0xd2} @@ -33,12 +33,13 @@ var ( AttributeAltSecurityIdentitiesGUID, _ = uuid.FromString("{00FBF30C-91FE-11D1-AEBC-0000F80367C1}") AttributeProfilePathGUID, _ = uuid.FromString("{bf967a05-0de6-11d0-a285-00aa003049e2}") AttributeScriptPathGUID, _ = uuid.FromString("{bf9679a8-0de6-11d0-a285-00aa003049e2}") - AttributeMSDSManagedPasswordId, _ = uuid.FromString("0e78295a-c6d3-0a40-b491-d62251ffa0a6") + AttributeMSDSManagedPasswordId, _ = uuid.FromString("{0e78295a-c6d3-0a40-b491-d62251ffa0a6}") - ExtendedRightCertificateEnroll, _ = uuid.FromString("0e10c968-78fb-11d2-90d4-00c04f79dc55") + ExtendedRightCertificateEnroll, _ = uuid.FromString("{0e10c968-78fb-11d2-90d4-00c04f79dc55}") + ExtendedRightCertificateAutoEnroll, _ = uuid.FromString("{a05b8cc2-17bc-4802-a710-e7c15ab866a2}") - ValidateWriteSelfMembership, _ = uuid.FromString("bf9679c0-0de6-11d0-a285-00aa003049e2") - ValidateWriteSPN, _ = uuid.FromString("f3a64788-5306-11d1-a9c5-0000f80367c1") + ValidateWriteSelfMembership, _ = uuid.FromString("{bf9679c0-0de6-11d0-a285-00aa003049e2}") + ValidateWriteSPN, _ = uuid.FromString("{f3a64788-5306-11d1-a9c5-0000f80367c1}") ObjectGuidUser = uuid.UUID{0xbf, 0x96, 0x7a, 0xba, 0x0d, 0xe6, 0x11, 0xd0, 0xa2, 0x85, 0x00, 0xaa, 0x00, 0x30, 0x49, 0xe2} ObjectGuidComputer = uuid.UUID{0xbf, 0x96, 0x7a, 0x86, 0x0d, 0xe6, 0x11, 0xd0, 0xa2, 0x85, 0x00, 0xaa, 0x00, 0x30, 0x49, 0xe2} @@ -676,13 +677,48 @@ func init() { continue } for index, acl := range sd.DACL.Entries { - if sd.DACL.IsObjectClassAccessAllowed(index, o, engine.RIGHT_DS_CONTROL_ACCESS, ExtendedRightCertificateEnroll, ao) { + // https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-crtd/211ab1e3-bad6-416d-9d56-8480b42617a4 + if sd.DACL.IsObjectClassAccessAllowed(index, o, engine.RIGHT_DS_CONTROL_ACCESS, ExtendedRightCertificateEnroll, ao) || + sd.DACL.IsObjectClassAccessAllowed(index, o, engine.RIGHT_DS_VOODOO_BIT, uuid.Nil, ao) { ao.FindOrAddAdjacentSID(acl.SID, o).EdgeTo(o, activedirectory.EdgeCertificateEnroll) } } } }, "Permission to enroll into a certificate template", engine.BeforeMergeFinal) + Loader.AddProcessor(func(ao *engine.Objects) { + for _, o := range ao.Slice() { + if o.Type() != engine.ObjectTypeCertificateTemplate { + continue + } + sd, err := o.SecurityDescriptor() + if err != nil { + continue + } + for index, acl := range sd.DACL.Entries { + // https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-crtd/211ab1e3-bad6-416d-9d56-8480b42617a4 + if sd.DACL.IsObjectClassAccessAllowed(index, o, engine.RIGHT_DS_CONTROL_ACCESS, ExtendedRightCertificateAutoEnroll, ao) || + sd.DACL.IsObjectClassAccessAllowed(index, o, engine.RIGHT_DS_VOODOO_BIT, uuid.Nil, ao) { + ao.FindOrAddAdjacentSID(acl.SID, o).EdgeTo(o, activedirectory.EdgeCertificateAutoEnroll) + } + } + } + }, "Permission to auto-enroll into a certificate template", engine.BeforeMergeFinal) + + Loader.AddProcessor(func(ao *engine.Objects) { + for _, o := range ao.Slice() { + sd, err := o.SecurityDescriptor() + if err != nil { + continue + } + for index, acl := range sd.DACL.Entries { + if sd.DACL.IsObjectClassAccessAllowed(index, o, engine.RIGHT_DS_VOODOO_BIT, uuid.Nil, ao) { + ao.FindOrAddAdjacentSID(acl.SID, o).EdgeTo(o, activedirectory.EdgeVoodooBit) + } + } + } + }, "Has the Voodoo Bit set", engine.BeforeMergeFinal) + Loader.AddProcessor(func(ao *engine.Objects) { for _, o := range ao.Slice() { if o.Type() != engine.ObjectTypeDomainDNS { diff --git a/modules/integrations/activedirectory/pwns.go b/modules/integrations/activedirectory/pwns.go index b887249..93e6906 100644 --- a/modules/integrations/activedirectory/pwns.go +++ b/modules/integrations/activedirectory/pwns.go @@ -17,7 +17,7 @@ var ( EdgeGenericAll = engine.NewEdge("GenericAll") EdgeWriteAll = engine.NewEdge("WriteAll") EdgeWritePropertyAll = engine.NewEdge("WritePropertyAll") - EdgeWriteExtendedAll = engine.NewEdge("ExtendedAll") + EdgeWriteExtendedAll = engine.NewEdge("WriteExtendedAll") EdgeTakeOwnership = engine.NewEdge("TakeOwnership") EdgeWriteDACL = engine.NewEdge("WriteDACL") EdgeWriteSPN = engine.NewEdge("WriteSPN").RegisterProbabilityCalculator(func(source, target *engine.Object) engine.Probability { @@ -77,4 +77,6 @@ var ( EdgeWriteProfilePath = engine.NewEdge("WriteProfilePath") EdgeWriteScriptPath = engine.NewEdge("WriteScriptPath") EdgeCertificateEnroll = engine.NewEdge("CertificateEnroll") + EdgeCertificateAutoEnroll = engine.NewEdge("CertificateAutoEnroll") + EdgeVoodooBit = engine.NewEdge("VoodooBit") )