Part II Authentication & Directory Services
Chapter 3 LDAP Directory Services (ldap)
ldap.py — LDAP Login & Search (login / search)
This file implements the login functions for LDAP, LDAPS, GC (Global Catalog) and Kerberos.
def login(self, user='', password='', domain='', lmhash='', nthash='',authenticationChoice='sicilyNegotiate'):
.....
def kerberosLogin(self, user, password, domain='', lmhash='', nthash='', aesKey='', kdcHost=None, TGT=None,TGS=None, useCache=True):
.....
It also contains the LDAP search function:
def search(self, searchBase=None, scope=None, derefAliases=None, sizeLimit=0, timeLimit=0, typesOnly=False,searchFilter='(objectClass=*)', attributes=None, searchControls=None, perRecordCallback=None):
The remaining functions are mostly filter helpers used by search, the sendReceive function that sends bind / search requests, and error handlers.
These 3 functions of ldap.py are the ones you will use most when writing scripts, whether inside or outside the domain.
A quick note on GC: the Global Catalog can loosely be understood as a cross-domain cached-database interface. A global catalog server holds a set of all objects in the Active Directory Domain Services (AD DS) forest — it is a domain controller that stores a full replica of every object in its own domain's directory plus a partial, read-only replica of the objects of every other domain in the forest, and answers global-catalog queries. Its ports are 3268 (LDAP) and 3269 (LDAPS) — two more ports worth adding to your DC scan list.
ldapasn1.py — LDAP Request Data Structures (ASN.1)
This file defines the data structures of each LDAP request parameter; think of them as the structs of Go.
class SearchResultEntry(univ.Sequence):
tagSet = univ.Sequence.tagSet.tagImplicitly(tag.Tag(tag.tagClassApplication, tag.tagFormatConstructed, 4))
componentType = namedtype.NamedTypes(
namedtype.NamedType('objectName', LDAPDN()),
namedtype.NamedType('attributes', PartialAttributeList())
)
They are typically used in callbacks to verify that the received structure is the expected one.
# eg.examples/GetADUsers.py
def run(self):
.....
try:
logging.debug('Search Filter=%s' % searchFilter)
sc = ldap.SimplePagedResultsControl(size=100)
ldapConnection.search(searchFilter=searchFilter,
attributes=['sAMAccountName', 'pwdLastSet', 'mail', 'lastLogon'],
sizeLimit=0, searchControls = [sc], perRecordCallback=self.processRecord)
......
def processRecord(self, item):
if isinstance(item, ldapasn1.SearchResultEntry) is not True:
return
.....
Here is an official pyasn1 example. pyasn1 lets you build Python objects from ASN.1 data structures, for example the following ASN.1 structure:
Record ::= SEQUENCE {
id INTEGER,
room [0] INTEGER OPTIONAL,
house [1] INTEGER DEFAULT 0
}
can be expressed in pyasn1 like this:
class Record(Sequence):
componentType = NamedTypes(
NamedType('id', Integer()),
OptionalNamedType(
'room', Integer().subtype(
implicitTag=Tag(tagClassContext, tagFormatSimple, 0)
)
),
DefaultedNamedType(
'house', Integer(0).subtype(
implicitTag=Tag(tagClassContext, tagFormatSimple, 1)
)
)
)
ldaptypes.py — ACL Security Descriptor Structures (ACE / DACL)
This file mainly defines the security-descriptor structures used in ACLs (ACE, DACL, etc.).
ACE_TYPES = [
ACCESS_ALLOWED_ACE,
ACCESS_ALLOWED_OBJECT_ACE,
ACCESS_DENIED_ACE,
ACCESS_DENIED_OBJECT_ACE,
ACCESS_ALLOWED_CALLBACK_ACE,
ACCESS_DENIED_CALLBACK_ACE,
ACCESS_ALLOWED_CALLBACK_OBJECT_ACE,
ACCESS_DENIED_CALLBACK_OBJECT_ACE,
SYSTEM_AUDIT_ACE,
SYSTEM_AUDIT_OBJECT_ACE,
SYSTEM_AUDIT_CALLBACK_ACE,
SYSTEM_MANDATORY_LABEL_ACE,
SYSTEM_AUDIT_CALLBACK_OBJECT_ACE,
SYSTEM_RESOURCE_ATTRIBUTE_ACE,
SYSTEM_SCOPED_POLICY_ID_ACE
]
In practice it is mainly used to construct ACL-modification requests.
# eg./examples/ldap_shell.py
def create_allow_ace(self, sid):
nace = ldaptypes.ACE()
nace['AceType'] = ldaptypes.ACCESS_ALLOWED_ACE.ACE_TYPE
nace['AceFlags'] = 0x00
acedata = ldaptypes.ACCESS_ALLOWED_ACE()
acedata['Mask'] = ldaptypes.ACCESS_MASK()
acedata['Mask']['Mask'] = 983551 # Full control
acedata['Sid'] = ldaptypes.LDAP_SID()
acedata['Sid'].fromCanonical(sid)
nace['Ace'] = acedata
return nace