def _generator(self): kernel = self.context.modules[self.config['kernel']] filter_func = pslist.PsList.create_pid_filter( self.config.get('pid', None)) # Collect all the values as we will want to group them later sessions = {} for proc in pslist.PsList.list_processes(self.context, kernel.layer_name, kernel.symbol_table_name, filter_func=filter_func): session_id = proc.get_session_id() # Detect RDP, Console or set default value session_type = renderers.NotAvailableValue() # Construct Username from Process Env user_domain = '' user_name = '' for var, val in proc.environment_variables(): if var.lower() == 'username': user_name = val elif var.lower() == 'userdomain': user_domain = val if var.lower() == 'sessionname': session_type = val # Concat Domain and User full_user = f'{user_domain}/{user_name}' if full_user == '/': full_user = renderers.NotAvailableValue() # Collect all the values in to a row we can yield after sorting. row = { "session_id": session_id, "process_id": proc.UniqueProcessId, "process_name": utility.array_to_string(proc.ImageFileName), "user_name": full_user, "process_start": proc.get_create_time(), "session_type": session_type } # Add row to correct session so we can sort it later if session_id in sessions: sessions[session_id].append(row) else: sessions[session_id] = [row] # Group and yield each row for rows in sessions.values(): for row in rows: yield 0, (row.get('session_id'), row.get('session_type'), row.get('process_id'), row.get('process_name'), row.get('user_name'), row.get('process_start'))
def _generator(self, syshive: registry.RegistryHive, samhive: registry.RegistryHive): if syshive is None: vollog.debug("SYSTEM address is None: Did you use the correct profile?") yield (0, (renderers.NotAvailableValue(), renderers.NotAvailableValue(), renderers.NotAvailableValue(), renderers.NotAvailableValue())) if samhive is None: vollog.debug("SAM address is None: Did you use the correct profile?") yield (0, (renderers.NotAvailableValue(), renderers.NotAvailableValue(), renderers.NotAvailableValue(), renderers.NotAvailableValue())) bootkey = self.get_bootkey(syshive) hbootkey = self.get_hbootkey(samhive, bootkey) if hbootkey: for user in self.get_user_keys(samhive): ret = self.get_user_hashes(user, samhive, hbootkey) if ret: lmhash, nthash = ret ## temporary fix to prevent UnicodeDecodeError backtraces ## however this can cause truncated user names as a result name = self.get_user_name(user, samhive) if name is None: name = renderers.NotAvailableValue() else: name = str(name, 'utf-16-le', errors = 'ignore') lmout = str(binascii.hexlify(lmhash or self.empty_lm), 'latin-1') ntout = str(binascii.hexlify(nthash or self.empty_nt), 'latin-1') rid = int(str(user.get_name()), 16) yield (0, (name, rid, lmout, ntout)) else: vollog.warning("Hbootkey is not valid")
def parse_data(self, data: bytes) -> Tuple[str, bytes]: name = renderers.NotAvailableValue() certificate_data = renderers.NotAvailableValue() while len(data) > 12: ctype, clength = struct.unpack("<QI", data[0:12]) cvalue, data = data[12:12 + clength], data[12 + clength:] if ctype == 0x10000000b: name = str(cvalue, 'utf-16').strip("\x00") elif ctype == 0x100000020: certificate_data = cvalue return (name, certificate_data)
def _generator(self): kernel = self.context.modules[self.config['kernel']] callback_table_name = self.create_callback_table( self.context, kernel.symbol_table_name, self.config_path) collection = ssdt.SSDT.build_module_collection( self.context, kernel.layer_name, kernel.symbol_table_name) callback_methods = (self.list_notify_routines, self.list_bugcheck_callbacks, self.list_bugcheck_reason_callbacks, self.list_registry_callbacks) for callback_method in callback_methods: for callback_type, callback_address, callback_detail in callback_method( self.context, kernel.layer_name, kernel.symbol_table_name, callback_table_name): if callback_detail is None: detail = renderers.NotApplicableValue() else: detail = callback_detail module_symbols = list( collection.get_module_symbols_by_absolute_location( callback_address)) if module_symbols: for module_name, symbol_generator in module_symbols: symbols_found = False # we might have multiple symbols pointing to the same location for symbol in symbol_generator: symbols_found = True yield (0, (callback_type, format_hints.Hex(callback_address), module_name, symbol.split(constants.BANG)[1], detail)) # no symbols, but we at least can report the module name if not symbols_found: yield (0, (callback_type, format_hints.Hex(callback_address), module_name, renderers.NotAvailableValue(), detail)) else: # no module was found at the absolute location yield (0, (callback_type, format_hints.Hex(callback_address), renderers.NotAvailableValue(), renderers.NotAvailableValue(), detail))
def find_sid_re( sid_string, sid_re_list) -> Union[str, interfaces.renderers.BaseAbsentValue]: for reg, name in sid_re_list: if reg.search(sid_string): return name return renderers.NotAvailableValue()
def _generator(self): kernel = self.context.modules[self.config['kernel']] collection = ssdt.SSDT.build_module_collection(self.context, kernel.layer_name, kernel.symbol_table_name) for driver in driverscan.DriverScan.scan_drivers(self.context, kernel.layer_name, kernel.symbol_table_name): try: driver_name = driver.get_driver_name() except (ValueError, exceptions.InvalidAddressException): driver_name = renderers.NotApplicableValue() for i, address in enumerate(driver.MajorFunction): module_symbols = collection.get_module_symbols_by_absolute_location(address) for module_name, symbol_generator in module_symbols: symbols_found = False for symbol in symbol_generator: symbols_found = True yield (0, (format_hints.Hex(driver.vol.offset), driver_name, MAJOR_FUNCTIONS[i], format_hints.Hex(address), module_name, symbol.split(constants.BANG)[1])) if not symbols_found: yield (0, (format_hints.Hex(driver.vol.offset), driver_name, MAJOR_FUNCTIONS[i], format_hints.Hex(address), module_name, renderers.NotAvailableValue()))
def _get_banner(self, clazz: Type[symbol_cache.SymbolBannerCache], data: Any) -> str: """Gets a banner from an ISF file""" banner_symbol = data.get('symbols', {}).get(clazz.symbol_name, {}).get('constant_data', renderers.NotAvailableValue()) if not isinstance(banner_symbol, interfaces.renderers.BaseAbsentValue): banner_symbol = str(base64.b64decode(banner_symbol), encoding='latin-1') return banner_symbol
def _generator(self): if self.config.get('isf', None) is not None: file_list = [self.config['isf']] else: file_list = list(self.list_all_isf_files()) # Filter the files filtered_list = [] if not len(self.config['filter']): filtered_list = file_list else: for isf_file in file_list: for filter_item in self.config['filter']: if filter_item in isf_file: filtered_list.append(isf_file) try: import jsonschema if not self.config['validate']: raise ImportError # Act as if we couldn't import if validation is turned off def check_valid(data): return "True" if schemas.validate(data, True) else "False" except ImportError: def check_valid(data): return "Unknown" # Process the filtered list for entry in filtered_list: num_types = num_enums = num_bases = num_symbols = 0 windows_info = linux_banner = mac_banner = renderers.NotAvailableValue( ) valid = "Unknown" with resources.ResourceAccessor().open(url=entry) as fp: try: data = json.load(fp) num_symbols = len(data.get('symbols', [])) num_types = len(data.get('user_types', [])) num_enums = len(data.get('enums', [])) num_bases = len(data.get('base_types', [])) linux_banner = self._get_banner(linux.LinuxBannerCache, data) mac_banner = self._get_banner(mac.MacBannerCache, data) if not linux_banner and not mac_banner: windows_info = os.path.splitext( os.path.basename(entry))[0] valid = check_valid(data) except (UnicodeDecodeError, json.decoder.JSONDecodeError): vollog.warning("Invalid ISF: {}".format(entry)) yield (0, (entry, valid, num_bases, num_types, num_symbols, num_enums, windows_info, linux_banner, mac_banner))
def _generator(self) -> Iterator[Tuple[int, Tuple[int, int, Any, Any]]]: layer_name = self.config['primary'] collection = self.build_module_collection(self.context, self.config["primary"], self.config["nt_symbols"]) kvo = self.context.layers[layer_name].config['kernel_virtual_offset'] ntkrnlmp = self.context.module(self.config["nt_symbols"], layer_name = layer_name, offset = kvo) # this is just one way to enumerate the native (NT) service table. # to do the same thing for the Win32K service table, we would need Win32K.sys symbol support ## we could also find nt!KeServiceDescriptorTable (NT) and KeServiceDescriptorTableShadow (NT, Win32K) service_table_address = ntkrnlmp.get_symbol("KiServiceTable").address service_limit_address = ntkrnlmp.get_symbol("KiServiceLimit").address service_limit = ntkrnlmp.object(object_type = "int", offset = service_limit_address) # on 32-bit systems the table indexes are 32-bits and contain pointers (unsigned) # on 64-bit systems the indexes are also 32-bits but they're offsets from the # base address of the table and can be negative, so we need a signed data type is_kernel_64 = symbols.symbol_table_is_64bit(self.context, self.config["nt_symbols"]) if is_kernel_64: array_subtype = "long" def kvo_calulator(func: int) -> int: return kvo + service_table_address + (func >> 4) find_address = kvo_calulator else: array_subtype = "unsigned long" def passthrough(func: int) -> int: return func find_address = passthrough functions = ntkrnlmp.object(object_type = "array", offset = service_table_address, subtype = ntkrnlmp.get_type(array_subtype), count = service_limit) for idx, function_obj in enumerate(functions): function = find_address(function_obj) module_symbols = collection.get_module_symbols_by_absolute_location(function) for module_name, symbol_generator in module_symbols: symbols_found = False for symbol in symbol_generator: symbols_found = True yield (0, (idx, format_hints.Hex(function), module_name, symbol.split(constants.BANG)[1])) if not symbols_found: yield (0, (idx, format_hints.Hex(function), module_name, renderers.NotAvailableValue()))
def _generator(self, procs): pe_table_name = intermed.IntermediateSymbolTable.create( self.context, self.config_path, "windows", "pe", class_types=pe.class_types) kernel = self.context.modules[self.config['kernel']] kuser = info.Info.get_kuser_structure(self.context, kernel.layer_name, kernel.symbol_table_name) nt_major_version = int(kuser.NtMajorVersion) nt_minor_version = int(kuser.NtMinorVersion) # LoadTime only applies to versions higher or equal to Window 7 (6.1 and higher) dll_load_time_field = (nt_major_version > 6) or ( nt_major_version == 6 and nt_minor_version >= 1) for proc in procs: proc_id = proc.UniqueProcessId proc_layer_name = proc.add_process_layer() for entry in proc.load_order_modules(): BaseDllName = FullDllName = renderers.UnreadableValue() try: BaseDllName = entry.BaseDllName.get_string() # We assume that if the BaseDllName points to an invalid buffer, so will FullDllName FullDllName = entry.FullDllName.get_string() except exceptions.InvalidAddressException: pass if dll_load_time_field: # Versions prior to 6.1 won't have the LoadTime attribute # and 32bit version shouldn't have the Quadpart according to MSDN try: DllLoadTime = conversion.wintime_to_datetime( entry.LoadTime.QuadPart) except exceptions.InvalidAddressException: DllLoadTime = renderers.UnreadableValue() else: DllLoadTime = renderers.NotApplicableValue() file_output = "Disabled" if self.config['dump']: file_handle = self.dump_pe(self.context, pe_table_name, entry, self.open, proc_layer_name, prefix=f"pid.{proc_id}.") file_output = "Error outputting file" if file_handle: file_handle.close() file_output = file_handle.preferred_filename try: dllbase = format_hints.Hex(entry.DllBase) except exceptions.InvalidAddressException: dllbase = renderers.NotAvailableValue() try: size_of_image = format_hints.Hex(entry.SizeOfImage) except exceptions.InvalidAddressException: size_of_image = renderers.NotAvailableValue() yield (0, (proc.UniqueProcessId, proc.ImageFileName.cast( "string", max_length=proc.ImageFileName.vol.count, errors='replace'), dllbase, size_of_image, BaseDllName, FullDllName, DllLoadTime, file_output))