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 _create_analytic_ability(self, name, query): reference_ability = (await self.data_svc.locate( 'abilities', match=dict(ability_id='bf565e6a-0037-4aa4-852f-1afa222c76db')) )[0] #TODO: replace ability_id = str(uuid.uuid4()) executors = [] for pl in ['windows', 'darwin', 'linux']: reference_executor = reference_ability.find_executor( 'elasticsearch', pl) if not reference_executor: continue parsers = deepcopy(reference_executor.parsers) executors.append( Executor(platform=pl, name='elasticsearch', command=query, parsers=parsers, timeout=60)) ability = Ability(ability_id=ability_id, name=name, description='custom analytic', tactic='analytic', technique_name='analytic', technique_id='x', buckets=['analytic'], access=self.Access.BLUE, executors=executors) await self.data_svc.store(ability) return [dict(ability_id=ability.ability_id)]
def test_no_duplicate_ability(self, loop, data_svc): executor = Executor(name='special_executor', platform='darwin', command='whoami', payloads=['wifi.sh']) loop.run_until_complete( data_svc.store( Ability(ability_id='123', tactic='discovery', technique_id='1', technique_name='T1033', name='test', description='find active user', privilege=None, executors=[executor]))) loop.run_until_complete( data_svc.store( Ability(ability_id='123', tactic='discovery', technique_id='1', technique_name='T1033', name='test', description='find active user', privilege=None, executors=[executor]))) abilities = loop.run_until_complete(data_svc.locate('abilities')) assert len(abilities) == 1
def setup_contact_service(loop, data_svc, agent, ability, operation, link, adversary): texecutor = Executor(name='special_executor', 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]) tability.HOOKS['special_executor'] = TestProcessor() loop.run_until_complete(data_svc.store(tability)) tagent = agent(sleep_min=10, sleep_max=60, watchdog=0, executors=['special_executor']) loop.run_until_complete(data_svc.store(tagent)) toperation = operation(name='sample', agents=[tagent], adversary=adversary()) tlink = link(command='', paw=tagent.paw, ability=tability, id='5212fca4-6544-49ce-a78d-a95d30e95705', executor=texecutor) loop.run_until_complete(toperation.apply(tlink)) loop.run_until_complete(data_svc.store(toperation)) yield tlink
async def add_manual_command(self, access, data): for parameter in ['operation', 'agent', 'executor', 'command']: if parameter not in data.keys(): return dict(error='Missing parameter: %s' % parameter) operation_search = {'id': data['operation'], **access} operation = next(iter(await self.get_service('data_svc').locate('operations', match=operation_search)), None) if not operation: return dict(error='Operation not found') agent_search = {'paw': data['agent'], **access} agent = next(iter(await self.get_service('data_svc').locate('agents', match=agent_search)), None) if not agent: return dict(error='Agent not found') if data['executor'] not in agent.executors: return dict(error='Agent missing specified executor') encoded_command = self.encode_string(data['command']) ability_id = str(uuid.uuid4()) executor = Executor(name=data['executor'], platform=agent.platform, command=data['command']) ability = Ability(ability_id=ability_id, tactic='auto-generated', technique_id='auto-generated', technique_name='auto-generated', name='Manual Command', description='Manual command ability', executors=[executor]) link = Link.load(dict(command=encoded_command, paw=agent.paw, cleanup=0, ability=ability, score=0, jitter=2, executor=executor, status=operation.link_status())) link.apply_id(agent.host) operation.add_link(link) return dict(link=link.unique)
async def load_executors_from_platform_dict(self, platforms): executors = [] for platform_names, platform_executors in platforms.items(): for executor_names, executor in platform_executors.items(): command = executor['command'].strip() if executor.get('command') else None cleanup = executor['cleanup'].strip() if executor.get('cleanup') else None code = executor['code'].strip() if executor.get('code') else None if code: _, code_path = await self.get_service('file_svc').find_file_path(code) if code_path: _, code_data = await self.get_service('file_svc').read_file(code) code = code_data.decode('utf-8').strip() language = executor.get('language') build_target = executor.get('build_target') payloads = executor.get('payloads') uploads = executor.get('uploads') timeout = executor.get('timeout', 60) variations = executor.get('variations', []) parsers = await self._load_executor_parsers(executor.get('parsers', [])) for platform_name in platform_names.split(','): for executor_name in executor_names.split(','): executors.append(Executor(name=executor_name, platform=platform_name, command=command, code=code, language=language, build_target=build_target, payloads=payloads, uploads=uploads, timeout=timeout, parsers=parsers, cleanup=cleanup, variations=variations)) return executors
def test_builtin_fact_replacement_with_upstream_dest( self, loop, obfuscator, init_base_world): executor = Executor( name='psh', platform='windows', command= 'echo #{paw} #{server} #{group} #{location} #{exe_name} #{upstream_dest}' ) ability = Ability(ability_id='123', executors=[executor]) agent = Agent(paw='123', sleep_min=2, sleep_max=8, watchdog=0, executors=['pwsh', 'psh'], platform='windows', group='my_group', server='http://10.10.10.10:8888', location='testlocation', exe_name='testexe', upstream_dest='http://127.0.0.1:12345') loop.run_until_complete(agent.task([ability], 'plain-text', [])) assert 1 == len(agent.links) link = agent.links[0] decoded_command = b64decode(link.command).decode('utf-8') want = 'echo 123 http://10.10.10.10:8888 my_group testlocation testexe http://127.0.0.1:12345' assert want == decoded_command
def test_task_with_facts(self, event_loop, obfuscator, init_base_world, knowledge_svc): executor = Executor(name='psh', platform='windows', command='net user #{domain.user.name} /domain') ability = Ability(ability_id='123', executors=[executor]) agent = Agent(paw='123', sleep_min=2, sleep_max=8, watchdog=0, executors=['pwsh', 'psh'], platform='windows') fact = Fact(trait='domain.user.name', value='bob') event_loop.run_until_complete(agent.task([ability], 'plain-text', [fact])) assert 1 == len(agent.links)
def test_task_no_facts(self, loop, data_svc, obfuscator, init_base_world): executor = Executor(name='psh', platform='windows', command='whoami') ability = Ability(ability_id='123', executors=[executor]) agent = Agent(paw='123', sleep_min=2, sleep_max=8, watchdog=0, executors=['pwsh', 'psh'], platform='windows') loop.run_until_complete(agent.task([ability], obfuscator='plain-text')) assert 1 == len(agent.links)
def test_task_missing_fact(self, loop, obfuscator, init_base_world): executor = Executor(name='psh', platform='windows', command='net user #{domain.user.name} /domain') ability = Ability(ability_id='123', executors=[executor]) agent = Agent(paw='123', sleep_min=2, sleep_max=8, watchdog=0, executors=['pwsh', 'psh'], platform='windows') loop.run_until_complete(agent.task([ability], obfuscator='plain-text')) assert 0 == len(agent.links)
def test_no_autogen_cleanup_cmds(self, event_loop, data_svc): cleanup_executor = Executor(name='sh', platform='linux', cleanup='rm #{payload}') event_loop.run_until_complete( data_svc.store( Ability( ability_id='4cd4eb44-29a7-4259-91ae-e457b283a880', tactic='defense-evasion', technique_id='T1070.004', technique_name='Indicator Removal on Host: File Deletion', name='Delete payload', description='Remove a downloaded payload file', privilege=None, executors=[cleanup_executor]))) executor = Executor(name='special_executor', platform='darwin', command='whoami', payloads=['wifi.sh']) event_loop.run_until_complete( data_svc.store( Ability(ability_id='123', tactic='discovery', technique_id='1', technique_name='T1033', name='test', description='find active user', privilege=None, executors=[executor]))) event_loop.run_until_complete(data_svc._verify_abilities()) abilities = event_loop.run_until_complete( data_svc.locate('abilities', dict(ability_id='123'))) for ability in abilities: for executor in ability.executors: assert not executor.cleanup
def replaced_ability_payload(test_ability): ability_data = test_ability.schema.dump(test_ability) test_executor_linux = Executor(name='sh', platform='linux', command='whoami') test_requirement = Requirement( module='plugins.stockpile.app.requirements.paw_provenance', relationship_match=[{ 'source': 'host.user.name' }]) ability_data.update( dict(name='replaced test ability', tactic='collection', technique_name='discovery', technique_id='2', executors=[ExecutorSchema().dump(test_executor_linux)], plugin='', requirements=[RequirementSchema().dump(test_requirement)])) return ability_data
def new_ability_payload(): test_executor_linux = Executor(name='sh', platform='linux', command='whoami') return { 'name': 'new test ability', 'ability_id': '456', 'tactic': 'collection', 'technique_name': 'collection', 'technique_id': '1', 'executors': [ExecutorSchema().dump(test_executor_linux)], 'access': {}, 'additional_info': {}, 'buckets': ['collection'], 'description': '', 'privilege': '', 'repeatable': False, 'requirements': [], 'singleton': False, 'plugin': '' }
def setup_learning_service(loop, 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]) 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='', executor=texecutor) yield toperation, tlink
def _generate_executor(name='psh', platform='windows', *args, **kwargs): return Executor(name, platform, *args, **kwargs)