def test_handle_artefacts(artefact_list, expected_result, dummy_request_class): from assemblyline_v4_service.common.dynamic_service_helper import SandboxOntology r = dummy_request_class() o = SandboxOntology() actual_result = o.handle_artefacts(artefact_list, r) assert actual_result == expected_result
def _process_extraction_info(self, processes: List[Dict[str, Any]], process_path_set: Set[str], command_line_set: Set[str], so: SandboxOntology) -> None: """ This method handles the processing of the extraction info process details :param processes: A list of processes :param process_path_set: A set containing process paths :param command_line_set: A set containing command lines :param so: the sandbox ontology object :return: None """ for item in processes: p = so.create_process( pid=item["process_id"], image=item["process_path"], ppid=item["parent_process_id"], ) process_path_set.add(item["process_path"]) so.add_process(p) if item["process_path"] != item["module_path"]: self.log.debug( f"Investigate! process_path: {item['process_path']} != module_path: {item['module_path']}" ) process_path_set.add(item["module_path"]) command_line = f"{item['process_path']} {item['module_path']}" command_line_set.add(command_line) so.update_process(command_line=command_line, pid=item["process_id"], start_time=float("-inf"))
def test_handle_artefact(artefact, expected_result_section_title): from assemblyline_v4_service.common.dynamic_service_helper import SandboxOntology, Artefact from assemblyline_v4_service.common.result import ResultSection if artefact is None: with pytest.raises(Exception): SandboxOntology._handle_artefact(artefact, None) return expected_result_section = None if expected_result_section_title is not None: expected_result_section = ResultSection( expected_result_section_title) expected_result_section.add_tag("dynamic.process.file_name", artefact["path"]) parent_result_section = ResultSection("blah") a = Artefact(name=artefact["name"], path=artefact["path"], description=artefact["description"], to_be_extracted=artefact["to_be_extracted"]) SandboxOntology._handle_artefact(a, parent_result_section) if len(parent_result_section.subsections) > 0: actual_result_section = parent_result_section.subsections[0] else: actual_result_section = None if expected_result_section is None and actual_result_section is None: assert True else: assert check_section_equality(actual_result_section, expected_result_section)
def test_get_process_tree_with_signatures(process_list, signatures, expected_result): from assemblyline_v4_service.common.dynamic_service_helper import SandboxOntology o = SandboxOntology(process_list) if process_list and signatures and process_list[0][ "pid"] != signatures[0]["pid"]: with pytest.raises(Exception): o.get_process_tree_with_signatures(signatures=signatures) else: actual_result = o.get_process_tree_with_signatures( signatures=signatures) assert actual_result == expected_result
def test_validate_artefacts(artefact_list): from assemblyline_v4_service.common.dynamic_service_helper import SandboxOntology, Artefact actual_validated_artefact_list = SandboxOntology._validate_artefacts( artefact_list) if artefact_list is None: artefact_list = [] for index, artefact in enumerate(artefact_list): expected_artefact = Artefact( name=artefact["name"], path=artefact["path"], description=artefact["description"], to_be_extracted=artefact["to_be_extracted"]) assert check_artefact_equality( expected_artefact, actual_validated_artefact_list[index])
def _handle_subanalyses(self, request: ServiceRequest, sha256: str, analysis_id: str, file_verdict_map: Dict[str, str], parent_section: ResultSection) -> None: """ This method handles the subanalyses for a given analysis ID :param request: The service request object :param sha256: The hash of the given file :param analysis_id: The ID for the analysis which we will be retrieving :param file_verdict_map: A map of sha256s representing a file's contents, and the verdict for that file :param parent_result_section: The result section that the network result section will be added to, if applicable :return: None """ so = SandboxOntology() # This boolean is used to determine if we should try to download another file can_we_download_files = True # These sets will be used as we work through the process trees process_path_set = set() command_line_set = set() # Now let's get into the subanalyses for this sample sub_analyses = self.client.get_sub_analyses_by_id(analysis_id) for sub in sub_analyses: sub_analysis_id = sub["sub_analysis_id"] # Get the extraction info, which is basically the details of how the subanalysis object came to be extraction_info = sub.pop("extraction_info", None) # Processes is only present when the sample has undergone dynamic execution if extraction_info and "processes" not in extraction_info: extraction_info = None code_reuse = self.client.get_sub_analysis_code_reuse_by_id( analysis_id, sub_analysis_id) if code_reuse: families = code_reuse.pop("families", []) else: families = [] if not families and not extraction_info: # Otherwise, boring! continue if families and not any(family["reused_gene_count"] > 1 for family in families): # Most likely a false positive continue ### # If we have gotten to this point, then the sub analysis is worth reporting ### extraction_method = sub["source"].replace("_", " ") if extraction_method != "root": sub_kv_section = ResultKeyValueSection( f"Subanalysis report for {sub['sha256']}, extracted via {extraction_method}" ) else: sub_kv_section = ResultKeyValueSection( f"Subanalysis report for {sub['sha256']}") metadata = self.client.get_sub_analysis_metadata_by_id( analysis_id, sub_analysis_id) processed_subanalysis = self._process_details( metadata.copy(), UNINTERESTING_SUBANALYSIS_KEYS) sub_kv_section.update_items(processed_subanalysis) parent_section.add_subsection(sub_kv_section) if code_reuse: code_reuse_kv_section = ResultKeyValueSection( "Code reuse detected") code_reuse_kv_section.update_items(code_reuse) sub_kv_section.add_subsection(code_reuse_kv_section) sub_sha256 = sub["sha256"] if families: self._process_families(families, sub_sha256, file_verdict_map, sub_kv_section) if extraction_info: self._process_extraction_info(extraction_info["processes"], process_path_set, command_line_set, so) # Setting a heuristic here or downloading the file would be redundant if the hash matched the original file if sub_sha256 != sha256: self._set_heuristic_by_verdict( sub_kv_section, file_verdict_map.get(sub_sha256)) if can_we_download_files: file_was_downloaded = self.client.download_file_by_sha256( sub_sha256, self.working_directory) if file_was_downloaded: path = f"{self.working_directory}/{sub_sha256}.sample" request.add_extracted( path, f"{sub_sha256}.sample", f"Extracted via {extraction_method}", ) self.log.debug( f"Added {sub_sha256}.sample as an extracted file.") else: can_we_download_files = False process_tree_section = so.get_process_tree_result_section() for process_path in process_path_set: process_tree_section.add_tag("dynamic.process.file_name", process_path) for command_line in command_line_set: process_tree_section.add_tag("dynamic.process.command_line", command_line) if process_tree_section.body: parent_section.add_subsection(process_tree_section)
def test_get_process_tree(process_list, expected_result): from assemblyline_v4_service.common.dynamic_service_helper import SandboxOntology o = SandboxOntology(process_list) actual_result = o.get_process_tree() assert actual_result == expected_result
def test_convert_processes_dict_to_tree(processes_dict, expected_result): from assemblyline_v4_service.common.dynamic_service_helper import SandboxOntology actual_result = SandboxOntology._convert_processes_dict_to_tree( processes_dict) assert expected_result == actual_result
def test_init(events, expected_events): from assemblyline_v4_service.common.dynamic_service_helper import SandboxOntology so = SandboxOntology(events=events) assert so.events == expected_events
def test_get_events(events, expected_result): from assemblyline_v4_service.common.dynamic_service_helper import SandboxOntology so = SandboxOntology(events=events) actual_result = so.get_events() assert actual_result == expected_result
def test_process_extraction_info(intezer_static_class_instance): from assemblyline_v4_service.common.dynamic_service_helper import SandboxOntology so = SandboxOntology() processes = [ { "process_id": 123, "process_path": "blah.exe", "parent_process_id": 321, "module_path": "blah.exe" }, { "process_id": 124, "process_path": "blah2.exe", "parent_process_id": 321, "module_path": "blah2.dll,blah" }, { "process_id": 123, "process_path": "blah.exe", "parent_process_id": 321, "module_path": "blah.dll,blah" }, { "process_id": 321, "process_path": "blah3.exe", "parent_process_id": 322, "module_path": "blah3.exe" }, ] process_path_set = set() command_line_set = set() correct_processes = [ { "start_time": float("-inf"), "end_time": float("inf"), "objectid": { "tag": "blah.exe", "treeid": None, "processtree": None, "time_observed": float("-inf") }, "pobjectid": { "tag": "blah3.exe", "treeid": None, "processtree": None, "time_observed": float("-inf") }, "pimage": "blah3.exe", "pcommand_line": None, "ppid": 321, "pid": 123, "image": "blah.exe", "command_line": "blah.exe blah.dll,blah", "integrity_level": None, "image_hash": None, "original_file_name": None, }, { "start_time": float("-inf"), "end_time": float("inf"), "objectid": { "tag": "blah2.exe", "treeid": None, "processtree": None, "time_observed": float("-inf") }, "pobjectid": { "tag": "blah3.exe", "treeid": None, "processtree": None, "time_observed": float("-inf") }, "pimage": "blah3.exe", "pcommand_line": None, "ppid": 321, "pid": 124, "image": "blah2.exe", "command_line": "blah2.exe blah2.dll,blah", "integrity_level": None, "image_hash": None, "original_file_name": None, }, { "start_time": float("-inf"), "end_time": float("inf"), "objectid": { "tag": "blah3.exe", "treeid": None, "processtree": None, "time_observed": float("-inf") }, "pobjectid": { "tag": None, "treeid": None, "processtree": None, "time_observed": None }, "pimage": None, "pcommand_line": None, "ppid": 322, "pid": 321, "image": "blah3.exe", "command_line": None, "integrity_level": None, "image_hash": None, "original_file_name": None, }, ] intezer_static_class_instance._process_extraction_info( processes, process_path_set, command_line_set, so) for index, process in enumerate(so.get_processes()): process_as_primitives = process.as_primitives() process_as_primitives["objectid"].pop("guid") process_as_primitives["pobjectid"].pop("guid") assert process_as_primitives == correct_processes[index] assert process_path_set == { "blah.dll,blah", "blah2.dll,blah", "blah2.exe", "blah.exe", "blah3.exe" } assert command_line_set == { "blah.exe blah.dll,blah", "blah2.exe blah2.dll,blah" }