Codebase list msldap / 6d503d6
Import upstream version 0.4.7 Kali Janitor 1 year, 5 months ago
13 changed file(s) with 182 addition(s) and 33 deletion(s). Raw diff Collapse all Expand all
00 Metadata-Version: 2.1
11 Name: msldap
2 Version: 0.4.1
2 Version: 0.4.7
33 Summary: Python library to play with MS LDAP
44 Home-page: https://github.com/skelsec/msldap
55 Author: Tamas Jos
6060 <protocol> sets the ldap protocol following values supported:
6161 - ldap
6262 - ldaps
63 - gc
64 - gc_ssl
6365
6466 <auth> can be omitted if plaintext authentication is to be performed (in that case it default to ntlm-password), otherwise:
6567 - ntlm-password
109111
110112 # Kudos
111113 Certificate services functionality was based on [certi](https://github.com/zer1t0/certi) created by @zer1t0
114 AC-RN
00
1 __version__ = "0.4.1"
1 __version__ = "0.4.7"
22 __banner__ = \
33 """
44 # msldap %s
33 # Tamas Jos (@skelsec)
44 #
55
6 from codecs import lookup
76 import copy
87 import asyncio
98
113112 self._serverinfo = res
114113 self._tree = res['defaultNamingContext']
115114 self._ldapinfo, err = await self.get_ad_info()
116 self._domainsid_cache[self._ldapinfo.objectSid] = self._ldapinfo.name
115 if self._con.is_anon is False:
116 if err is not None:
117 raise err
118 self._domainsid_cache[self._ldapinfo.objectSid] = self._ldapinfo.name
119
117120 if self.keepalive is True:
118121 self.__keepalive_task = asyncio.create_task(self.__keepalive())
119 if err is not None:
120 raise err
121122 return True, None
122123 except Exception as e:
123124 return False, e
934935 'servicePrincipalName': [('add', [spn])]
935936 }
936937 return await self._con.modify(user_dn, changes)
938
939 async def del_user_spn(self, user_dn, spn):
940 """
941 Adds an SPN record to the user object.
942
943 :param user_dn: The user's DN
944 :type user_dn: str
945 :param spn: The SPN to be added. It must follow the SPN string format specifications.
946 :type spn: str
947 :return: A tuple of (True, None) on success or (False, Exception) on error.
948 :rtype: (:class:`bool`, :class:`Exception`)
949
950 """
951 changes = {
952 'servicePrincipalName': [('delete', [spn])]
953 }
954 return await self._con.modify(user_dn, changes)
937955
938956 async def add_additional_hostname(self, user_dn, hostname):
939957 """
12941312 except Exception as e:
12951313 yield None, e
12961314 return
1315
1316 async def list_gmsa(self):
1317 try:
1318 ldap_filter = r'(objectClass=msDS-GroupManagedServiceAccount)'
1319 async for entry, err in self.pagedsearch(ldap_filter, attributes = ['sAMAccountName','msDS-GroupMSAMembership', 'msDS-ManagedPassword']):
1320 if err is not None:
1321 yield None, err
1322 return
1323 yield entry['attributes'].get('sAMAccountName'), entry['attributes'].get('msDS-GroupMSAMembership'), entry['attributes'].get('msDS-ManagedPassword'), None
1324
1325 except Exception as e:
1326 yield None, None, None, e
1327 return
1328
12971329
12981330 async def resolv_sd(self, sd):
12991331 "Resolves all SIDs found in security descriptor, returns lookup table"
8080 raise NotImplementedError()
8181 protocol = UniProto.CLIENT_UDP
8282 port = 389
83 elif schemes[0] == 'GC':
84 protocol = UniProto.CLIENT_TCP
85 port = 3268
86 elif schemes[0] == 'GC_SSL':
87 protocol = UniProto.CLIENT_SSL_TCP
88 port = 3269
8389 else:
8490 raise Exception('Unknown protocol! %s' % schemes[0])
8591
1717 from asysocks.unicomm.common.target import UniProto
1818 from msldap.commons.exceptions import LDAPBindException, LDAPAddException, LDAPModifyException, LDAPDeleteException
1919 from hashlib import sha256
20 from minikerberos.gssapi.channelbindings import ChannelBindingsStruct
2120 from asysocks.unicomm.client import UniClient
2221 from asyauth.common.constants import asyauthProtocol
2322 from asyauth.common.credentials import UniCredential
23 from asyauth.common.winapi.constants import ISC_REQ
2424
2525 class MSLDAPClientConnection:
2626 def __init__(self, target:MSLDAPTarget, credential:UniCredential, auth=None):
3333
3434 self.connected = False
3535 self.bind_ok = False
36 self.is_anon = False
3637 self.__sign_messages = False
3738 self.__encrypt_messages = False
3839 self.network = None
180181 # now processing channel binding options
181182 if self.target.protocol == UniProto.CLIENT_SSL_TCP:
182183 certdata = self.network.get_peer_certificate()
183 cb_struct = ChannelBindingsStruct()
184 cb_struct.application_data = b'tls-server-end-point:' + sha256(certdata).digest()
185
186 self.cb_data = cb_struct.to_bytes()
184 self.cb_data = b'tls-server-end-point:' + sha256(certdata).digest()
187185
188186 self.handle_incoming_task = asyncio.create_task(self.__handle_incoming())
189187 logger.debug('Connection succsessful!')
233231 logger.debug('BIND in progress...')
234232 try:
235233 if self.credential.protocol == asyauthProtocol.SICILY:
236
237 data, to_continue, err = await self.auth.authenticate(None, spn=self.target.to_target_string())
234 flags = ISC_REQ.CONNECTION|ISC_REQ.CONFIDENTIALITY|ISC_REQ.INTEGRITY
235 if self.target.protocol == UniProto.CLIENT_SSL_TCP:
236 flags = ISC_REQ.CONNECTION
237 data, to_continue, err = await self.auth.authenticate(None, spn=self.target.to_target_string(), flags=flags, cb_data = self.cb_data)
238238 if err is not None:
239239 return None, err
240240
288288 res['protocolOp']['diagnosticMessage']
289289 )
290290
291 data, to_continue, err = await self.auth.authenticate(res['protocolOp']['matchedDN'], spn=self.target.to_target_string())
291 data, to_continue, err = await self.auth.authenticate(res['protocolOp']['matchedDN'], spn=self.target.to_target_string(), cb_data = self.cb_data)
292292 if err is not None:
293293 return None, err
294294
329329 user = b''
330330 if self.auth.username != None:
331331 user = self.auth.username.encode()
332
332 if user == b'':
333 self.is_anon = True
334
333335 auth = {
334336 'simple' : pw
335337 }
363365 challenge = None
364366 while True:
365367 try:
366 data, to_continue, err = await self.auth.authenticate(challenge, cb_data = self.cb_data, spn=self.target.to_target_string())
368 flags = ISC_REQ.CONNECTION|ISC_REQ.CONFIDENTIALITY|ISC_REQ.INTEGRITY
369 if self.target.protocol == UniProto.CLIENT_SSL_TCP:
370 flags = ISC_REQ.CONNECTION
371
372 data, to_continue, err = await self.auth.authenticate(challenge, cb_data = self.cb_data, spn=self.target.to_target_string(), flags=flags)
367373 if err is not None:
368374 raise err
369375 except Exception as e:
394400 res = res.native
395401 if res['protocolOp']['resultCode'] == 'success':
396402 if 'serverSaslCreds' in res['protocolOp']:
397 data, _, err = await self.auth.authenticate(res['protocolOp']['serverSaslCreds'], cb_data = self.cb_data, spn=self.target.to_target_string())
403 data, _, err = await self.auth.authenticate(res['protocolOp']['serverSaslCreds'], cb_data = self.cb_data, spn=self.target.to_target_string(), flags=flags)
398404 if err is not None:
399405 return False, err
400406
401 self.encryption_sequence_counter = self.auth.get_seq_number()
407 if self.auth.encryption_needed() is True or self.auth.signing_needed() is True:
408 self.encryption_sequence_counter = self.auth.get_seq_number()
402409 self.__bind_success()
403410
404411 return True, None
772779 #print('res')
773780 #print(res)
774781 return convert_attributes(res.native['protocolOp']['attributes']), None
775
776
777
778
779
780
781
782
783
44 #
55
66 import asyncio
7 from os import terminal_size
87 import traceback
98 import logging
109 import csv
2423 from msldap.ldap_objects import MSADUser, MSADMachine, MSADUser_TSV_ATTRS
2524
2625 from winacl.dtyp.security_descriptor import SECURITY_DESCRIPTOR
27 from winacl.dtyp.ace import ACCESS_ALLOWED_OBJECT_ACE, ADS_ACCESS_MASK, AceFlags, ACE_OBJECT_PRESENCE
26 from winacl.dtyp.ace import ACCESS_ALLOWED_OBJECT_ACE, ADS_ACCESS_MASK, AceFlags,\
27 ACE_OBJECT_PRESENCE, ACEType
2828 from winacl.dtyp.sid import SID
2929 from winacl.dtyp.guid import GUID
3030
31 from msldap.ldap_objects.adcertificatetemplate import MSADCertificateTemplate, EX_RIGHT_CERTIFICATE_ENROLLMENT, CertificateNameFlag
31 from msldap.ldap_objects.adcertificatetemplate import MSADCertificateTemplate,\
32 EX_RIGHT_CERTIFICATE_ENROLLMENT, CertificateNameFlag
3233 from msldap.wintypes.asn1.sdflagsrequest import SDFlagsRequest
3334
3435
577578 traceback.print_exc()
578579 return False
579580
581 async def do_delspn(self, user_dn, spn):
582 """Removes an SPN entry to the users account"""
583 try:
584 _, err = await self.connection.del_user_spn(user_dn, spn)
585 if err is not None:
586 raise err
587 print('SPN removed!')
588 return True
589 except:
590 traceback.print_exc()
591 return False
592
580593 async def do_addhostname(self, user_dn, hostname):
581594 """Adds additional hostname to computer account"""
582595 try:
851864 except:
852865 traceback.print_exc()
853866 return False, None
867
868 async def do_gmsa(self):
869 """Lists all managed service accounts (MSA). If user has permissions it retrieves the password as well"""
870 try:
871 print('---------------------------------------------')
872 async for samaccountname, memberships, pwblob, err in self.connection.list_gmsa():
873 if err is not None:
874 raise err
875 print('Username: %s' % samaccountname)
876 allowed_machines = []
877 if memberships is not None:
878 for entry in memberships.Dacl.aces:
879 if entry.AceType == ACEType.ACCESS_ALLOWED_ACE_TYPE:
880 try:
881 user = await self.do_sidresolv(entry.Sid, to_print=False)
882 allowed_machines.append(user)
883 except:
884 allowed_machines.append(entry.Sid)
885 for mname in allowed_machines:
886 print('Allowed machine: %s' % mname)
887 if pwblob is not None:
888 print('Password: %s' % pwblob.CurrentPassword[:-2].hex())
889 print('Password -NT-: %s' % pwblob.nt_hash)
890 else:
891 print('Password: <EMPTY>')
892 print('---------------------------------------------')
893
894 except:
895 traceback.print_exc()
896 return False
854897
855898 async def do_test(self):
856899 """testing, dontuse"""
55 from winacl.dtyp.security_descriptor import SECURITY_DESCRIPTOR
66 from msldap import logger
77 from msldap.protocol.messages import Attribute, Change, PartialAttribute
8 from msldap.wintypes.managedpassword import MSDS_MANAGEDPASSWORD_BLOB
89
910 MSLDAP_DT_WIN_EPOCH = datetime.datetime(1601, 1, 1)
1011
4344
4445 def x2sid(x):
4546 return str(SID.from_bytes(x[0]))
47
48 def x2gmsa(x):
49 return MSDS_MANAGEDPASSWORD_BLOB.from_bytes(x[0])
4650
4751 def list_x2sid(x):
4852 t = []
301305 'msPKI-Cert-Template-OID' : list_str_one,
302306 'msPKI-Certificate-Application-Policy' : list_str,
303307 'msPKI-RA-Application-Policies' : list_str, #I'm guessing here
308 'msDS-ManagedPassword' : x2gmsa,
309 'msDS-GroupMSAMembership' : x2sd,
304310 }
305311
306312 LDAP_ATTRIBUTE_TYPES_ENC = {
0 import io
1 from unicrypto.hashlib import md4
2
3 class MSDS_MANAGEDPASSWORD_BLOB:
4 def __init__(self):
5 self.Version = None
6 self.Reserved = None
7 self.Length = None
8 self.CurrentPasswordOffset = None
9 self.PreviousPasswordOffset = None
10 self.QueryPasswordIntervalOffset = None
11 self.UnchangedPasswordIntervalOffset = None
12 self.CurrentPassword = None
13 self.PreviousPassword = None
14 #('AlignmentPadding',':'),
15 self.QueryPasswordInterval = None
16 self.UnchangedPasswordInterval = None
17
18 self.nt_hash = None
19
20 @staticmethod
21 def from_bytes(data:bytes):
22 return MSDS_MANAGEDPASSWORD_BLOB.from_buffer(io.BytesIO(data))
23
24 @staticmethod
25 def from_buffer(buff:io.BytesIO):
26 blob = MSDS_MANAGEDPASSWORD_BLOB()
27 blob.Version = int.from_bytes(buff.read(2), byteorder='little', signed=False)
28 blob.Reserved = int.from_bytes(buff.read(2), byteorder='little', signed=False)
29 blob.Length = int.from_bytes(buff.read(4), byteorder='little', signed=False)
30 blob.CurrentPasswordOffset = int.from_bytes(buff.read(2), byteorder='little', signed=False)
31 blob.PreviousPasswordOffset = int.from_bytes(buff.read(2), byteorder='little', signed=False)
32 blob.QueryPasswordIntervalOffset = int.from_bytes(buff.read(2), byteorder='little', signed=False)
33 blob.UnchangedPasswordIntervalOffset = int.from_bytes(buff.read(2), byteorder='little', signed=False)
34
35 ppwo = blob.PreviousPasswordOffset
36 if ppwo == 0:
37 ppwo = blob.QueryPasswordIntervalOffset
38 if blob.CurrentPasswordOffset >0:
39 buff.seek(blob.CurrentPasswordOffset, 0)
40 blob.CurrentPassword = buff.read(ppwo - blob.CurrentPasswordOffset)
41 if blob.PreviousPasswordOffset >0:
42 buff.seek(blob.PreviousPasswordOffset, 0)
43 blob.PreviousPassword = buff.read(blob.QueryPasswordIntervalOffset - blob.CurrentPasswordOffset)
44 if blob.QueryPasswordIntervalOffset >0:
45 buff.seek(blob.QueryPasswordIntervalOffset, 0)
46 blob.QueryPasswordInterval = buff.read(blob.UnchangedPasswordIntervalOffset - blob.UnchangedPasswordIntervalOffset)
47 if blob.UnchangedPasswordIntervalOffset >0:
48 buff.seek(blob.UnchangedPasswordIntervalOffset, 0)
49 blob.UnchangedPasswordInterval = buff.read()
50
51
52 blob.nt_hash = md4(blob.CurrentPassword[:-2]).hexdigest()
53 return blob
54
55 def __str__(self):
56 t = ''
57 for k in self.__dict__:
58 t += '%s: %s\r\n' % (k, self.__dict__[k])
59 return t
00 Metadata-Version: 2.1
11 Name: msldap
2 Version: 0.4.1
2 Version: 0.4.7
33 Summary: Python library to play with MS LDAP
44 Home-page: https://github.com/skelsec/msldap
55 Author: Tamas Jos
6262 msldap/protocol/ldap_filter/parser.py
6363 msldap/protocol/ldap_filter/soundex.py
6464 msldap/wintypes/__init__.py
65 msldap/wintypes/managedpassword.py
6566 msldap/wintypes/asn1/__init__.py
6667 msldap/wintypes/asn1/sdflagsrequest.py
00 unicrypto>=0.0.9
1 asyauth>=0.0.2
1 asyauth>=0.0.7
22 asysocks>=0.2.1
33 asn1crypto>=1.3.0
44 minikerberos>=0.3.1
4747 ),
4848 install_requires=[
4949 'unicrypto>=0.0.9',
50 'asyauth>=0.0.2',
50 'asyauth>=0.0.7',
5151 'asysocks>=0.2.1',
5252 'asn1crypto>=1.3.0',
5353 'minikerberos>=0.3.1',