Skip to content

LDAP and AD Security Descriptors

Back to the Technology Index

LDAP is used to search AD objects and change their attributes. Impacket uses two clients for different purposes. When following the code, first check which client the command calls. For the meaning of attribute changes and LDIF examples, see LDAP Modification Operations.

ImplementationCommandsSuitable Operations
impacket.ldap.LDAPConnectionGetADUsers, GetUserSPNs, GetNPUsers, GetLAPSPassword, findDelegation, etc.Bind, search, simple modify
ldap3 (init_ldap_session)dacledit, owneredit, rbcd, badsuccessor, and addcomputer’s LDAPS pathChanges with SD controls, complex modify operations

ASN.1 is in ldapasn1.py (RFC 4511). AD security descriptors are in ldaptypes.py. Extended-rights GUIDs are in msada_guids.py.

impacket/acl.py is not for AD. It handles SMB file FileSecInformation and SID resolution through LSARPC. Use ldaptypes when working with nTSecurityDescriptor.

LDAPConnection(url, baseDN='', dstIp=None, signing=True, timeout=None):

SchemePortSigning DefaultTLS
ldap://389OnNone
ldaps://636Off (the channel itself uses TLS)pyOpenSSL TLS_METHOD
gc://3268OffNone (Global Catalog)

dstIp overrides only the endpoint. The Kerberos SPN ldap/<URL host> still uses the hostname.

LDAPS channel binding puts the RFC 5929 tls-server-end-point: prefix and the peer certificate’s SHA-256 in a structure, then passes its MD5 as channel_binding_value. NTLM Type3 AV_CHANNEL_BINDINGS and Kerberos AP-REQ CheckSumField.Bnd consume it. On a DC that requires CBT, bind fails without it. Use CheckLDAPStatus to test this.

login(..., authenticationChoice='sasl'):

ChoiceMechanism
simpleuser@domain or DOMAIN\user plus password
sicilyNegotiateSicily NTLM (Type1 in negotiate, Type3 in response)
sasl (default)GSS-SPNEGO + NTLMv2; adds a MIC to Type3 and uses SPNEGOCipher when signing

kerberosLogin():

  1. Look for ldap/<host> with CCache.parseFile
  2. If absent, call getKerberosTGT → getKerberosTGS
  3. SPNEGO + AP-REQ with checksum 0x8003; CONF|INTEG when signing, or CBT in Bnd for LDAPS
  4. BindRequest SASL GSS-SPNEGO

With signing enabled, send() writes a four-byte length plus a wrapped message. Kerberos uses GSS_Wrap_LDAP; NTLM uses SPNEGOCipher.encrypt. recv_raw() decrypts it.

The ldap3 path (impacket.examples.utils.init_ldap_session) passes NTLM/Kerberos to ldap3’s SASL and uses security_descriptor_control for modifications. dacledit and related commands use this path.

LDAPConnection.search defaults to wholeSubtree and neverDerefAliases. Filters follow RFC 4515 (& | !, =, >=, <=, :=, *, \XX).

Paging uses control OID 1.2.840.113556.1.4.319 (SimplePagedResultsControl, default size 1000) and iterates until the server cookie is empty. Removing filters, as with -stealth on a large domain, can truncate results without paging.

Modify operation constants: ADD=0, DELETE=1, REPLACE=2, INCREMENT=3. Use control OID 1.2.840.113556.1.4.801 (SDFlagsControl) for SD changes. Flags: OWNER=1, GROUP=2, DACL=4, SACL=8. dacledit reads only the DACL (0x04) in many cases.

This is a self-relative SD from [MS-DTYP] 2.4.6.

SR_SECURITY_DESCRIPTOR
Revision, Control
OffsetOwner / OffsetGroup / OffsetSacl / OffsetDacl
OwnerSid, GroupSid, Sacl, Dacl
ACL
AceCount + ACE[]
ACE
AceType, AceFlags, AceSize + body

Common ACEs:

AceTypeClassPurpose
0x00ACCESS_ALLOWED_ACEOrdinary allow ACE; also used to enumerate RBCD SIDs
0x01ACCESS_DENIED_ACEDeny
0x05ACCESS_ALLOWED_OBJECT_ACEObject GUID; DCSync / ResetPassword
0x06ACCESS_DENIED_OBJECT_ACEObject deny ACE

The combination of ACE_OBJECT_TYPE_PRESENT / INHERITED_OBJECT_TYPE_PRESENT and GUIDs matters for object ACEs. Do not remove one merely because its SID matches another.

Representative masks:

NameValueMeaning
WRITE_DACL0x40000Change DACL
WRITE_OWNER0x80000Change owner
READ_CONTROL0x20000Read SD
ADS_RIGHT_DS_CONTROL_ACCESS0x100Extended right
WRITE_PROP0x20Write attributes
CREATE_CHILD / DELETE_CHILD0x1 / 0x2Child objects

Examples from msada_guids.EXTENDED_RIGHTS:

  • 00299570-246d-11d0-a768-00aa006e0529 — User-Force-Change-Password
  • 1131f6aa-9c07-11d1-f79f-00c04fc2dcd2 — DS-Replication-Get-Changes
  • 1131f6ad-9c07-11d1-f79f-00c04fc2dcd2 — Get-Changes-All (one part of DCSync)
  • ab721a53-1e2f-11d0-9819-00aa0040529b — User-Change-Password

RECALC_ACE_SIZE (True by default) recalculates ACE sizes on serialization. Because this can change the padding held by AD, backups and restores retain the original binary blob (dacledit’s JSON backup).

OperationAttribute / TargetCommand
Edit DACLnTSecurityDescriptordacledit
Change ownerSD Ownerowneredit
RBCDmsDS-AllowedToActOnBehalfOfOtherIdentity (contains an SD)rbcd
Enumerate delegationUAC, msDS-AllowedToDelegateTo, etc.findDelegation
LAPSms-Mcs-AdmPwd / Windows LAPS + GKDIGetLAPSPassword
dMSADelegated MSA attributesbadsuccessor

An RBCD value is a self-relative SD, not a SID array. The mask in create_allow_ace is 983551 (equivalent to full control). flush clears the entire attribute; remove deletes only the ACE for the specified SID.

  • Decide whether to change LDAPConnection or ldap3 first
  • Reading nTSecurityDescriptor without an SD control omits data
  • Preserve ACE order, unknown ACEs, and inheritance flags on a round trip
  • Related tests: tests/SMB_RPC/test_ldap.py