Beispiel #1
0
	def run(self):
		self.in_q = AsyncProcessQueue()
		self.out_q = AsyncProcessQueue()
		if self.use_progress_bar is True:
			self.prg_hosts = tqdm(desc='HOSTS', ascii = True)
			self.prg_shares = tqdm(desc='Shares', ascii = True)
			self.prg_sessions = tqdm(desc='Sessions', ascii = True)
			self.prg_groups = tqdm(desc='LocalGroup', ascii = True)
			self.prg_errors = tqdm(desc='Errors', ascii = True)

		self.results_thread = threading.Thread(target = self.get_results)
		self.results_thread.daemon = True
		self.results_thread.start()

		self.gatherer = AIOSMBGatherer(self.in_q, self.out_q, self.smb_mgr, gather = self.gathering_type, localgroups = self.localgroups, concurrent_connections = self.concurrent_connections)
		self.gatherer.start()
		
		for target in self.__target_generator():
			self.total_targets += 1
			if self.use_progress_bar is True:
				self.prg_hosts.total = self.total_targets
			self.in_q.put(target)
		
		self.in_q.put(None)
		#if self.use_progress_bar is True:
		#	self.prg_hosts.total = self.total_targets

		self.results_thread.join()
Beispiel #2
0
	def __init__(self, smb_mgr, worker_cnt = 50):
		self.in_q = AsyncProcessQueue()
		self.out_q = AsyncProcessQueue()
		self.smb_mgr = smb_mgr
		self.gathering_type = ['all']
		self.localgroups = ['Administrators', 'Distributed COM Users','Remote Desktop Users']
		self.concurrent_connections = worker_cnt
		self.domain = None
		self.dc_ip = None
		self.timeout = 3
		self.db_conn = None

		self.total_targets = 0
		self.targets = []
		self.targets_file = None
		self.ldap_conn = None
		self.target_ad = None
		self.lookup_ad = None #if specified, it will look up the targets in the DB.
		self.out_file = None

		self.gatherer = None
		
		self.use_progress_bar = True
		self.prg_hosts = None
		self.prg_shares = None
		self.prg_sessions = None
		self.prg_groups = None
		self.prg_errors = None

		self.results_thread = None
Beispiel #3
0
    def __init__(self, db_conn, ldam_mgr, agent_cnt=None, queue_size=10):
        self.db_conn = db_conn
        self.ldam_mgr = ldam_mgr

        self.session = None

        self.queue_size = queue_size
        self.agent_in_q = AsyncProcessQueue()
        self.agent_out_q = AsyncProcessQueue(1000)
        self.agents = []

        self.agent_cnt = agent_cnt
        if agent_cnt is None:
            self.agent_cnt = min(multiprocessing.cpu_count(), 3)

        self.ad_id = None

        self.user_ctr = 0
        self.machine_ctr = 0
        self.ou_ctr = 0
        self.group_ctr = 0
        self.sd_ctr = 0
        self.spn_ctr = 0
        self.member_ctr = 0
        self.domaininfo_ctr = 0
        self.gpo_ctr = 0
        self.trust_ctr = 0

        self.user_finish_ctr = 0
        self.machine_finish_ctr = 0
        self.ou_finish_ctr = 0
        self.group_finish_ctr = 0
        self.sd_finish_ctr = 0
        self.spn_finish_ctr = 0
        self.member_finish_ctr = 0
        self.domaininfo_finish_ctr = 0
        self.gpo_finish_ctr = 0

        self.total_progress = None
        self.total_counter = 0
        self.total_counter_steps = 100
        self.progress_total_present = False
        self.remaining_ctr = None

        self.enum_finished_evt = None  #multiprocessing.Event()

        self.running_enums = {}
        self.finished_enums = []
        self.enum_types = [
            'adinfo', 'trusts', 'users', 'machines', 'groups', 'memberships',
            'sds', 'ous', 'gpos', 'spns'
        ]
        self.enum_types_len = len(self.enum_types)
Beispiel #4
0
    def __init__(self,
                 settings_base,
                 db_conn=None,
                 db_session=None,
                 worker_cnt=30):
        self.settings_base = settings_base
        self.in_q = AsyncProcessQueue()
        self.out_q = AsyncProcessQueue()
        self.worker_cnt = worker_cnt
        self.targets_thread = None
        self.db_conn = db_conn
        self.db_session = db_session
        self.dir_lookup = {}
        self.exclude_shares = ['IPC$']

        self.use_progress_bar = True
        self.prg_dirs = None
        self.prg_files = None
        self.prg_errors = None
Beispiel #5
0
    def __init__(self, db_conn, ldam_mgr, agent_cnt=None, queue_size=10):
        self.db_conn = db_conn
        self.ldam_mgr = ldam_mgr

        self.session = None

        self.queue_size = queue_size
        self.agent_in_q = AsyncProcessQueue()
        self.agent_out_q = AsyncProcessQueue(100)
        self.agents = []
        self.agent_cnt = multiprocessing.cpu_count(
        ) if agent_cnt is None else agent_cnt
        self.ad_id = None

        self.user_ctr = 0
        self.machine_ctr = 0
        self.ou_ctr = 0
        self.group_ctr = 0
        self.sd_ctr = 0
        self.spn_ctr = 0
        self.member_ctr = 0
        self.domaininfo_ctr = 0
        self.gpo_ctr = 0

        self.user_finish_ctr = 0
        self.machine_finish_ctr = 0
        self.ou_finish_ctr = 0
        self.group_finish_ctr = 0
        self.sd_finish_ctr = 0
        self.spn_finish_ctr = 0
        self.member_finish_ctr = 0
        self.domaininfo_finish_ctr = 0
        self.gpo_finish_ctr = 0

        self.total_progress = None
        self.total_counter = 0
        self.total_counter_steps = 100
Beispiel #6
0
class SMBGathererManager:
	def __init__(self, smb_mgr, worker_cnt = 50):
		self.in_q = AsyncProcessQueue()
		self.out_q = AsyncProcessQueue()
		self.smb_mgr = smb_mgr
		self.gathering_type = ['all']
		self.localgroups = ['Administrators', 'Distributed COM Users','Remote Desktop Users']
		self.concurrent_connections = worker_cnt
		self.domain = None
		self.dc_ip = None
		self.timeout = 3
		self.db_conn = None

		self.total_targets = 0
		self.targets = []
		self.targets_file = None
		self.ldap_conn = None
		self.target_ad = None
		self.lookup_ad = None #if specified, it will look up the targets in the DB.
		self.out_file = None

		self.gatherer = None
		
		self.use_progress_bar = True
		self.prg_hosts = None
		self.prg_shares = None
		self.prg_sessions = None
		self.prg_groups = None
		self.prg_errors = None

		self.results_thread = None

	def __target_generator(self):
		if self.db_conn is not None:
			session = get_session(self.db_conn)
		
		for target in self.targets:
			tid = -1
			yield (tid, target)

		if self.targets_file is not None:
			tid = -1
			with open(self.targets_file, 'r') as f:
				for line in f:
					line = line.strip()
					yield (tid, line)

		if self.ldap_conn is not None:
			ldap_filter = r'(&(sAMAccountType=805306369))'
			attributes = ['sAMAccountName']
			for entry in self.ldap_conn.pagedsearch(ldap_filter, attributes):
				tid = -1
				if self.lookup_ad is not None:
					res = session.query(JackDawADMachine)\
							.filter_by(ad_id = self.lookup_ad)\
							.with_entities(JackDawADMachine.id)\
							.filter(JackDawADMachine.sAMAccountName == entry['attributes']['sAMAccountName'])\
							.first()
					if res is not None:
						tid = res[0]
				
				yield (tid, entry['attributes']['sAMAccountName'][:-1])

		if self.target_ad is not None:
			for target_id, target_name in session.query(JackDawADMachine).filter_by(ad_id = self.target_ad).with_entities(JackDawADMachine.id, JackDawADMachine.sAMAccountName):
				yield (target_id, target_name[:-1])

		if self.db_conn is not None:
			session.close()

	def get_results(self):
		session = None
		if self.db_conn is not None:
			session = get_session(self.db_conn)
		
		while True:
			x = self.out_q.get()
			if x is None:
				break

			tid, target, result, error = x
			if result is None and error is not None:
				#something went error
				logger.debug('[AIOSMBScanner][TargetError][%s] %s' % (target.get_ip(), error))
				if self.use_progress_bar is True:
					self.prg_errors.update()

			if result is not None:
				if self.use_progress_bar is True:
					if isinstance(result, NetSession):
						self.prg_sessions.update()
					elif isinstance(result, NetShare):
						self.prg_shares.update()
					elif isinstance(result, LocalGroup):
						self.prg_groups.update()

				if session is None:
					logger.debug(target, str(result), error)
				else:
					session.add(result)
					session.commit()

			if result is None and error is None:
				logger.debug('Finished: %s' % target.ip)
				if self.use_progress_bar is True:
					self.prg_hosts.update()
	
	def run(self):
		self.in_q = AsyncProcessQueue()
		self.out_q = AsyncProcessQueue()
		if self.use_progress_bar is True:
			self.prg_hosts = tqdm(desc='HOSTS', ascii = True)
			self.prg_shares = tqdm(desc='Shares', ascii = True)
			self.prg_sessions = tqdm(desc='Sessions', ascii = True)
			self.prg_groups = tqdm(desc='LocalGroup', ascii = True)
			self.prg_errors = tqdm(desc='Errors', ascii = True)

		self.results_thread = threading.Thread(target = self.get_results)
		self.results_thread.daemon = True
		self.results_thread.start()

		self.gatherer = AIOSMBGatherer(self.in_q, self.out_q, self.smb_mgr, gather = self.gathering_type, localgroups = self.localgroups, concurrent_connections = self.concurrent_connections)
		self.gatherer.start()
		
		for target in self.__target_generator():
			self.total_targets += 1
			if self.use_progress_bar is True:
				self.prg_hosts.total = self.total_targets
			self.in_q.put(target)
		
		self.in_q.put(None)
		#if self.use_progress_bar is True:
		#	self.prg_hosts.total = self.total_targets

		self.results_thread.join()
Beispiel #7
0
class LDAPEnumeratorManager:
    def __init__(self, db_conn, ldam_mgr, agent_cnt=None, queue_size=10):
        self.db_conn = db_conn
        self.ldam_mgr = ldam_mgr

        self.session = None

        self.queue_size = queue_size
        self.agent_in_q = AsyncProcessQueue()
        self.agent_out_q = AsyncProcessQueue(100)
        self.agents = []
        self.agent_cnt = multiprocessing.cpu_count(
        ) if agent_cnt is None else agent_cnt
        self.ad_id = None

        self.user_ctr = 0
        self.machine_ctr = 0
        self.ou_ctr = 0
        self.group_ctr = 0
        self.sd_ctr = 0
        self.spn_ctr = 0
        self.member_ctr = 0
        self.domaininfo_ctr = 0
        self.gpo_ctr = 0

        self.user_finish_ctr = 0
        self.machine_finish_ctr = 0
        self.ou_finish_ctr = 0
        self.group_finish_ctr = 0
        self.sd_finish_ctr = 0
        self.spn_finish_ctr = 0
        self.member_finish_ctr = 0
        self.domaininfo_finish_ctr = 0
        self.gpo_finish_ctr = 0

        self.total_progress = None
        self.total_counter = 0
        self.total_counter_steps = 100

    @staticmethod
    def spn_to_account(spn):
        if spn.find('/') != -1:
            return spn.rsplit('/')[1].upper() + '$'

    def setup(self):
        logger.debug('mgr setup')
        self.total_progress = tqdm(desc='LDAP info entries', ascii=True)
        self.session = get_session(self.db_conn)
        for _ in range(self.agent_cnt):
            agent = LDAPEnumeratorAgent(self.ldam_mgr, self.agent_in_q,
                                        self.agent_out_q)
            agent.daemon = True
            agent.start()
            self.agents.append(agent)

    def enum_domain(self, info):
        #print('Got domain!')
        self.session.add(info)
        self.session.commit()
        self.session.refresh(info)
        self.ad_id = info.id

        self.user_ctr += 1
        job = LDAPAgentJob(LDAPAgentCommand.USERS, self.ad_id)
        self.agent_in_q.put(job)

        self.machine_ctr += 1
        job = LDAPAgentJob(LDAPAgentCommand.MACHINES, self.ad_id)
        self.agent_in_q.put(job)

        self.group_ctr += 1
        job = LDAPAgentJob(LDAPAgentCommand.GROUPS, self.ad_id)
        self.agent_in_q.put(job)

        self.ou_ctr += 1
        job = LDAPAgentJob(LDAPAgentCommand.OUS, self.ad_id)
        self.agent_in_q.put(job)

        self.spn_ctr += 1
        job = LDAPAgentJob(LDAPAgentCommand.SPNSERVICES, self.ad_id)
        self.agent_in_q.put(job)

        self.gpo_ctr += 1
        job = LDAPAgentJob(LDAPAgentCommand.GPOS, self.ad_id)
        self.agent_in_q.put(job)

    def enum_machine(self, machine_data):
        #print('Got machine object!')
        machine = Machine.from_adcomp(machine_data)
        machine.ad_id = self.ad_id
        self.session.add(machine)
        self.session.commit()
        self.session.refresh(machine)

        for spn in getattr(machine, 'allowedtodelegateto', []):
            con = MachineConstrainedDelegation()
            con.spn = spn
            con.targetaccount = LDAPEnumeratorManager.spn_to_account(spn)
            machine.allowedtodelegateto.append(con)

        self.session.commit()

        membership_attr = {
            'dn': str(machine.dn),
            'cn': str(machine.cn),
            'guid': str(machine.objectGUID),
            'sid': str(machine.objectSid),
            'type': 'machine'
        }

        self.member_ctr += 1
        job = LDAPAgentJob(LDAPAgentCommand.MEMBERSHIPS, membership_attr)
        self.agent_in_q.put(job)

        self.sd_ctr += 1
        job = LDAPAgentJob(LDAPAgentCommand.SDS, {
            'dn': machine.dn,
            'obj_type': 'machine'
        })
        self.agent_in_q.put(job)
        del machine

    def store_user(self, user):
        user.ad_id = self.ad_id

        #self.session.flush()
        #self.session.refresh(user)

        for spn in getattr(user, 'allowedtodelegateto', []):
            con = JackDawUserConstrainedDelegation()
            con.spn = spn
            con.targetaccount = LDAPEnumeratorManager.spn_to_account(spn)
            user.allowedtodelegateto.append(con)

        self.session.add(user)
        self.session.flush()

        membership_attr = {
            'dn': str(user.dn),
            'cn': str(user.cn),
            'guid': str(user.objectGUID),
            'sid': str(user.objectSid),
            'type': 'user'
        }

    def enum_users(self):

        self.member_ctr += 1
        job = LDAPAgentJob(LDAPAgentCommand.MEMBERSHIPS, membership_attr)
        self.agent_in_q.put(job)

        self.sd_ctr += 1
        job = LDAPAgentJob(LDAPAgentCommand.SDS, {
            'dn': user.dn,
            'obj_type': 'user'
        })
        self.agent_in_q.put(job)

    def enum_group(self, group):
        #qry =

        membership_attr = {
            'dn': str(group.dn),
            'cn': str(group.cn),
            'guid': str(group.guid),
            'sid': str(group.sid),
            'type': 'group'
        }

        self.member_ctr += 1
        job = LDAPAgentJob(LDAPAgentCommand.MEMBERSHIPS, membership_attr)
        self.agent_in_q.put(job)

        self.sd_ctr += 1
        job = LDAPAgentJob(LDAPAgentCommand.SDS, {
            'dn': group.dn,
            'obj_type': 'group'
        })
        self.agent_in_q.put(job)

    def store_groups(self, group):
        group.ad_id = self.ad_id
        self.session.add(group)
        self.session.commit()

    def enum_ou(self, ou):
        ou.ad_id = self.ad_id
        self.session.add(ou)
        self.session.commit()
        self.session.refresh(ou)

        if ou.gPLink is not None and ou.gPLink != 'None':
            for x in ou.gPLink.split(']'):
                if x is None or x == 'None':
                    continue
                x = x.strip()
                if x == '':
                    continue
                gp, order = x[1:].split(';')
                gp = re.search(r'{(.*?)}', gp).group(1)
                gp = '{' + gp + '}'

                link = Gplink()
                link.ent_id = ou.id
                link.gpo_dn = gp
                link.order = order
                self.session.add(link)
        self.session.commit()

        self.sd_ctr += 1
        job = LDAPAgentJob(LDAPAgentCommand.SDS, {
            'dn': ou.dn,
            'obj_type': 'ou'
        })
        self.agent_in_q.put(job)

    def enum_gpo(self, res):
        #print('Got gpo object!')
        res.ad_id = self.ad_id
        self.session.add(res)
        self.session.commit()

        self.sd_ctr += 1
        job = LDAPAgentJob(LDAPAgentCommand.SDS, {
            'dn': res.dn,
            'obj_type': 'user'
        })
        self.agent_in_q.put(job)

    def store_spnservice(self, spn):
        #print('Got SPNSERVICE!')
        spn.ad_id = self.ad_id
        self.session.add(spn)
        self.session.commit()

    def store_membership(self, res):
        #print('Got membership object!')
        res.ad_id = self.ad_id
        self.session.add(res)
        self.session.commit()

    def store_sd(self, data):
        #print('Got SD object!')
        sd = data['sd']
        obj_type = data['obj_type']
        order_ctr = 0
        for ace in sd.nTSecurityDescriptor.Dacl.aces:
            acl = JackDawADDACL()
            acl.ad_id = self.ad_id
            acl.object_type = obj_type
            acl.object_type_guid = OBJECTTYPE_GUID_MAP.get(obj_type)
            acl.owner_sid = str(sd.nTSecurityDescriptor.Owner)
            acl.group_sid = str(sd.nTSecurityDescriptor.Group)
            acl.ace_order = order_ctr

            order_ctr += 1
            acl.guid = str(sd.objectGUID)
            if sd.objectSid:
                acl.sid = str(sd.objectSid)
            if sd.cn:
                acl.cn = sd.cn
            if sd.distinguishedName:
                acl.dn = str(sd.distinguishedName)
            acl.sd_control = sd.nTSecurityDescriptor.Control

            acl.ace_type = ace.AceType.name
            acl.ace_mask = ace.Mask
            t = getattr(ace, 'ObjectType', None)
            if t:
                acl.ace_objecttype = str(t)

            t = getattr(ace, 'InheritedObjectType', None)
            if t:
                acl.ace_inheritedobjecttype = str(t)

            true_attr, false_attr = JackDawADDACL.mask2attr(ace.Mask)

            for attr in true_attr:
                setattr(acl, attr, True)
            for attr in false_attr:
                setattr(acl, attr, False)

            true_attr, false_attr = JackDawADDACL.hdrflag2attr(ace.AceFlags)

            for attr in true_attr:
                setattr(acl, attr, True)
            for attr in false_attr:
                setattr(acl, attr, False)

            acl.ace_sid = str(ace.Sid)
            self.session.add(acl)

        self.session.commit()

    def check_status(self):
        #print('user')
        #print(self.user_ctr)
        #print(self.user_finish_ctr)
        #
        #print('machine')
        #print(self.machine_ctr)
        #print(self.machine_finish_ctr)
        #
        #print('ou')
        #print(self.ou_ctr)
        #print(self.ou_finish_ctr)
        #
        #print('group')
        #print(self.group_ctr)
        #print(self.group_finish_ctr)
        #
        #print('sd')
        #print(self.sd_ctr)
        #print(self.sd_finish_ctr)
        #
        #print('spn')
        #print(self.spn_ctr)
        #print(self.spn_finish_ctr)
        #
        #print('member')
        #print(self.member_ctr)
        #print(self.member_finish_ctr)
        #
        #print('domain')
        #print(self.domaininfo_ctr)
        #print(self.domaininfo_finish_ctr)

        self.total_counter += 1
        if self.total_counter == self.total_counter_steps:
            self.total_progress.update(self.total_counter)
            self.total_counter = 0

        if self.user_ctr == self.user_finish_ctr \
         and self.machine_ctr == self.machine_finish_ctr\
         and self.ou_ctr == self.ou_finish_ctr\
         and self.group_ctr == self.group_finish_ctr\
         and self.sd_ctr == self.sd_finish_ctr\
         and self.spn_ctr == self.spn_finish_ctr\
         and self.member_ctr == self.member_finish_ctr\
         and self.domaininfo_ctr == self.domaininfo_finish_ctr\
         and self.gpo_ctr == self.gpo_finish_ctr:
            self.total_progress.update(self.total_counter)
            return True
        return False

    def stop_agents(self):
        logger.debug('mgr stop')
        self.session.commit()
        self.session.close()
        for _ in self.agents:
            self.agent_in_q.put(None)
        for agent in self.agents:
            agent.join()
        logger.debug('All agents finished!')

    def run(self):
        logger.info(
            '[+] Starting LDAP information acqusition. This might take a while...'
        )
        self.setup()
        logger.debug('setup finished!')

        self.domaininfo_ctr += 1
        job = LDAPAgentJob(LDAPAgentCommand.DOMAININFO, None)
        self.agent_in_q.put(job)

        while True:
            res = self.agent_out_q.get()
            #print(res)
            res_type, res = res
            if res_type == LDAPAgentCommand.DOMAININFO:
                self.enum_domain(res)

            elif res_type == LDAPAgentCommand.USER:
                self.enum_user(res)

            elif res_type == LDAPAgentCommand.MACHINE:
                self.enum_machine(res)

            elif res_type == LDAPAgentCommand.SPNSERVICE:
                self.store_spnservice(res)

            elif res_type == LDAPAgentCommand.GROUP:
                self.enum_group(res)

            elif res_type == LDAPAgentCommand.OU:
                self.enum_ou(res)

            elif res_type == LDAPAgentCommand.SD:
                self.store_sd(res)

            elif res_type == LDAPAgentCommand.GPO:
                self.enum_gpo(res)

            elif res_type == LDAPAgentCommand.MEMBERSHIP:
                self.store_membership(res)

            elif res_type == LDAPAgentCommand.EXCEPTION:
                logger.warning(res)

            elif res_type == LDAPAgentCommand.SPNSERVICES_FINISHED:
                logger.debug('SPN enumeration finished!')
                self.spn_finish_ctr += 1
            elif res_type == LDAPAgentCommand.USERS_FINISHED:
                logger.debug('Users enumeration finished!')
                self.user_finish_ctr += 1
            elif res_type == LDAPAgentCommand.MACHINES_FINISHED:
                logger.debug('Machines enumeration finished!')
                self.machine_finish_ctr += 1
            elif res_type == LDAPAgentCommand.OUS_FINISHED:
                logger.debug('OUs enumeration finished!')
                self.ou_finish_ctr += 1
            elif res_type == LDAPAgentCommand.GROUPS_FINISHED:
                logger.debug('Groups enumeration finished!')
                self.group_finish_ctr += 1
            elif res_type == LDAPAgentCommand.MEMBERSHIPS_FINISHED:
                logger.debug('Memberships enumeration finished!')
                self.member_finish_ctr += 1
            elif res_type == LDAPAgentCommand.SDS_FINISHED:
                logger.debug('Secuirty Descriptor enumeration finished!')
                self.sd_finish_ctr += 1
            elif res_type == LDAPAgentCommand.DOMAININFO_FINISHED:
                logger.debug('Domaininfo enumeration finished!')
                self.domaininfo_finish_ctr += 1
            elif res_type == LDAPAgentCommand.GPOS_FINISHED:
                logger.debug('GPOs enumeration finished!')
                self.gpo_finish_ctr += 1

            if self.check_status() == True:
                break

        self.stop_agents()
        logger.info('[+] LDAP information acqusition finished!')
        return self.ad_id
Beispiel #8
0
class LDAPEnumeratorManager:
	def __init__(self, db_conn, ldam_mgr, agent_cnt = None, queue_size = 10):
		self.db_conn = db_conn
		self.ldam_mgr = ldam_mgr

		self.session = None

		self.queue_size = queue_size
		self.agent_in_q = AsyncProcessQueue()
		self.agent_out_q = AsyncProcessQueue(1000)
		self.agents = []

		self.agent_cnt = agent_cnt
		if agent_cnt is None:
			self.agent_cnt = min(multiprocessing.cpu_count(), 3)

		self.ad_id = None

		self.user_ctr = 0
		self.machine_ctr = 0
		self.ou_ctr = 0
		self.group_ctr = 0
		self.sd_ctr = 0
		self.spn_ctr = 0
		self.member_ctr = 0
		self.domaininfo_ctr = 0
		self.gpo_ctr = 0
		self.trust_ctr = 0

		self.user_finish_ctr = 0
		self.machine_finish_ctr = 0
		self.ou_finish_ctr = 0
		self.group_finish_ctr = 0
		self.sd_finish_ctr = 0
		self.spn_finish_ctr = 0
		self.member_finish_ctr = 0
		self.domaininfo_finish_ctr = 0
		self.gpo_finish_ctr = 0

		self.total_progress = None
		self.total_counter = 0
		self.total_counter_steps = 100
		self.progress_total_present = False
		self.remaining_ctr = None

		self.enum_finished_evt = None #multiprocessing.Event()
		
		self.running_enums = {}
		self.finished_enums = []
		self.enum_types = [
			'adinfo',
			'trusts',
			'users', 
			'machines',
			'groups',
			'memberships', 
			'sds', 
			'ous', 
			'gpos',
			'spns'
		]
		self.enum_types_len = len(self.enum_types)

	def check_jobs(self, finished_type):
		self.session.commit()
		if finished_type is not None:
			logger.debug('%s enumeration finished!' % MSLDAP_JOB_TYPES_INV[finished_type])
			del self.running_enums[MSLDAP_JOB_TYPES_INV[finished_type]]
			self.finished_enums.append(MSLDAP_JOB_TYPES_INV[finished_type])

		lr = len(self.running_enums)
		if self.enum_types_len == len(self.finished_enums):
			#everything finished
			return True

		if lr == self.agent_cnt:
			#enums still running with max performance
			return False

		if lr < self.agent_cnt:
			#we can start a new enum
			for _ in range(self.agent_cnt - lr):
				if len(self.enum_types) > 0:
					next_type = self.enum_types.pop(0)
				else:
					return False
				
				if next_type == 'adinfo':
					self.enum_domain()
					#this must be the first!
					self.running_enums[next_type] = 1
					return False
				
				elif next_type == 'users':
					self.enum_users()

				elif next_type == 'machines':
					self.enum_machines()
				elif next_type == 'sds':
					self.enum_sds()
				elif next_type == 'memberships':
					self.enum_memberships()
				elif next_type == 'ous':
					self.enum_ous()
				elif next_type == 'gpos':
					self.enum_gpos()
				elif next_type == 'groups':
					self.enum_groups()
				elif next_type == 'spns':
					self.enum_spnservices()
				elif next_type == 'trusts':
					self.enum_trusts()
				else:
					logger.warning('Unknown next_type! %s' % next_type)

				self.running_enums[next_type] = 1

			return False
		

	@staticmethod
	def spn_to_account(spn):
		if spn.find('/') != -1:
			return spn.rsplit('/')[1].upper() + '$'
	
	def get_enum_stats(self):
		return {
			'users' : self.user_ctr,
			'machines' : self.machine_ctr,
			'ous' : self.ou_ctr,
			'groups' : self.group_ctr,
			'security_descriptors' : self.sd_ctr,
			'spns' : self.spn_ctr,
			'membership_tokens' : self.member_ctr,
			'domaininfo' : self.domaininfo_ctr,
			'gpos' : self.gpo_ctr,
		}

	def setup(self):
		logger.debug('mgr setup')
		self.total_progress = tqdm(desc='LDAP info entries', ascii = True)
		self.session = get_session(self.db_conn)
		
		for _ in range(self.agent_cnt):
			agent = LDAPEnumeratorAgent(self.ldam_mgr, self.agent_in_q, self.agent_out_q)
			agent.daemon = True
			agent.start()
			self.agents.append(agent)

	def enum_domain(self):
		logger.debug('Enumerating domain')
		job = LDAPAgentJob(LDAPAgentCommand.DOMAININFO, None)
		self.agent_in_q.put(job)

	def store_domain(self, info):
		self.session.add(info)
		self.session.commit()
		self.session.refresh(info)
		self.ad_id = info.id

	def enum_trusts(self):
		logger.debug('Enumerating trusts')
		job = LDAPAgentJob(LDAPAgentCommand.TRUSTS, None)
		self.agent_in_q.put(job)

	def store_trust(self, trust):
		trust.ad_id = self.ad_id
		self.session.add(trust)
		self.session.flush()

	def enum_users(self):
		logger.debug('Enumerating users')
		job = LDAPAgentJob(LDAPAgentCommand.USERS, self.ad_id)
		self.agent_in_q.put(job)
		

	def store_user(self, user):
		user.ad_id = self.ad_id

		#self.session.flush()
		#self.session.refresh(user)

		for spn in getattr(user,'allowedtodelegateto',[]):
			con = JackDawUserConstrainedDelegation()
			con.spn = spn
			con.targetaccount = LDAPEnumeratorManager.spn_to_account(spn)
			user.allowedtodelegateto.append(con)

		self.session.add(user)
		self.session.flush()

	def enum_machines(self):
		logger.debug('Enumerating machines')
		job = LDAPAgentJob(LDAPAgentCommand.MACHINES, self.ad_id)
		self.agent_in_q.put(job)

	def store_machine(self, machine):
		machine.ad_id = self.ad_id
		self.session.add(machine)
		#self.session.commit()
		self.session.flush()
	
	def enum_groups(self):
		logger.debug('Enumerating groups')
		job = LDAPAgentJob(LDAPAgentCommand.GROUPS, self.ad_id)
		self.agent_in_q.put(job)

	def store_group(self, group):
		group.ad_id = self.ad_id
		self.session.add(group)
		self.session.flush()

	def enum_ous(self):
		logger.debug('Enumerating ous')
		job = LDAPAgentJob(LDAPAgentCommand.OUS, self.ad_id)
		self.agent_in_q.put(job)

	def store_ous(self, ou):
		ou.ad_id = self.ad_id
		self.session.add(ou)
		self.session.commit()
		self.session.refresh(ou)

		if ou.gPLink is not None and ou.gPLink != 'None':
			for x in ou.gPLink.split(']'):
				if x is None or x == 'None':
					continue
				x = x.strip()
				if x == '':
					continue
				gp, order = x[1:].split(';')
				gp = re.search(r'{(.*?)}', gp).group(1)
				gp = '{' + gp + '}'

				link = JackDawADGplink()
				link.ent_id = ou.id
				link.gpo_dn = gp
				link.order = order
				self.session.add(link)
		self.session.flush()

	def enum_spnservices(self):		
		logger.debug('Enumerating spns')
		job = LDAPAgentJob(LDAPAgentCommand.SPNSERVICES, self.ad_id)
		self.agent_in_q.put(job)

	def store_spn(self, spn):
		spn.ad_id = self.ad_id
		self.session.add(spn)
		self.session.flush()

	def enum_gpos(self):
		logger.debug('Enumerating gpos')
		job = LDAPAgentJob(LDAPAgentCommand.GPOS, self.ad_id)
		self.agent_in_q.put(job)

	def store_gpo(self, gpo):
		gpo.ad_id = self.ad_id
		self.session.add(gpo)
		self.session.flush()

	def enum_memberships(self):
		logger.debug('Enumerating memberships')
		job = LDAPAgentJob(LDAPAgentCommand.MEMBERSHIPS, None)
		self.agent_in_q.put(job)


	def store_membership(self, res):
		res.ad_id = self.ad_id
		self.session.add(res)
		
		if self.member_finish_ctr % 1000 == 0:
			self.session.commit()
		else:
			self.session.flush()

	def enum_sds(self):
		logger.debug('Enumerating security descriptors')
		job = LDAPAgentJob(LDAPAgentCommand.SDS, None)
		self.agent_in_q.put(job)

	def store_sd(self, sd):
		#secdesc = SECURITY_DESCRIPTOR.from_bytes(sd.nTSecurityDescriptor)
		#
		if sd.objectClass[-1] in ['user', 'group']:
			obj_type = sd.objectClass[-1]
		elif sd.objectClass[-1] == 'computer':
			obj_type = 'machine'
		elif sd.objectClass[-1] == 'groupPolicyContainer':
			obj_type = 'gpo'
		elif sd.objectClass[-1] == 'organizationalUnit':
			obj_type = 'ou'
		else:
			obj_type = sd.objectClass[-1]

		jdsd = JackDawSD()

		jdsd.ad_id = self.ad_id
		jdsd.guid =  str(sd.objectGUID)
		if sd.objectSid:
			jdsd.sid = str(sd.objectSid)
		jdsd.object_type = obj_type
		jdsd.sd = base64.b64encode(sd.nTSecurityDescriptor)
		
		self.session.add(jdsd)
		
		if self.sd_ctr % 1000 == 0:
			self.session.commit()
		else:
			self.session.flush()

	def update_progress(self):
		if self.remaining_ctr is not None and self.progress_total_present is False:
			self.total_progress.total = (self.remaining_ctr +  self.total_counter)
			self.progress_total_present = True
		self.total_counter += 1
		if self.total_counter % self.total_counter_steps == 0:
			self.total_progress.update(self.total_counter_steps)

		if self.total_counter % 5000 == 0:
			running_jobs = ','.join([k for k in self.running_enums])
			finished_jobs = ','.join(self.finished_enums)
			msg = 'FINISHED: %s RUNNING: %s' % (finished_jobs, running_jobs)
			#logger.debug(msg)
			self.total_progress.set_description(msg)
			self.total_progress.refresh()

	def stop_agents(self):
		logger.debug('mgr stop')
		self.session.commit()
		self.session.close()
		for _ in range(self.agent_cnt):
			self.agent_in_q.put(None)
		for agent in self.agents:
			agent.join()
		logger.debug('All agents finished!')

	def run(self):
		logger.info('[+] Starting LDAP information acqusition. This might take a while...')
		self.setup()
		logger.debug('setup finished!')

		self.check_jobs(None)

		while True:
			res = self.agent_out_q.get()
			self.update_progress()
			res_type, res = res

			if res_type == LDAPAgentCommand.DOMAININFO:
				self.domaininfo_ctr += 1
				self.store_domain(res)
			
			elif res_type == LDAPAgentCommand.USER:
				self.user_ctr += 1
				self.store_user(res)

			elif res_type == LDAPAgentCommand.MACHINE:
				self.machine_ctr += 1
				self.store_machine(res)

			elif res_type == LDAPAgentCommand.GROUP:
				self.group_ctr += 1
				self.store_group(res)

			elif res_type == LDAPAgentCommand.OU:
				self.ou_ctr += 1
				self.store_ous(res)

			elif res_type == LDAPAgentCommand.GPO:
				self.gpo_ctr += 1
				self.store_gpo(res)

			elif res_type == LDAPAgentCommand.SPNSERVICE:
				self.spn_ctr += 1
				self.store_spn(res)
				
			elif res_type == LDAPAgentCommand.SD:
				self.sd_ctr += 1
				self.store_sd(res)
				
			elif res_type == LDAPAgentCommand.MEMBERSHIP:
				self.member_ctr += 1
				self.store_membership(res)

			elif res_type == LDAPAgentCommand.TRUSTS:
				self.trust_ctr += 1
				self.store_trust(res)

			elif res_type == LDAPAgentCommand.EXCEPTION:
				logger.warning(str(res))
				
			elif res_type.name.endswith('FINISHED'):
				if self.check_jobs(res_type) is True:
					break
		
		self.stop_agents()
		logger.info('[+] LDAP information acqusition finished!')
		return self.ad_id
Beispiel #9
0
class ShareGathererManager:
    def __init__(self,
                 settings_base,
                 db_conn=None,
                 db_session=None,
                 worker_cnt=30):
        self.settings_base = settings_base
        self.in_q = AsyncProcessQueue()
        self.out_q = AsyncProcessQueue()
        self.worker_cnt = worker_cnt
        self.targets_thread = None
        self.db_conn = db_conn
        self.db_session = db_session
        self.dir_lookup = {}
        self.exclude_shares = ['IPC$']

        self.use_progress_bar = True
        self.prg_dirs = None
        self.prg_files = None
        self.prg_errors = None

    def generate_targets(self):
        session = get_session(self.db_conn)
        qry = session.query(
            JackDawADMachine.sAMAccountName, NetShare.id,
            NetShare.netname).filter(
                JackDawADMachine.ad_id == self.settings_base.ad_id).filter(
                    JackDawADMachine.id == NetShare.machine_id)

        for mname, shareid, sharename in qry.all():
            if sharename in self.exclude_shares:
                continue
            target = mname if mname[-1] != '$' else mname[:-1]
            fullpath = '\\\\%s\\%s' % (target, sharename)
            smbshare = SMBShare(fullpath=fullpath)

            #print(target)
            #print(fullpath)
            #print(smbshare)

            settings = copy.deepcopy(self.settings_base)
            settings.share_id = shareid
            settings.target = target
            settings.share = smbshare
            self.in_q.put((SMBShareGathererCmd.START, settings))

        session.close()
        self.in_q.put((SMBShareGathererCmd.END, None))

    def init_dbsession(self):
        if self.db_session is not None:
            return
        self.db_session = get_session(self.db_conn)

    def setup(self):
        self.init_dbsession()
        self.targets_thread = threading.Thread(target=self.generate_targets)
        self.targets_thread.daemon = True
        self.targets_thread.start()

        self.gatherer = ShareGathererProcess(self.in_q, self.out_q,
                                             self.worker_cnt)
        self.gatherer.start()

        if self.use_progress_bar is True:
            self.prg_dirs = tqdm(desc='Dirs', ascii=True)
            self.prg_files = tqdm(desc='files', ascii=True)
            self.prg_errors = tqdm(desc='Errors', ascii=True)

    def get_dir_id(self, unc_path, name):
        #print(name)
        if name == '' or name is None:
            return None
        # this might get extended later!
        return self.dir_lookup[unc_path]

    def store_sd(self, sd, object_type, object_id):
        if sd is None:
            return
        order_ctr = 0
        for ace in sd.Dacl.aces:
            acl = NetDACL()
            acl.object_id = object_id
            acl.object_type = object_type
            acl.owner_sid = str(sd.Owner)
            acl.group_sid = str(sd.Group)
            acl.ace_order = order_ctr

            order_ctr += 1
            acl.sd_control = sd.Control

            acl.ace_type = ace.Header.AceType.name
            acl.ace_mask = ace.Mask
            t = getattr(ace, 'ObjectType', None)
            if t:
                acl.ace_objecttype = str(t)

            t = getattr(ace, 'InheritedObjectType', None)
            if t:
                acl.ace_inheritedobjecttype = str(t)

            true_attr, false_attr = NetDACL.mask2attr(ace.Mask)

            for attr in true_attr:
                setattr(acl, attr, True)
            for attr in false_attr:
                setattr(acl, attr, False)

            true_attr, false_attr = NetDACL.hdrflag2attr(ace.Header.AceFlags)

            for attr in true_attr:
                setattr(acl, attr, True)
            for attr in false_attr:
                setattr(acl, attr, False)

            acl.ace_sid = str(ace.Sid)
            self.db_session.add(acl)

        self.db_session.commit()

    def run(self):
        self.setup()
        try:
            self.collect_results()
        except:
            print(
                '!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!'
            )
            traceback.print_exc()

    def collect_results(self):
        while True:
            result = self.out_q.get()
            if result is None:
                #print('enumerator finished!')
                break

            if isinstance(result, SMBEnumError):
                #something went error
                tid = result.settings
                if result.settings is not None:
                    tid = result.settings.target
                logger.debug('[AIOSMBShareGatherer][Error][%s] %s' %
                             (tid, result.error))
                if self.use_progress_bar is True:
                    self.prg_errors.update()

            elif isinstance(result, SMBShareGathererResult):
                if result.type == 'dir':
                    if self.use_progress_bar is True:
                        self.prg_dirs.update()

                    nd = NetDir()
                    nd.share_id = result.settings.share_id
                    nd.parent_id = self.get_dir_id(result.result.unc_path,
                                                   result.result.name)
                    nd.creation_time = result.result.creation_time
                    nd.last_access_time = result.result.creation_time
                    nd.last_write_time = result.result.last_write_time
                    nd.change_time = result.result.change_time
                    nd.unc = result.result.unc_path
                    nd.name = result.result.name
                    self.db_session.add(nd)
                    self.db_session.commit()
                    self.db_session.refresh(nd)
                    self.dir_lookup[result.result.unc_path] = nd.id
                    for subdir in result.result.subdirs:
                        sd = result.result.subdirs[subdir]
                        nsd = NetDir()
                        nsd.share_id = result.settings.share_id
                        nsd.parent_id = nd.id
                        nsd.creation_time = sd.creation_time
                        nsd.last_access_time = sd.creation_time
                        nsd.last_write_time = sd.last_write_time
                        nsd.change_time = sd.change_time
                        nsd.unc = sd.unc_path
                        nsd.name = sd.name
                        self.db_session.add(nsd)
                        self.db_session.commit()
                        self.db_session.refresh(nsd)
                        self.dir_lookup[sd.unc_path] = nd.id
                        self.store_sd(sd.sid, 'dir', nd.id)

                    for filename in result.result.files:
                        if self.use_progress_bar is True:
                            self.prg_files.update()
                        f = result.result.files[filename]
                        nf = NetFile()
                        nf.folder_id = nd.id
                        nf.creation_time = f.creation_time
                        nf.last_access_time = f.last_access_time
                        nf.last_write_time = f.last_write_time
                        nf.change_time = f.change_time
                        nf.unc = f.unc_path
                        nf.size = f.size
                        name = f.name
                        x = f.name.rsplit('.', 1)
                        if len(x) > 1:
                            name = x[0]
                            ext = x[1]
                        nf.name = name
                        nf.ext = ext
                        self.db_session.add(nf)
                        self.db_session.commit()
                        self.db_session.refresh(nf)
                        self.store_sd(f.sid, 'file', nf.id)