Beispiel #1
0
    async def get_tree_plot(self, dn, level=2):
        """
		Returns a dictionary representing a tree starting from 'dn' containing all subtrees.
		Parameters:
			dn (str): Distinguished name of the root of the tree
			level (int): Recursion level
		Returns:
			dict
		"""
        logger.debug('Tree, dn: %s level: %s' % (dn, level))
        tree = {}
        async for entry, err in self._con.pagedsearch(
                dn.encode(),
                query_syntax_converter('(distinguishedName=*)'),
                attributes=[b'distinguishedName'],
                paged_size=self.ldap_query_page_size,
                search_scope=LEVEL,
                controls=None,
        ):
            if err is not None:
                raise err

            if level == 0:
                return {}
            #print(entry)
            #print(entry['attributes']['distinguishedName'])
            if 'distinguishedName' not in entry['attributes'] or entry[
                    'attributes']['distinguishedName'] is None or entry[
                        'attributes']['distinguishedName'] == []:
                continue
            subtree = await self.get_tree_plot(
                entry['attributes']['distinguishedName'], level=level - 1)
            tree[entry['attributes']['distinguishedName']] = subtree
        return {dn: tree}
Beispiel #2
0
    async def pagedsearch(self, ldap_filter, attributes, controls=None):
        """
		Performs a paged search on the AD, using the filter and attributes as a normal query does.
		Needs to connect to the server first!

		Parameters:
			ldap_filter (str): LDAP query filter
			attributes (list): Attributes list to recieve in the result
			controls (obj): Additional control dict
		
		Returns:
			generator
		"""
        logger.debug('Paged search, filter: %s attributes: %s' %
                     (ldap_filter, ','.join(attributes)))
        if self._con.status != MSLDAPClientStatus.RUNNING:
            if self._con.status == MSLDAPClientStatus.ERROR:
                print('There was an error in the connection!')
                return
            elif self._con.status == MSLDAPClientStatus.ERROR:
                print('Theconnection is in stopped state!')
                return

        if self._tree is None:
            raise Exception('BIND first!')
        t = []
        for x in attributes:
            t.append(x.encode())
        attributes = t
        ldap_filter = query_syntax_converter(ldap_filter)

        t = []
        if controls is not None:
            for control in controls:
                t.append(
                    Control({
                        'controlType': control[0].encode(),
                        'criticality': control[1],
                        'controlValue': control[2]
                    }))

        controls = t

        async for entry, err in self._con.pagedsearch(
                self._tree.encode(),
                ldap_filter,
                attributes=attributes,
                paged_size=self.ldap_query_page_size,
                controls=controls):

            if err is not None:
                raise err
            if entry['objectName'] == '' and entry['attributes'] == '':
                #searchresref...
                continue
            #print('et %s ' % entry)
            yield entry
Beispiel #3
0
    async def get_tokengroups(self, dn):
        """
		returns the tokengroups attribute for a given DN
		"""
        ldap_filter = query_syntax_converter(r'(distinguishedName=%s)' %
                                             escape_filter_chars(dn))
        attributes = [b'tokenGroups']

        async for entry, err in self._con.pagedsearch(
                dn.encode(),
                ldap_filter,
                attributes=attributes,
                paged_size=self.ldap_query_page_size,
                search_scope=BASE,
        ):
            if err is not None:
                yield None, err
                break

            #print(entry['attributes'])
            if 'tokenGroups' in entry:
                for sid_data in entry['tokenGroups']:
                    yield sid_data
Beispiel #4
0
    async def get_all_tokengroups(self):
        """
		returns the tokengroups attribute for a given DN
		"""
        ldap_filter = r'(|(sAMAccountType=805306369)(objectClass=group)(sAMAccountType=805306368))'
        async for entry in self.pagedsearch(ldap_filter,
                                            attributes=[
                                                'dn', 'cn', 'objectSid',
                                                'objectClass', 'objectGUID'
                                            ]):

            if 'objectName' in entry:
                #print(entry['objectName'])
                async for entry2, err in self._con.pagedsearch(
                        entry['objectName'].encode(),
                        query_syntax_converter(
                            r'(distinguishedName=%s)' %
                            escape_filter_chars(entry['objectName'])),
                        attributes=[b'tokenGroups'],
                        paged_size=self.ldap_query_page_size,
                        search_scope=BASE,
                ):

                    #print(entry2)
                    if err is not None:
                        yield None, err
                        break
                    if 'tokenGroups' in entry2['attributes']:
                        for token in entry2['attributes']['tokenGroups']:
                            yield {
                                'cn': entry['attributes']['cn'],
                                'dn': entry['objectName'],
                                'guid': entry['attributes']['objectGUID'],
                                'sid': entry['attributes']['objectSid'],
                                'type': entry['attributes']['objectClass'][-1],
                                'token': token
                            }
Beispiel #5
0
    async def search(self,
                     base,
                     query,
                     attributes,
                     search_scope=2,
                     size_limit=1000,
                     types_only=False,
                     derefAliases=0,
                     timeLimit=None,
                     controls=None,
                     return_done=False):
        """
		Performs the search operation.
		
		:param base: base tree on which the search should be performed
		:type base: str
		:param query: filter query that defines what should be searched for
		:type query: str
		:param attributes: a list of attributes to be included in the response
		:type attributes: List[str]
		:param search_scope: Specifies the search operation's scope. Default: 2 (Subtree)
		:type search_scope: int
		:param types_only: indicates whether the entries returned should include attribute types only or both types and values. Default: False (both)
		:type types_only: bool
		:param size_limit: Size limit of result elements per query. Default: 1000
		:type size_limit: int
		:param derefAliases: Specifies the behavior on how aliases are dereferenced. Default: 0 (never)
		:type derefAliases: int
		:param timeLimit: Maximum time the search should take. If time limit reached the server SHOULD return an error
		:type timeLimit: int
		:param controls: additional controls to be passed in the query
		:type controls: dict
		:param return_done: Controls wether the final 'done' LDAP message should be returned, or just the actual results
		:type return_done: bool

		:return: Async generator which yields (`LDAPMessage`, None) tuple on success or (None, `Exception`) on error
		:rtype: Iterator[(:class:`LDAPMessage`, :class:`Exception`)]
		"""
        if self.status != MSLDAPClientStatus.RUNNING:
            yield None, Exception(
                'Connection not running! Probably encountered an error')
            return
        try:
            if timeLimit is None:
                timeLimit = 600  #not sure

            flt = query_syntax_converter(query)

            searchreq = {
                'baseObject': base.encode(),
                'scope': search_scope,
                'derefAliases': derefAliases,
                'sizeLimit': size_limit,
                'timeLimit': timeLimit,
                'typesOnly': types_only,
                'filter': flt,
                'attributes': attributes,
            }

            br = {'searchRequest': SearchRequest(searchreq)}
            msg = {'protocolOp': protocolOp(br)}
            if controls is not None:
                msg['controls'] = controls

            msg_id = await self.send_message(msg)

            while True:
                results = await self.recv_message(msg_id)
                for message in results:
                    msg_type = message['protocolOp'].name
                    message = message.native
                    if msg_type == 'searchResDone':
                        #print(message)
                        #print('BREAKING!')
                        if return_done is True:
                            yield (message, None)
                        break

                    elif msg_type == 'searchResRef':
                        #TODO: Check if we need to deal with this further
                        continue

                    if return_done is True:
                        yield (message, None)
                    else:
                        yield (convert_result(message['protocolOp']), None)
                else:
                    continue

                break

        except Exception as e:
            yield (None, e)
Beispiel #6
0
async def amain():
    import traceback
    from msldap.commons.url import MSLDAPURLDecoder

    base = 'DC=TEST,DC=CORP'

    #ip = 'WIN2019AD'
    #domain = 'TEST'
    #username = '******'
    #password = '******'
    ##auth_method = LDAPAuthProtocol.SICILY
    #auth_method = LDAPAuthProtocol.SIMPLE

    #cred = MSLDAPCredential(domain, username, password , auth_method)
    #target = MSLDAPTarget(ip)
    #target.dc_ip = '10.10.10.2'
    #target.domain = 'TEST'

    url = 'ldap+kerberos-password://test\\victim:Passw0rd!1@WIN2019AD/?dc=10.10.10.2'

    dec = MSLDAPURLDecoder(url)
    cred = dec.get_credential()
    target = dec.get_target()

    print(cred)
    print(target)

    input()

    client = MSLDAPClientConnection(target, cred)
    await client.connect()
    res, err = await client.bind()
    if err is not None:
        raise err

    #res = await client.search_test_2()
    #pprint.pprint(res)
    #search = bytes.fromhex('30840000007702012663840000006e043c434e3d3430392c434e3d446973706c6179537065636966696572732c434e3d436f6e66696775726174696f6e2c44433d746573742c44433d636f72700a01000a010002010002020258010100870b6f626a656374436c61737330840000000d040b6f626a656374436c617373')
    #msg = LDAPMessage.load(search)

    qry = r'(sAMAccountName=*)'  #'(userAccountControl:1.2.840.113556.1.4.803:=4194304)' #'(sAMAccountName=*)'
    #qry = r'(sAMAccountType=805306368)'
    #a = query_syntax_converter(qry)
    #print(a.native)
    #input('press bacon!')

    flt = query_syntax_converter(qry)
    i = 0
    async for res, err in client.pagedsearch(base.encode(),
                                             flt, ['*'.encode()],
                                             derefAliases=3,
                                             typesOnly=False):
        if err is not None:
            print('Error!')
            raise err
        i += 1
        if i % 1000 == 0:
            print(i)
        #pprint.pprint(res)

    await client.disconnect()
Beispiel #7
0
    qry = r'(sAMAccountName=*)'  #'(userAccountControl:1.2.840.113556.1.4.803:=4194304)' #'(sAMAccountName=*)'
    #qry = r'(sAMAccountType=805306368)'
    #a = query_syntax_converter(qry)
    #print(a.native)
    #input('press bacon!')
    schema = SchemaInfo.from_json(ad_2012_r2_schema)
    auto_escape = True
    auto_encode = True
    validator = None
    check_names = False
    #
    #
    res = parse_filter(qry, schema, auto_escape, auto_encode, validator,
                       check_names)
    print(repr(res))
    res = compile_filter(res.elements[0])
    #
    print(repr(res))
    print(encoder.encode(res).hex())
    #res = encoder.encode(res)
    #x = Filter.load(res)
    #pprint(x.native)

    flt = query_syntax_converter(qry)
    input(flt.native)

    #res = await client.search_test_2()
    #pprint.pprint(res)
    #search = bytes.fromhex('30840000007702012663840000006e043c434e3d3430392c434e3d446973706c6179537065636966696572732c434e3d436f6e66696775726174696f6e2c44433d746573742c44433d636f72700a01000a010002010002020258010100870b6f626a656374436c61737330840000000d040b6f626a656374436c617373')
    #msg = LDAPMessage.load(search)