Example #1
0
    def _method_offset(self,
                       context: interfaces.context.ContextInterface,
                       vlayer: layers.intel.Intel,
                       pattern: bytes,
                       result_offset: int,
                       progress_callback: constants.ProgressCallback = None) -> Optional[ValidKernelType]:
        """Method for finding a suitable kernel offset based on a module
        table."""
        vollog.debug("Kernel base determination - searching layer module list structure")
        valid_kernel: Optional[ValidKernelType] = None
        # If we're here, chances are high we're in a Win10 x64 image with kernel base randomization
        physical_layer_name = self.get_physical_layer_name(context, vlayer)
        physical_layer = context.layers[physical_layer_name]
        # TODO:  On older windows, this might be \WINDOWS\system32\nt rather than \SystemRoot\system32\nt
        results = physical_layer.scan(context, scanners.BytesScanner(pattern), progress_callback = progress_callback)
        seen: Set[int] = set()
        # Because this will launch a scan of the virtual layer, we want to be careful
        for result in results:
            # TODO: Identify the specific structure we're finding and document this a bit better
            pointer = context.object("pdbscan!unsigned long long",
                                     offset = (result + result_offset),
                                     layer_name = physical_layer_name)
            address = pointer & vlayer.address_mask
            if address in seen:
                continue
            seen.add(address)

            valid_kernel = self.check_kernel_offset(context, vlayer, address, progress_callback)

            if valid_kernel:
                break
        return valid_kernel
Example #2
0
    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()))
Example #3
0
    def _find_csystems_with_scanning(
            self, proc_layer_name: str,
            cryptdll_types: interfaces.context.ModuleInterface,
            cryptdll_base: int,
            cryptdll_size: int) -> List[interfaces.context.ModuleInterface]:
        """
        Performs scanning to find potential RC4 HMAC csystem instances

        This function may return several values as it cannot validate which is the active one

        Args:
            proc_layer_name: the lsass.exe process layer name
            cryptdll_types: the types from cryptdll binary analysis
            cryptdll_base: base address of cryptdll.dll inside of lsass.exe
            cryptdll_size: size of the VAD
        Returns:
            A list of csystem instances
        """

        csystems = []

        cryptdll_end = cryptdll_base + cryptdll_size

        proc_layer = self.context.layers[proc_layer_name]

        ecrypt_size = cryptdll_types.get_type("_KERB_ECRYPT").size

        # scan for potential instances of RC4 HMAC
        # the signature is based on the type being 0x17
        # and the block size member being 1 in all test samples
        for address in proc_layer.scan(
                self.context,
                scanners.BytesScanner(b"\x17\x00\x00\x00\x01\x00\x00\x00"),
                sections=[(cryptdll_base, cryptdll_size)]):

            # this occurs across page boundaries
            if not proc_layer.is_valid(address, ecrypt_size):
                continue

            kerb = cryptdll_types.object("_KERB_ECRYPT",
                                         offset=address,
                                         absolute=True)

            # ensure the Encrypt and Finish pointers are inside the VAD
            # these are not manipulated in the attack
            if (cryptdll_base < kerb.Encrypt < cryptdll_end) and \
                    (cryptdll_base < kerb.Finish < cryptdll_end):
                csystems.append(kerb)

        return csystems
Example #4
0
 def find_version_info(
         cls, context: interfaces.context.ContextInterface, layer_name: str,
         filename: str) -> Optional[Tuple[int, int, int, int]]:
     """Searches for an original filename, then tracks back to find the VS_VERSION_INFO and read the fixed
     version information structure"""
     premable_max_distance = 0x500
     filename = "OriginalFilename\x00" + filename
     iterator = context.layers[layer_name].scan(
         context=context,
         scanner=scanners.BytesScanner(bytes(filename, 'utf-16be')))
     for offset in iterator:
         data = context.layers[layer_name].read(
             offset - premable_max_distance, premable_max_distance)
         vs_ver_info = b"\xbd\x04\xef\xfe"
         verinfo_offset = data.find(vs_ver_info) + len(vs_ver_info)
         if verinfo_offset >= 0:
             structure = '<IHHHHHHHH'
             struct_version, FV2, FV1, FV4, FV3, PV2, PV1, PV4, PV3 = struct.unpack(
                 structure, data[verinfo_offset:verinfo_offset +
                                 struct.calcsize(structure)])
             return (FV1, FV2, FV3, FV4)
     return None
Example #5
0
    def _generator(self):

        service_table_name = self.create_service_table(
            self.context, self.config["nt_symbols"], self.config_path)

        relative_tag_offset = self.context.symbol_space.get_type(
            service_table_name + constants.BANG +
            "_SERVICE_RECORD").relative_child_offset("Tag")

        filter_func = pslist.PsList.create_name_filter(["services.exe"])

        is_vista_or_later = versions.is_vista_or_later(
            context=self.context, symbol_table=self.config["nt_symbols"])

        if is_vista_or_later:
            service_tag = b"serH"
        else:
            service_tag = b"sErv"

        seen = []

        for task in pslist.PsList.list_processes(
                context=self.context,
                layer_name=self.config['primary'],
                symbol_table=self.config['nt_symbols'],
                filter_func=filter_func):

            proc_id = "Unknown"
            try:
                proc_id = task.UniqueProcessId
                proc_layer_name = task.add_process_layer()
            except exceptions.InvalidAddressException as excp:
                vollog.debug(
                    "Process {}: invalid address {} in layer {}".format(
                        proc_id, excp.invalid_address, excp.layer_name))
                continue

            layer = self.context.layers[proc_layer_name]

            for offset in layer.scan(
                    context=self.context,
                    scanner=scanners.BytesScanner(needle=service_tag),
                    sections=vadyarascan.VadYaraScan.get_vad_maps(task)):

                if not is_vista_or_later:
                    service_record = self.context.object(
                        service_table_name + constants.BANG +
                        "_SERVICE_RECORD",
                        offset=offset - relative_tag_offset,
                        layer_name=proc_layer_name)

                    if not service_record.is_valid():
                        continue

                    yield (0, self.get_record_tuple(service_record))
                else:
                    service_header = self.context.object(
                        service_table_name + constants.BANG +
                        "_SERVICE_HEADER",
                        offset=offset,
                        layer_name=proc_layer_name)

                    if not service_header.is_valid():
                        continue

                    # since we walk the s-list backwards, if we've seen
                    # an object, then we've also seen all objects that
                    # exist before it, thus we can break at that time.
                    for service_record in service_header.ServiceRecord.traverse(
                    ):
                        if service_record in seen:
                            break
                        seen.append(service_record)
                        yield (0, self.get_record_tuple(service_record))