def test_check_repeatable_abilities(self, repeatable_ability): test_adversary = Adversary(adversary_id='123', name='test', description='', atomic_ordering=['456']) ram = dict(adversaries=[test_adversary], abilities=[repeatable_ability]) assert test_adversary.check_repeatable_abilities(ram['abilities'])
def test_store_existing(self, unrepeatable_ability, repeatable_ability): test_adversary = Adversary(adversary_id='123', name='test', description='', atomic_ordering=['123']) ram = dict(adversaries=[test_adversary], abilities=[unrepeatable_ability, repeatable_ability]) test_adversary.atomic_ordering = ['456'] test_adversary.store(ram) assert ram['adversaries'][0].has_repeatable_abilities assert ram['adversaries'][0].atomic_ordering[0] == '456'
def test_adversary(self): self.run_async(self.data_svc.store( Adversary(adversary_id='123', name='test', description='test adversary', phases=dict()) )) self.run_async(self.data_svc.store( Adversary(adversary_id='123', name='test', description='test adversary', phases=dict()) )) adversaries = self.run_async(self.data_svc.locate('adversaries')) self.assertEqual(1, len(adversaries)) for x in adversaries: json.dumps(x.display)
async def _load_adversaries(self, plugin): for filename in glob.iglob('%s/adversaries/**/*.yml' % plugin.data_dir, recursive=True): for adv in self.strip_yml(filename): if adv.get('phases'): ordering = await self._load_phase_adversary_variant(adv) else: ordering = adv.get('atomic_ordering', list()) atomic_ordering = await self._link_abilities(ordering, adv) adversary = Adversary(adversary_id=adv['id'], name=adv['name'], description=adv['description'], atomic_ordering=atomic_ordering) adversary.access = plugin.access await self.store(adversary)
async def _load_adversaries(self, plugin): for filename in glob.iglob('%s/adversaries/**/*.yml' % plugin.data_dir, recursive=True): for adv in self.strip_yml(filename): phases = adv.get('phases', dict()) for p in adv.get('packs', []): adv_pack = await self._add_adversary_packs(p) if adv_pack: await self._merge_phases(phases, adv_pack) sorted_phases = [phases[x] for x in sorted(phases.keys())] phases = await self._add_phases(sorted_phases, adv) adversary = Adversary(adversary_id=adv['id'], name=adv['name'], description=adv['description'], phases=phases) adversary.access = plugin.access await self.store(adversary)
def setup_rest_svc_test(loop, data_svc): BaseWorld.apply_config(name='default', config={ 'app.contact.http': '0.0.0.0', 'plugins': ['sandcat', 'stockpile'], 'crypt_salt': 'BLAH', 'api_key': 'ADMIN123', 'encryption_key': 'ADMIN123', 'exfil_dir': '/tmp' }) loop.run_until_complete( data_svc.store( Ability(ability_id='123', test=BaseWorld.encode_string('curl #{app.contact.http}'), variations=[]))) loop.run_until_complete( data_svc.store( Adversary(adversary_id='123', name='test', description='test', phases=[]))) loop.run_until_complete( data_svc.store(Agent(paw='123', sleep_min=2, sleep_max=8, watchdog=0))) loop.run_until_complete( data_svc.store( Planner(planner_id='123', name='test', module='test', params=dict()))) loop.run_until_complete( data_svc.store(Source(identifier='123', name='test', facts=[])))
def setup_planning_test(loop, ability, agent, operation, data_svc, init_base_world): tability = ability(ability_id='123', executor='sh', platform='darwin', test=BaseWorld.encode_string('mkdir test'), cleanup=BaseWorld.encode_string('rm -rf test'), variations=[]) tagent = agent(sleep_min=1, sleep_max=2, watchdog=0, executors=['sh'], platform='darwin') tsource = Source(id='123', name='test', facts=[], adjustments=[]) toperation = operation(name='test1', agents=tagent, adversary=Adversary(name='test', description='test', atomic_ordering=[], adversary_id='XYZ'), source=tsource) loop.run_until_complete(data_svc.store(tability)) loop.run_until_complete( data_svc.store( Obfuscator( name='plain-text', description= 'Does no obfuscation to any command, instead running it in plain text', module='plugins.stockpile.app.obfuscators.plain_text'))) yield tability, tagent, toperation
async def _load_adversaries(self, directory): for filename in glob.iglob('%s/*.yml' % directory, recursive=True): for adv in self.strip_yml(filename): phases = [ dict(phase=k, id=i) for k, v in adv.get('phases', dict()).items() for i in v ] ps = [] for p in adv.get('packs', []): ps.append(await self._add_adversary_packs(p)) for pack in ps: phases += pack if adv.get('visible', True): pp = defaultdict(list) for phase in phases: matching_abilities = await self.locate( 'abilities', match=dict(ability_id=phase['id'])) if not len(matching_abilities): self.log.error( 'Missing Ability (%s) for adversary: %s' % (phase['id'], adv['name'])) for ability in matching_abilities: pp[phase['phase']].append(ability) phases = dict(pp) await self.store( Adversary(adversary_id=adv['id'], name=adv['name'], description=adv['description'], phases=phases))
def setup_learning_service(loop, data_svc, ability, operation, link): tability = ability(tactic='discovery', technique_id='T1033', technique='Find', name='test', test='d2hvYW1pCg==', description='find active user', cleanup='', executor='sh', platform='darwin', payloads=['wifi.sh'], parsers=[], requirements=[], privilege=None, variations=[]) loop.run_until_complete(data_svc.store(tability)) toperation = operation(name='sample', agents=None, adversary=Adversary(name='sample', adversary_id='XYZ', atomic_ordering=[], description='test')) loop.run_until_complete(data_svc.store(toperation)) tlink = link(ability=tability, command='', paw='') yield toperation, tlink
async def _load_adversaries(self, directory): total = 0 for filename in glob.iglob('%s/*.yml' % directory, recursive=True): for adv in self.strip_yml(filename): phases = [ dict(phase=k, id=i) for k, v in adv.get('phases', dict()).items() for i in v ] for pack in [ await self._add_adversary_packs(p) for p in adv.get('packs', []) ]: phases += pack if adv.get('visible', True): pp = defaultdict(list) for phase in phases: for ability in await self.locate( 'abilities', match=dict(ability_id=phase['id'])): pp[phase['phase']].append(ability) phases = dict(pp) await self.store( Adversary(adversary_id=adv['id'], name=adv['name'], description=adv['description'], phases=phases)) total += 1 self.log.debug('Loaded %s adversaries' % total)
def setup_planning_test(loop, executor, ability, agent, operation, data_svc, event_svc, init_base_world): texecutor = executor(name='sh', platform='darwin', command='mkdir test', cleanup='rm -rf test') tability = ability(ability_id='123', executors=[texecutor], repeatable=True, buckets=['test'], name='test1') tagent = agent(sleep_min=1, sleep_max=2, watchdog=0, executors=['sh'], platform='darwin', server='http://127.0.0.1:8000') tsource = Source(id='123', name='test', facts=[], adjustments=[]) toperation = operation(name='test1', agents=[tagent], adversary=Adversary(name='test', description='test', atomic_ordering=[], adversary_id='XYZ'), source=tsource) cexecutor = executor(name='sh', platform='darwin', command=test_string, cleanup='whoami') cability = ability(ability_id='321', executors=[cexecutor], singleton=True, name='test2') loop.run_until_complete(data_svc.store(tability)) loop.run_until_complete(data_svc.store(cability)) loop.run_until_complete(data_svc.store( Obfuscator(name='plain-text', description='Does no obfuscation to any command, instead running it in plain text', module='plugins.stockpile.app.obfuscators.plain_text') )) yield tability, tagent, toperation, cability
def test_save_discover_seeded_fact_not_in_command(self, event_loop, ability, executor, operation, knowledge_svc): test_executor = executor(name='psh', platform='windows') test_ability = ability(ability_id='123', executors=[test_executor]) fact1 = Fact(trait='remote.host.fqdn', value='dc') fact2 = Fact(trait='domain.user.name', value='Bob') relationship = Relationship(source=fact1, edge='has_user', target=fact2) link = Link(command='net user', paw='123456', ability=test_ability, id='111111', executor=test_executor) operation = operation(name='test-op', agents=[], adversary=Adversary(name='sample', adversary_id='XYZ', atomic_ordering=[], description='test'), source=Source(id='test-source', facts=[fact1, fact2])) event_loop.run_until_complete(operation._init_source()) event_loop.run_until_complete( link.save_fact(operation, fact2, 1, relationship)) assert fact2.origin_type == OriginType.SEEDED assert '123456' in fact2.collected_by
async def _load_adversaries(self, plugin): for filename in glob.iglob('%s/adversaries/**/*.yml' % plugin.data_dir, recursive=True): for adv in self.strip_yml(filename): adversary = Adversary.load(adv) adversary.access = plugin.access await self.store(adversary)
async def _adjust_adversary_phases(self): if not self.phases_enabled: return Adversary(adversary_id=(self.adversary.adversary_id + "_phases_disabled"), name=(self.adversary.name + " - with phases disabled"), description=(self.adversary.name + " with phases disabled"), phases={1: [i for phase, ab in self.adversary.phases.items() for i in ab]}) else: return self.adversary
async def _construct_adversary_for_op(self, adversary_id): adv = await self.get_service('data_svc').locate( 'adversaries', match=dict(adversary_id=adversary_id)) if adv: return copy.deepcopy(adv[0]) return Adversary(adversary_id=0, name='ad-hoc', description='an empty adversary profile', phases={'1': []})
def test_no_duplicate_adversary(self, loop, data_svc): loop.run_until_complete( data_svc.store( Adversary(adversary_id='123', name='test', description='test adversary', phases=dict()))) loop.run_until_complete( data_svc.store( Adversary(adversary_id='123', name='test', description='test adversary', phases=dict()))) adversaries = loop.run_until_complete(data_svc.locate('adversaries')) assert len(adversaries) == 1 for x in adversaries: json.dumps(x.display)
def setup_rest_svc_test(loop, data_svc): BaseWorld.apply_config(name='main', config={ 'app.contact.http': '0.0.0.0', 'plugins': ['sandcat', 'stockpile'], 'crypt_salt': 'BLAH', 'api_key': 'ADMIN123', 'encryption_key': 'ADMIN123', 'exfil_dir': '/tmp' }) loop.run_until_complete( data_svc.store( Ability(ability_id='123', test=BaseWorld.encode_string('curl #{app.contact.http}'), variations=[], executor='psh', platform='windows'))) adversary = Adversary(adversary_id='123', name='test', description='test', atomic_ordering=[]) loop.run_until_complete(data_svc.store(adversary)) agent = Agent(paw='123', sleep_min=2, sleep_max=8, watchdog=0, executors=['pwsh', 'psh'], platform='windows') loop.run_until_complete(data_svc.store(agent)) loop.run_until_complete( data_svc.store( Planner(planner_id='123', name='test', module='test', params=dict()))) source = Source(id='123', name='test', facts=[], adjustments=[]) loop.run_until_complete(data_svc.store(source)) loop.run_until_complete( data_svc.store( Operation(name='test', agents=[agent], adversary=adversary, id='123', source=source))) loop.run_until_complete( data_svc.store( Obfuscator( name='plain-text', description= 'Does no obfuscation to any command, instead running it in plain text', module='plugins.stockpile.app.obfuscators.plain_text')))
def _generate_adversary(adversary_id=None, name=None, description=None, phases=None): if not adversary_id: adversary_id = uuid.uuid4() if not name: name = ''.join(random.choice(string.ascii_uppercase) for _ in range(10)) if not description: description = "description" if not phases: phases = dict() return Adversary(adversary_id=adversary_id, name=name, description=description, atomic_ordering=phases)
def test_no_duplicate_adversary(self, event_loop, data_svc): event_loop.run_until_complete( data_svc.store( Adversary(adversary_id='123', name='test', description='test adversary', atomic_ordering=list()))) event_loop.run_until_complete( data_svc.store( Adversary(adversary_id='123', name='test', description='test adversary', atomic_ordering=list()))) adversaries = event_loop.run_until_complete( data_svc.locate('adversaries')) assert len(adversaries) == 1 for x in adversaries: json.dumps(x.display)
async def _construct_adversary_for_op(self, adversary_id): adv = await self.get_service('data_svc').locate( 'adversaries', match=dict(adversary_id=adversary_id)) if adv: return copy.deepcopy(adv[0]) return Adversary.load( dict(adversary_id='ad-hoc', name='ad-hoc', description='an empty adversary profile', atomic_ordering=[]))
def test_operation(self): adversary = self.run_async(self.data_svc.store( Adversary(adversary_id='123', name='test', description='test adversary', phases=dict()) )) self.run_async(self.data_svc.store(Operation(name='my first op', agents=[], adversary=adversary))) operations = self.run_async(self.data_svc.locate('operations')) self.assertEqual(1, len(operations)) for x in operations: json.dumps(x.display)
async def _construct_and_dump_adversary(self, adversary_id: str): adv = await self.services['data_svc'].locate( 'adversaries', match=dict(adversary_id=adversary_id)) if not adv: adv = Adversary.load( dict(adversary_id='ad-hoc', name='ad-hoc', description='an empty adversary profile', atomic_ordering=[])) else: adv = adv[0] return AdversarySchema().dump(adv)
async def _adjust_adversary_phases(operation): """If an operation has phases disabled, replace operation adversary with new adversary whose phases are collapsed. Modified adversary is temporary and not stored, just used for the operation. """ if not operation.phases_enabled: return Adversary(adversary_id=(operation.adversary.adversary_id + "_phases_disabled"), name=(operation.adversary.name + " - with phases disabled"), description=(operation.adversary.name + " with phases disabled"), phases={1: [i for phase, ab in operation.adversary.phases.items() for i in ab]}) else: return operation.adversary
async def _load_adversaries(self, directory): for filename in glob.iglob('%s/*.yml' % directory, recursive=True): for adv in self.strip_yml(filename): phases = adv.get('phases', dict()) for p in adv.get('packs', []): adv_pack = await self._add_adversary_packs(p) if adv_pack: await self._merge_phases(phases, adv_pack) if adv.get('visible', True): sorted_phases = [phases[x] for x in sorted(phases.keys())] phases = await self._add_phases(sorted_phases, adv) await self.store( Adversary(adversary_id=adv['id'], name=adv['name'], description=adv['description'], phases=phases) )
def test_operation(self, loop, data_svc): adversary = loop.run_until_complete( data_svc.store( Adversary(adversary_id='123', name='test', description='test adversary', phases=dict()))) loop.run_until_complete( data_svc.store( Operation(name='my first op', agents=[], adversary=adversary))) operations = loop.run_until_complete(data_svc.locate('operations')) assert len(operations) == 1 for x in operations: json.dumps(x.display)
def setup_rest_svc_test(loop, data_svc): BaseWorld.apply_config(name='main', config={'app.contact.http': '0.0.0.0', 'plugins': ['sandcat', 'stockpile'], 'crypt_salt': 'BLAH', 'api_key': 'ADMIN123', 'encryption_key': 'ADMIN123', 'exfil_dir': '/tmp'}) loop.run_until_complete(data_svc.store( Ability(ability_id='123', name='testA', executors=[ Executor(name='psh', platform='windows', command='curl #{app.contact.http}') ]) )) loop.run_until_complete(data_svc.store( Ability(ability_id='456', name='testB', executors=[ Executor(name='sh', platform='linux', command='whoami') ]) )) loop.run_until_complete(data_svc.store( Ability(ability_id='789', name='testC', executors=[ Executor(name='sh', platform='linux', command='hostname') ]) )) adversary = Adversary(adversary_id='123', name='test', description='test', atomic_ordering=[]) loop.run_until_complete(data_svc.store(adversary)) agent = Agent(paw='123', sleep_min=2, sleep_max=8, watchdog=0, executors=['pwsh', 'psh'], platform='windows') loop.run_until_complete(data_svc.store(agent)) loop.run_until_complete(data_svc.store( Objective(id='495a9828-cab1-44dd-a0ca-66e58177d8cc', name='default', goals=[Goal()]) )) loop.run_until_complete(data_svc.store( Planner(planner_id='123', name='test', module='test', params=dict()) )) source = Source(id='123', name='test', facts=[], adjustments=[]) loop.run_until_complete(data_svc.store(source)) loop.run_until_complete(data_svc.store( Operation(name='test', agents=[agent], adversary=adversary, id='123', source=source) )) loop.run_until_complete(data_svc.store( Obfuscator(name='plain-text', description='Does no obfuscation to any command, instead running it in plain text', module='plugins.stockpile.app.obfuscators.plain_text') ))
async def _load_adversaries(self, directory): for filename in glob.iglob('%s/*.yml' % directory, recursive=True): for adv in self.strip_yml(filename): phases = [dict(phase=k, id=i) for k, v in adv.get('phases', dict()).items() for i in v] ps = [] for p in adv.get('packs', []): adv_pack = await self._add_adversary_packs(p) if adv_pack: ps.append(adv_pack) for pack in ps: phases += pack if adv.get('visible', True): phases = await self._add_phases(phases, adv) await self.store( Adversary(adversary_id=adv['id'], name=adv['name'], description=adv['description'], phases=phases) )
def setup_rest_svc_test(loop, data_svc): BaseWorld.apply_config(name='default', config={ 'app.contact.http': '0.0.0.0', 'plugins': ['sandcat', 'stockpile'], 'crypt_salt': 'BLAH', 'api_key': 'ADMIN123', 'exfil_dir': '/tmp' }) loop.run_until_complete( data_svc.store( Ability(ability_id='123', test=BaseWorld.encode_string('curl #{app.contact.http}'), variations=[]))) loop.run_until_complete( data_svc.store( Adversary(adversary_id='123', name='test', description='test', phases=[])))
def test_create_relationship_source_fact(self, event_loop, ability, executor, operation, knowledge_svc): test_executor = executor(name='psh', platform='windows') test_ability = ability(ability_id='123', executors=[test_executor]) fact1 = Fact(trait='remote.host.fqdn', value='dc') fact2 = Fact(trait='domain.user.name', value='Bob') relationship = Relationship(source=fact1, edge='has_admin', target=fact2) link1 = Link(command='echo "Bob"', paw='123456', ability=test_ability, id='111111', executor=test_executor) operation = operation(name='test-op', agents=[], adversary=Adversary(name='sample', adversary_id='XYZ', atomic_ordering=[], description='test'), source=Source(id='test-source', facts=[fact1])) event_loop.run_until_complete(operation._init_source()) event_loop.run_until_complete( link1.create_relationships([relationship], operation)) link2 = Link(command='echo "Bob"', paw='789100', ability=test_ability, id='222222', executor=test_executor) event_loop.run_until_complete( link2.create_relationships([relationship], operation)) fact_store_operation_source = event_loop.run_until_complete( knowledge_svc.get_facts(dict(source=operation.source.id))) fact_store_operation = event_loop.run_until_complete( knowledge_svc.get_facts(dict(source=operation.id))) assert len(fact_store_operation_source) == 1 assert len(fact_store_operation) == 1 assert len(fact_store_operation_source[0].collected_by) == 2
async def setup_learning_service(data_svc, ability, operation, link): texecutor = Executor(name='sh', platform='darwin', command='whoami', payloads=['wifi.sh']) tability = ability(tactic='discovery', technique_id='T1033', technique_name='Find', name='test', description='find active user', privilege=None, executors=[texecutor]) await data_svc.store(tability) toperation = operation(name='sample', agents=None, adversary=Adversary(name='sample', adversary_id='XYZ', atomic_ordering=[], description='test')) await data_svc.store(toperation) tlink1 = link(ability=tability, command='', paw='1234', executor=texecutor) tlink2 = link(ability=tability, command='', paw='5678', executor=texecutor) yield toperation, tlink1, tlink2