第二部分 认证与目录服务
第 3 章 LDAP 目录服务(ldap)
ldap.py — LDAP 登录与检索(login / search)
该文件主要实现了 LDAP、LDAPS、GC(全局编录)和 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):
.....
还有ldap进行搜索操作的函数
def search(self, searchBase=None, scope=None, derefAliases=None, sizeLimit=0, timeLimit=0, typesOnly=False,searchFilter='(objectClass=*)', attributes=None, searchControls=None, perRecordCallback=None):
其余函数主要是配合 search 的过滤器函数、发送 bind / search 请求的 sendReceive 函数,以及错误处理函数。
ldap.py 中这 3 个函数,是后续编写脚本时(无论域内还是域外)最常用的函数。
这边顺便说下 GC 协议:全局编录(Global Catalog)可以通俗理解为一个跨域的缓存数据库接口。全局编录服务器是 Active Directory 域服务(AD DS)林中所有对象的集合——它是一个域控制器,存储本域目录中所有对象的完全副本,以及林中其他域对象的部分只读副本,用于响应全局编录查询。端口为 3268(LDAP)和 3269(LDAPS),扫描域控时又可以多关注两个端口了。
ldapasn1.py — LDAP 请求数据结构(ASN.1)
该文件主要定义了 LDAP 请求中各参数的数据结构,可以类比成 Go 编程中的 struct。
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())
)
一般用在回调函数中判定请求的结构是否正确
# 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
.....
这边插一个 pyasn1 官方示例。使用 pyasn1 可以从 ASN.1 数据结构构建 Python 对象,例如下面的 ASN.1 数据结构:
Record ::= SEQUENCE {
id INTEGER,
room [0] INTEGER OPTIONAL,
house [1] INTEGER DEFAULT 0
}
可以这样在 pyasn1 中表达:
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 安全描述符结构(ACE / DACL)
该文件主要定义了 ACL 中各类安全描述符结构(ACE、DACL 等)。
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
]
实际使用中主要用于构造 ACL 变更相关的请求。
# 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