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