def rel_fs_store(): cam = Campaign(id=CAMPAIGN_ID, **CAMPAIGN_KWARGS) idy = Identity(id=IDENTITY_ID, **IDENTITY_KWARGS) ind = Indicator(id=INDICATOR_ID, **INDICATOR_KWARGS) mal = Malware(id=MALWARE_ID, **MALWARE_KWARGS) rel1 = Relationship(ind, 'indicates', mal, id=RELATIONSHIP_IDS[0]) rel2 = Relationship(mal, 'targets', idy, id=RELATIONSHIP_IDS[1]) rel3 = Relationship(cam, 'uses', mal, id=RELATIONSHIP_IDS[2]) stix_objs = [cam, idy, ind, mal, rel1, rel2, rel3] fs = FileSystemStore(FS_PATH) for o in stix_objs: fs.add(o) yield fs for o in stix_objs: filepath = os.path.join(FS_PATH, o.type, o.id, _timestamp2filename(o.modified) + '.json') # Some test-scoped fixtures (e.g. fs_store) delete all campaigns, so by # the time this module-scoped fixture tears itself down, it may find # its campaigns already gone, which causes not-found errors. try: os.remove(filepath) except OSError as e: # 3 is the ERROR_PATH_NOT_FOUND windows error code. Which has an # errno symbolic value, but not the windows meaning... if e.errno in (errno.ENOENT, 3): continue raise
def get_technique_by_name(self, name): dir_path = os.path.dirname(os.path.realpath(__file__)) from stix2 import FileSystemStore fs = FileSystemStore(dir_path + "/../enterprise-attack") filt = [ Filter('type', '=', 'attack-pattern'), Filter('name', '=', name) ] return fs.query(filt)
def rel_fs_store(): cam = Campaign(id=CAMPAIGN_ID, **CAMPAIGN_KWARGS) idy = Identity(id=IDENTITY_ID, **IDENTITY_KWARGS) ind = Indicator(id=INDICATOR_ID, **INDICATOR_KWARGS) mal = Malware(id=MALWARE_ID, **MALWARE_KWARGS) rel1 = Relationship(ind, 'indicates', mal, id=RELATIONSHIP_IDS[0]) rel2 = Relationship(mal, 'targets', idy, id=RELATIONSHIP_IDS[1]) rel3 = Relationship(cam, 'uses', mal, id=RELATIONSHIP_IDS[2]) stix_objs = [cam, idy, ind, mal, rel1, rel2, rel3] fs = FileSystemStore(FS_PATH) for o in stix_objs: fs.add(o) yield fs for o in stix_objs: os.remove(os.path.join(FS_PATH, o.type, o.id + '.json'))
def test_filesystem_store_add_as_bundle(): fs_store = FileSystemStore(FS_PATH, bundlify=True) camp1 = Campaign(name="Great Heathen Army", objective="Targeting the government of United Kingdom and insitutions affiliated with the Church Of England", aliases=["Ragnar"]) fs_store.add(camp1) with open(os.path.join(FS_PATH, "campaign", camp1.id + ".json")) as bundle_file: assert '"type": "bundle"' in bundle_file.read() camp1_r = fs_store.get(camp1.id) assert camp1_r.id == camp1.id assert camp1_r.name == camp1.name shutil.rmtree(os.path.join(FS_PATH, "campaign"), True)
def fs_store(): # create yield FileSystemStore(FS_PATH) # remove campaign dir shutil.rmtree(os.path.join(FS_PATH, "campaign"), True)
def main(args, config): """ Wrapper to run all components of CDAS Calls context, agents, and asset builders to create simulation componenets. Passes resulting components to simulation module. Manages output. Parameters ---------- args : list The arguments passed in from argparse or read from the configuration file in the arguments method config : dict The configuration file opened and loaded from json """ # Set up the Output directory if os.path.isdir(args.output): q = (f"Overwrite the output folder {os.getcwd() + '/' + args.output}? " f"(y/n) ") else: q = f"Output path {os.getcwd() + '/' + args.output} does not exist.\n\ Create this directory? (y/n) " if not args.overwrite_output: answer = "" while answer not in ['y', 'n']: answer = input(q) else: answer = 'y' if answer == 'n': sys.exit(f"CDAS exited without completing") else: if os.path.isdir(args.output): for filename in os.listdir(args.output): file_path = os.path.join(args.output, filename) try: if os.path.isfile(file_path) or os.path.islink(file_path): os.unlink(file_path) elif os.path.isdir(file_path): shutil.rmtree(file_path) except Exception as e: print('Failed to delete %s. %s' % (file_path, e)) else: os.mkdir(args.output) # Set up the STIX data stores # Check if it's okay to overwrite the contents of the temporary data store temp_path = pkg_resources.resource_filename(__name__, config['temp_path']) if os.path.isdir(temp_path): q = f"Overwrite temporary stix data folder ({temp_path})? (y/n) " overwrite = input(q) if overwrite == 'n': print(f"Rename the 'temp path' variable in config file and \ restart the simulation.") sys.exit() elif overwrite == 'y': shutil.rmtree(temp_path) os.mkdir(temp_path) else: overwrite = input(q) else: os.mkdir(temp_path) fs_gen = FileSystemStore(temp_path) fs_real = FileSystemSource( pkg_resources.resource_filename(__name__, "assets/mitre_cti/")) # Load or create country data countries = [] if args.randomize_geopol is True: print("Creating countries...") with open(args.random_geodata, encoding='utf-8') as f: context_options = json.load(f) # seed file f.close() map_matrix = context.Map(args.num_countries) for c in range(0, args.num_countries): countries.append( context.Country(fs_gen, context_options, map_matrix.map)) for c in countries: # This loop is used mainly to convert references to other countries # to the names of those countries instead of their ID numbers, # since, during the generation of each country it only has access # to map_matrix with ID numbers of the other countries # Convert the neighbors listed by id# to neighbor country names neighbors = {} for n in c.neighbors: n_name = next((x.name for x in countries if x.id == n), None) neighbors[n_name] = c.neighbors[n] c.neighbors = neighbors if len(c.neighbors) == 0: c.neighbors = "None (island nation)" # if country is a terrority, find its owner if c.government_type == "non-self-governing territory": gdps = [(int(gdp.gdp[1:].replace(',', '')), gdp.name) for gdp in countries] gdps.sort() # Territory owners are most likely to be high GDP countries # pick a random one from the top three GDP owner_name = np.random.choice([gdp[1] for gdp in gdps][-3:]) if c.name in [gdp[1] for gdp in gdps][-3:]: # if the territory itself is in the top three GDP, change # its gov type to a republic instead of a territory c.government_type = "federal parliamentary republic" else: c.government_type += f" of {str(owner_name)}" # update ethnic groups to include owner instead of random owner = next( (x.id for x in countries if x.name == owner_name), None) if str(owner) not in c.ethnic_groups: egs = {} for eg in c.ethnic_groups: try: int(eg) if str(owner) not in egs: egs[str(owner)] = c.ethnic_groups[eg] else: egs[eg] = c.ethnic_groups[eg] except ValueError: egs[eg] = c.ethnic_groups[eg] c.ethnic_groups = egs # update forces to include owner name if necessary msf = c.military_and_security_forces c.military_and_security_forces = msf.replace( "[COUNTRY]", owner_name) # update languages to include owner instead of random if str(owner) not in c.languages: langs = {} for eg in c.languages: try: int(eg) if str(owner) not in langs: langs[str(owner)] = c.languages[eg] else: langs[eg] = c.languages[eg] except ValueError: langs[eg] = c.languages[eg] c.languages = langs # Apply nationalities to ethnic groups listed by id# egs = {} for eg in c.ethnic_groups: try: egs[next( (x.nationality for x in countries if x.id == int(eg)), None)] = c.ethnic_groups[eg] except ValueError: egs[eg] = c.ethnic_groups[eg] c.ethnic_groups = egs # Convert languges listed by id# to country names egs = {} for eg in c.languages: try: eg_name = next( (x.name for x in countries if x.id == int(eg)), None) if eg_name.endswith(('a', 'e', 'i', 'o', 'u')): eg_name += "nese" else: eg_name += 'ish' egs[eg_name] = c.languages[eg] except ValueError: egs[eg] = c.languages[eg] c.languages = egs else: # Using country data files instead of random generation print("Loading countries...") for fn in os.listdir(args.country_data): with open(args.country_data + fn, 'r') as f: country_data = json.load(f) f.close() countries.append(context.Country(fs_gen, **country_data)) # Load or create actor data print("Creating threat actors...") with open(pkg_resources.resource_filename(__name__, "assets/stix_vocab.json"), encoding='utf-8') as json_file: stix_vocab = json.load(json_file) json_file.close() if config['agents']['randomize_threat_actors'] is True: apt_store = fs_gen with open(pkg_resources.resource_filename( __name__, config['agents']['random_variables']['actor_name_1']), encoding='utf-8') as f: adjectives = [line.rstrip() for line in f] f.close() with open(pkg_resources.resource_filename( __name__, config['agents']['random_variables']['actor_name_2']), encoding='utf-8') as f: nouns = [line.rstrip() for line in f] f.close() actors = 1 while actors <= config['agents']['random_variables']['num_agents']: agents.create_threatactor(stix_vocab, nouns, adjectives, countries, apt_store) actors += 1 else: # no randomization - use provided data set if config['agents']['non_random_vars']['apt_data'] == "mitre_cti": apt_store = fs_real else: apt_store = FileSystemStore( config['agents']['non_random_vars']['apt_data']) # Create organizations print('Creating organizations...') with open( pkg_resources.resource_filename( __name__, config['agents']['org_variables']['org_names'])) as f: org_names = f.read().splitlines() # organization name possibilities f.close() with open(pkg_resources.resource_filename(__name__, 'assets/NIST_assess.json'), encoding='utf-8') as json_file: assessment = json.load(json_file) json_file.close() for c in countries: orgs = 0 while orgs < config['agents']['org_variables']["orgs_per_country"]: agents.create_organization(stix_vocab, fs_gen, c, org_names, assessment) orgs += 1 # Run simulation print('Running simulation...') start = datetime.strptime(config["simulation"]['time_range'][0], '%Y-%m-%d') end = datetime.strptime(config["simulation"]['time_range'][1], '%Y-%m-%d') td = end - start actors = apt_store.query(Filter("type", "=", "intrusion-set")) orgs = fs_gen.query([ Filter("type", "=", "identity"), Filter("identity_class", "=", "organization") ]) tools = fs_real.query(Filter('type', '=', 'tool')) malwares = fs_real.query(Filter('type', '=', 'malware')) for r in range(1, int(config["simulation"]['number_of_rounds']) + 1): print(f'\tRound {r}') simulator.simulate( actors, orgs, tools, malwares, fs_gen, start, td.days / (config["simulation"]['number_of_rounds'] * len(actors))) start += timedelta(days=td.days / config["simulation"]['number_of_rounds']) # Create output files print('Saving output...') # Map country_names = {} for country in countries: country_names[str(country.id)] = country.name try: map_matrix.plot_map(args.output, **country_names) except NameError: pass for ot in args.output_types: print(f'\t{ot}') path = args.output + "/" + ot if ot == "stix": shutil.copytree(temp_path, path) else: os.mkdir(path) os.mkdir(path + '/countries/') os.mkdir(path + '/actors/') os.mkdir(path + '/reports/') os.mkdir(path + '/organizations/') for country in countries: country.save(path + '/countries/', ot) apts = apt_store.query(Filter("type", "=", "intrusion-set")) for apt in apts: agents.save(apt, path + '/actors/', ot, fs_gen, fs_real) events = fs_gen.query(Filter("type", "=", "sighting")) for e in events: simulator.save(e, apt_store, fs_real, path + '/reports/', ot) for org in orgs: agents.save_org(org, path + '/organizations/', ot, assessment) if ot == "html": html_src = pkg_resources.resource_filename( __name__, 'assets/html_templates') html_templates = os.listdir(html_src) for f in html_templates: shutil.copy(html_src + '/' + f, path) f = open(path + '/COUNTRY.html', 'r') c_template = f.read() f.close() for country in countries: f = open(path + '/countries/' + country.name + '.html', 'w') f.write(c_template.replace('COUNTRY', country.name)) f.close() os.remove(path + '/COUNTRY.html') shutil.rmtree(temp_path) print('Done')