def _generator(self, tasks): vmlinux = self.context.modules[self.config["kernel"]] is_32bit = not symbols.symbol_table_is_64bit(self.context, vmlinux.symbol_table_name) if is_32bit: pack_format = "I" bash_json_file = "bash32" else: pack_format = "Q" bash_json_file = "bash64" bash_table_name = BashIntermedSymbols.create(self.context, self.config_path, "linux", bash_json_file) ts_offset = self.context.symbol_space.get_type( bash_table_name + constants.BANG + "hist_entry").relative_child_offset("timestamp") for task in tasks: task_name = utility.array_to_string(task.comm) if task_name not in ["bash", "sh", "dash"]: continue proc_layer_name = task.add_process_layer() if not proc_layer_name: continue proc_layer = self.context.layers[proc_layer_name] bang_addrs = [] # find '#' values on the heap for address in proc_layer.scan( self.context, scanners.BytesScanner(b"#"), sections=task.get_process_memory_sections(heap_only=True)): bang_addrs.append(struct.pack(pack_format, address)) history_entries = [] if bang_addrs: for address, _ in proc_layer.scan( self.context, scanners.MultiStringScanner(bang_addrs), sections=task.get_process_memory_sections( heap_only=True)): hist = self.context.object(bash_table_name + constants.BANG + "hist_entry", offset=address - ts_offset, layer_name=proc_layer_name) if hist.is_valid(): history_entries.append(hist) for hist in sorted(history_entries, key=lambda x: x.get_time_as_integer()): yield (0, (task.pid, task_name, hist.get_time_object(), hist.get_command()))
def __init__(self, module: interfaces.context.ModuleInterface, constraint_lookup: Dict[bytes, PoolConstraint], alignment: int): super().__init__() self._module = module self._constraint_lookup = constraint_lookup self._alignment = alignment header_type = self._module.get_type('_POOL_HEADER') self._header_offset = header_type.relative_child_offset('PoolTag') self._subscanner = scanners.MultiStringScanner([c for c in constraint_lookup.keys()])
def stack(cls, context: interfaces.context.ContextInterface, layer_name: str, progress_callback: constants.ProgressCallback = None) -> Optional[interfaces.layers.DataLayerInterface]: """Attempts to identify linux within this layer.""" # Bail out by default unless we can stack properly layer = context.layers[layer_name] join = interfaces.configuration.path_join # Never stack on top of an intel layer # FIXME: Find a way to improve this check if isinstance(layer, intel.Intel): return None linux_banners = LinuxBannerCache.load_banners() # If we have no banners, don't bother scanning if not linux_banners: vollog.info("No Linux banners found - if this is a linux plugin, please check your symbol files location") return None mss = scanners.MultiStringScanner([x for x in linux_banners if x is not None]) for _, banner in layer.scan(context = context, scanner = mss, progress_callback = progress_callback): dtb = None vollog.debug("Identified banner: {}".format(repr(banner))) symbol_files = linux_banners.get(banner, None) if symbol_files: isf_path = symbol_files[0] table_name = context.symbol_space.free_table_name('LintelStacker') table = linux.LinuxKernelIntermedSymbols(context, 'temporary.' + table_name, name = table_name, isf_url = isf_path) context.symbol_space.append(table) kaslr_shift, aslr_shift = cls.find_aslr(context, table_name, layer_name, progress_callback = progress_callback) layer_class = intel.Intel # type: Type if 'init_top_pgt' in table.symbols: layer_class = intel.Intel32e dtb_symbol_name = 'init_top_pgt' elif 'init_level4_pgt' in table.symbols: layer_class = intel.Intel32e dtb_symbol_name = 'init_level4_pgt' else: dtb_symbol_name = 'swapper_pg_dir' dtb = cls.virtual_to_physical_address(table.get_symbol(dtb_symbol_name).address + kaslr_shift) # Build the new layer new_layer_name = context.layers.free_layer_name("IntelLayer") config_path = join("IntelHelper", new_layer_name) context.config[join(config_path, "memory_layer")] = layer_name context.config[join(config_path, "page_map_offset")] = dtb context.config[join(config_path, LinuxSymbolFinder.banner_config_key)] = str(banner, 'latin-1') layer = layer_class(context, config_path = config_path, name = new_layer_name, metadata = {'kaslr_value': aslr_shift, 'os': 'Linux'}) if layer and dtb: vollog.debug("DTB was found at: 0x{:0x}".format(dtb)) return layer vollog.debug("No suitable linux banner could be matched") return None
def _banner_scan( self, context: interfaces.context.ContextInterface, config_path: str, requirement: interfaces.configuration. ConstructableRequirementInterface, layer_name: str, progress_callback: constants.ProgressCallback = None) -> None: """Accepts a context, config_path and SymbolTableRequirement, with a constructed layer_name and scans the layer for banners.""" # Bomb out early if there's no banners if not self.banners: return mss = scanners.MultiStringScanner( [x for x in self.banners if x is not None]) layer = context.layers[layer_name] # Check if the Stacker has already found what we're looking for if layer.config.get(self.banner_config_key, None): banner_list = [(0, bytes(layer.config[self.banner_config_key], 'raw_unicode_escape')) ] # type: Iterable[Any] else: # Swap to the physical layer for scanning # TODO: Fix this so it works for layers other than just Intel layer = context.layers[layer.config['memory_layer']] banner_list = layer.scan(context=context, scanner=mss, progress_callback=progress_callback) for _, banner in banner_list: vollog.debug("Identified banner: {}".format(repr(banner))) symbol_files = self.banners.get(banner, None) if symbol_files: isf_path = symbol_files[0] vollog.debug("Using symbol library: {}".format( symbol_files[0])) clazz = self.symbol_class # Set the discovered options path_join = interfaces.configuration.path_join context.config[path_join(config_path, requirement.name, "class")] = clazz context.config[path_join(config_path, requirement.name, "isf_url")] = isf_path context.config[path_join(config_path, requirement.name, "symbol_mask")] = layer.address_mask # Set a default symbol_shift when attempt to determine it, # so we can create the symbols which are used in finding the aslr_shift anyway if not context.config.get( path_join(config_path, requirement.name, "symbol_shift"), None): # Don't overwrite it if it's already been set, it will be manually refound if not present prefound_kaslr_value = context.layers[ layer_name].metadata.get('kaslr_value', 0) context.config[path_join( config_path, requirement.name, "symbol_shift")] = prefound_kaslr_value # Construct the appropriate symbol table requirement.construct(context, config_path) # Apply the ASLR masking (only if we're not already shifted) if self.find_aslr and not context.config.get( path_join(config_path, requirement.name, "symbol_shift"), None): unmasked_symbol_table_name = context.config.get( path_join(config_path, requirement.name), None) if not unmasked_symbol_table_name: raise exceptions.SymbolSpaceError( "Symbol table could not be constructed") if not isinstance(layer, layers.intel.Intel): raise TypeError("Layer name {} is not an intel space") aslr_shift = self.find_aslr(context, unmasked_symbol_table_name, layer.config['memory_layer']) context.config[path_join(config_path, requirement.name, "symbol_shift")] = aslr_shift context.symbol_space.clear_symbol_cache( unmasked_symbol_table_name) break else: if symbol_files: vollog.debug("Symbol library path not found: {}".format( symbol_files[0])) # print("Kernel", banner, hex(banner_offset)) else: vollog.debug("No existing banners found")
def stack( cls, context: interfaces.context.ContextInterface, layer_name: str, progress_callback: constants.ProgressCallback = None ) -> Optional[interfaces.layers.DataLayerInterface]: """Attempts to identify mac within this layer.""" # Bail out by default unless we can stack properly layer = context.layers[layer_name] new_layer = None join = interfaces.configuration.path_join # Never stack on top of an intel layer # FIXME: Find a way to improve this check if isinstance(layer, intel.Intel): return None mac_banners = MacBannerCache.load_banners() # If we have no banners, don't bother scanning if not mac_banners: vollog.info( "No Mac banners found - if this is a mac plugin, please check your symbol files location" ) return None mss = scanners.MultiStringScanner([x for x in mac_banners if x]) for banner_offset, banner in layer.scan( context=context, scanner=mss, progress_callback=progress_callback): dtb = None vollog.debug(f"Identified banner: {repr(banner)}") symbol_files = mac_banners.get(banner, None) if symbol_files: isf_path = symbol_files[0] table_name = context.symbol_space.free_table_name( 'MacintelStacker') table = mac.MacKernelIntermedSymbols(context=context, config_path=join( 'temporary', table_name), name=table_name, isf_url=isf_path) context.symbol_space.append(table) kaslr_shift = cls.find_aslr( context=context, symbol_table=table_name, layer_name=layer_name, compare_banner=banner, compare_banner_offset=banner_offset, progress_callback=progress_callback) if kaslr_shift == 0: vollog.log( constants.LOGLEVEL_VVV, f"Invalid kalsr_shift found at offset: {banner_offset}" ) continue bootpml4_addr = cls.virtual_to_physical_address( table.get_symbol("BootPML4").address + kaslr_shift) new_layer_name = context.layers.free_layer_name( "MacDTBTempLayer") config_path = join("automagic", "MacIntelHelper", new_layer_name) context.config[join(config_path, "memory_layer")] = layer_name context.config[join(config_path, "page_map_offset")] = bootpml4_addr layer = layers.intel.Intel32e(context, config_path=config_path, name=new_layer_name, metadata={'os': 'Mac'}) idlepml4_ptr = table.get_symbol( "IdlePML4").address + kaslr_shift try: idlepml4_str = layer.read(idlepml4_ptr, 4) except exceptions.InvalidAddressException: vollog.log( constants.LOGLEVEL_VVVV, f"Skipping invalid idlepml4_ptr: 0x{idlepml4_ptr:0x}") continue idlepml4_addr = struct.unpack("<I", idlepml4_str)[0] tmp_dtb = idlepml4_addr if tmp_dtb % 4096: vollog.log( constants.LOGLEVEL_VVV, f"Skipping non-page aligned DTB: 0x{tmp_dtb:0x}") continue dtb = tmp_dtb # Build the new layer new_layer_name = context.layers.free_layer_name("IntelLayer") config_path = join("automagic", "MacIntelHelper", new_layer_name) context.config[join(config_path, "memory_layer")] = layer_name context.config[join(config_path, "page_map_offset")] = dtb context.config[join(config_path, MacSymbolFinder.banner_config_key)] = str( banner, 'latin-1') new_layer = intel.Intel32e(context, config_path=config_path, name=new_layer_name, metadata={'os': 'mac'}) new_layer.config['kernel_virtual_offset'] = kaslr_shift if new_layer and dtb: vollog.debug(f"DTB was found at: 0x{dtb:0x}") return new_layer vollog.debug("No suitable mac banner could be matched") return None
def _generator(self) -> Iterator[Tuple]: kernel = self.context.modules[self.config['kernel']] physical_layer_name = self.context.layers[ kernel.layer_name].config.get('memory_layer', None) # Decide of Memory Dump Architecture layer = self.context.layers[physical_layer_name] architecture = "intel" if not symbols.symbol_table_is_64bit( self.context, kernel.symbol_table_name) else "intel64" # Read in the Symbol File symbol_table = intermed.IntermediateSymbolTable.create( context=self.context, config_path=self.config_path, sub_path="windows", filename="mbr", class_types={ 'PARTITION_TABLE': mbr.PARTITION_TABLE, 'PARTITION_ENTRY': mbr.PARTITION_ENTRY }) partition_table_object = symbol_table + constants.BANG + "PARTITION_TABLE" # Define Signature and Data Length mbr_signature = b"\x55\xAA" mbr_length = 0x200 bootcode_length = 0x1B8 # Scan the Layer for Raw Master Boot Record (MBR) and parse the fields for offset, _value in layer.scan( context=self.context, scanner=scanners.MultiStringScanner(patterns=[mbr_signature])): try: mbr_start_offset = offset - (mbr_length - len(mbr_signature)) partition_table = self.context.object(partition_table_object, offset=mbr_start_offset, layer_name=layer.name) # Extract only BootCode full_mbr = layer.read(mbr_start_offset, mbr_length, pad=True) bootcode = full_mbr[:bootcode_length] all_zeros = None if bootcode: all_zeros = bootcode.count(b"\x00") == len(bootcode) if not all_zeros: partition_entries = [ partition_table.FirstEntry, partition_table.SecondEntry, partition_table.ThirdEntry, partition_table.FourthEntry ] if not self.config.get("full", True): yield (0, (format_hints.Hex(offset), partition_table.get_disk_signature(), self.get_hash(bootcode), self.get_hash(full_mbr), renderers.NotApplicableValue(), renderers.NotApplicableValue(), renderers.NotApplicableValue(), renderers.NotApplicableValue(), interfaces.renderers.Disassembly( bootcode, 0, architecture))) else: yield (0, (format_hints.Hex(offset), partition_table.get_disk_signature(), self.get_hash(bootcode), self.get_hash(full_mbr), renderers.NotApplicableValue(), renderers.NotApplicableValue(), renderers.NotApplicableValue(), renderers.NotApplicableValue(), renderers.NotApplicableValue(), renderers.NotApplicableValue(), renderers.NotApplicableValue(), renderers.NotApplicableValue(), renderers.NotApplicableValue(), renderers.NotApplicableValue(), renderers.NotApplicableValue(), renderers.NotApplicableValue(), renderers.NotApplicableValue(), interfaces.renderers.Disassembly( bootcode, 0, architecture), format_hints.HexBytes(bootcode))) for partition_index, partition_entry_object in enumerate( partition_entries, start=1): if not self.config.get("full", True): yield (1, ( format_hints.Hex(offset), partition_table.get_disk_signature(), self.get_hash(bootcode), self.get_hash(full_mbr), partition_index, partition_entry_object.is_bootable(), partition_entry_object.get_partition_type(), format_hints.Hex(partition_entry_object. get_size_in_sectors()), renderers.NotApplicableValue())) else: yield (1, ( format_hints.Hex(offset), partition_table.get_disk_signature(), self.get_hash(bootcode), self.get_hash(full_mbr), partition_index, partition_entry_object.is_bootable(), format_hints.Hex(partition_entry_object. get_bootable_flag()), partition_entry_object.get_partition_type(), format_hints.Hex( partition_entry_object.PartitionType), format_hints.Hex( partition_entry_object.get_starting_lba()), partition_entry_object.get_starting_cylinder(), partition_entry_object.get_starting_chs(), partition_entry_object.get_starting_sector(), partition_entry_object.get_ending_cylinder(), partition_entry_object.get_ending_chs(), partition_entry_object.get_ending_sector(), format_hints.Hex(partition_entry_object. get_size_in_sectors()), renderers.NotApplicableValue(), renderers.NotApplicableValue())) else: vollog.log( constants.LOGLEVEL_VVVV, f"Not a valid MBR: Data all zeroed out : {format_hints.Hex(offset)}" ) continue except exceptions.PagedInvalidAddressException as excp: vollog.log( constants.LOGLEVEL_VVVV, f"Invalid address identified in guessed MBR: {hex(excp.invalid_address)}" ) continue
def _banner_scan( self, context: interfaces.context.ContextInterface, config_path: str, requirement: interfaces.configuration. ConstructableRequirementInterface, layer_name: str, progress_callback: constants.ProgressCallback = None) -> None: """Accepts a context, config_path and SymbolTableRequirement, with a constructed layer_name and scans the layer for banners.""" # Bomb out early if there's no banners if not self.banners: return mss = scanners.MultiStringScanner( [x for x in self.banners if x is not None]) layer = context.layers[layer_name] # Check if the Stacker has already found what we're looking for if layer.config.get(self.banner_config_key, None): banner_list = [(0, bytes(layer.config[self.banner_config_key], 'raw_unicode_escape')) ] # type: Iterable[Any] else: # Swap to the physical layer for scanning # Only traverse down a layer if it's an intel layer # TODO: Fix this so it works for layers other than just Intel if isinstance(layer, layers.intel.Intel): layer = context.layers[layer.config['memory_layer']] banner_list = layer.scan(context=context, scanner=mss, progress_callback=progress_callback) for _, banner in banner_list: vollog.debug(f"Identified banner: {repr(banner)}") symbol_files = self.banners.get(banner, None) if symbol_files: isf_path = symbol_files[0] vollog.debug(f"Using symbol library: {symbol_files[0]}") clazz = self.symbol_class # Set the discovered options path_join = interfaces.configuration.path_join context.config[path_join(config_path, requirement.name, "class")] = clazz context.config[path_join(config_path, requirement.name, "isf_url")] = isf_path context.config[path_join(config_path, requirement.name, "symbol_mask")] = layer.address_mask # Construct the appropriate symbol table requirement.construct(context, config_path) break else: if symbol_files: vollog.debug( f"Symbol library path not found: {symbol_files[0]}") # print("Kernel", banner, hex(banner_offset)) else: vollog.debug("No existing banners found")