Пример #1
0
    def scan_payload(
        self,
        payload: Payload,
        request_meta: Optional[RequestMeta] = None,
        add_start_dispatch: Optional[List[str]] = None,
        add_start_deep_dispatch: Optional[List[str]] = None,
    ) -> StoqResponse:
        """

        Scan an individual payload

        :param payload: ``Payload`` object of data to be scanned
        :param request_meta: Metadata pertaining to the originating request
        :param add_start_dispatch: Force first round of scanning to use specified plugins
        :param add_start_deep_dispatch: Force second round of scanning to use specified plugins

        :return: Complete scan results
        :rtype: StoqResponse

        """
        request_meta = RequestMeta() if request_meta is None else request_meta
        add_start_dispatch = [] if add_start_dispatch is None else add_start_dispatch
        add_start_deep_dispatch = ([] if add_start_deep_dispatch is None else
                                   add_start_deep_dispatch)
        scan_results: List = []
        errors: DefaultDict[str, List[str]] = defaultdict(list)
        scan_queue = [(payload, add_start_dispatch, add_start_deep_dispatch)]
        hashes_seen: Set[str] = set(helpers.get_sha256(payload.content))

        for _recursion_level in range(self.max_recursion + 1):
            next_scan_queue: List[Tuple[Payload, List[str], List[str]]] = []
            for payload, add_dispatch, add_deep_dispatch in scan_queue:
                payload_results, extracted, p_errors = self._single_scan(
                    payload, add_dispatch, add_deep_dispatch, request_meta)
                scan_results.append(payload_results)
                # TODO: Add option for no-dedup
                for ex in extracted:
                    ex_hash = helpers.get_sha256(ex.content)
                    if ex_hash not in hashes_seen:
                        hashes_seen.add(ex_hash)
                        next_scan_queue.append(
                            (ex, ex.payload_meta.dispatch_to, []))
                errors = helpers.merge_dicts(errors, p_errors)
            scan_queue = next_scan_queue

        response = StoqResponse(results=scan_results,
                                request_meta=request_meta,
                                errors=errors)

        self._apply_decorators(response)

        for connector in self._loaded_connector_plugins:
            try:
                connector.save(response)
            except Exception:
                self.log.exception(
                    f'Failed to save results using {connector.__module__}: {response}'
                )
        return response
Пример #2
0
 def test_get_sha256(self):
     h = helpers.get_sha256(self.generic_content)
     self.assertEqual(
         h,
         '5cac4f980fedc3d3f1f99b4be3472c9b30d56523e632d151237ec9309048bda9')
Пример #3
0
    async def scan_request(
        self, request: Request, add_start_dispatch: Optional[List[str]] = None
    ) -> StoqResponse:
        """

        Scan an individual payload

        :param request: ``Request`` object of payload(s) to be scanned
        :param add_start_dispatch: Force first round of scanning to use specified plugins

        """

        self.log.debug(
            f'Request received: RequestMeta: {helpers.dumps(request.request_meta, indent=0)}, '
            f'start_dispatches: {helpers.dumps(add_start_dispatch, indent=0)}'
        )

        add_dispatches: Set[Tuple[Payload, str]] = set()
        hashes_seen: DefaultDict[str, List] = defaultdict(list)
        for idx, payload in enumerate(request.payloads):
            if payload.results.payload_meta.should_scan and add_start_dispatch:
                for plugin_name in add_start_dispatch:
                    add_dispatches.add((payload, plugin_name))

            sha = helpers.get_sha256(payload.content)
            hashes_seen[sha].append(idx)

        for _recursion_level in range(1, self.max_recursion + 1):
            self.log.debug(f'Beginning worker round {_recursion_level}')
            scan_result = await self._execute_scan_round(request, add_dispatches)

            if scan_result is None:
                self.log.debug('No more plugins to run, completing scan')
                break

            extracted_payloads, add_dispatches = scan_result
            # TODO: Add option for no-dedup
            for extracted_payload in extracted_payloads:
                payload_hash = helpers.get_sha256(extracted_payload.content)
                if payload_hash not in hashes_seen:
                    self.log.debug(
                        f'Extracted payload {extracted_payload.results.payload_id} with '
                        f'PayloadMeta: {extracted_payload.results.payload_meta}'
                    )

                    request.payloads.append(extracted_payload)
                    hashes_seen[payload_hash].append(len(request.payloads) - 1)

                    payload_meta = extracted_payload.results.payload_meta
                    if _recursion_level >= self.max_recursion:
                        request.errors.append(
                            Error(
                                error=f'Final worker round ({_recursion_level}) reached, unable to process payload',
                                payload_id=extracted_payload.results.payload_id,
                            )
                        )
                    elif payload_meta.should_scan and payload_meta.dispatch_to:
                        add_dispatches.update(
                            (extracted_payload, add_dispatch)
                            for add_dispatch in payload_meta.dispatch_to
                        )
                else:
                    payload_idx = hashes_seen[payload_hash]
                    for idx in payload_idx:
                        request.payloads[idx].results.extracted_by.extend(
                            extracted_payload.results.extracted_by
                        )
                        request.payloads[idx].results.extracted_from.extend(
                            extracted_payload.results.extracted_from
                        )

        archive_tasks: List = []
        if request.request_meta.archive_payloads:
            for payload in request.payloads:
                if not payload.results.payload_meta.should_archive:
                    continue

                for archiver in self._loaded_dest_archiver_plugins.values():
                    archive_tasks.append(
                        self._apply_archiver(archiver, payload, request)
                    )
            await asyncio.gather(*archive_tasks)

        response = StoqResponse(request=request)

        decorator_tasks = []
        for decorator in self._loaded_decorator_plugins.values():
            decorator_tasks.append(self._apply_decorator(decorator, response))
        await asyncio.gather(*decorator_tasks)

        connector_tasks = []
        for connector in self._loaded_connector_plugins:
            connector_tasks.append(self._apply_connector(connector, response))
        await asyncio.gather(*connector_tasks)
        return response