Ejemplo n.º 1
0
    def testMultiResponseParsers(self):
        class FooParser(parser.MultiResponseParser):

            supported_artifacts = ["Foo"]

            def ParseResponses(self, knowledge_base, responses):
                raise NotImplementedError()

        class BarParser(parser.MultiResponseParser):

            supported_artifacts = ["Bar"]

            def ParseResponses(self, knowledge_base, responses):
                raise NotImplementedError()

        parsers.MULTI_RESPONSE_PARSER_FACTORY.Register("Foo", FooParser)
        parsers.MULTI_RESPONSE_PARSER_FACTORY.Register("Bar", BarParser)

        foo_factory = parsers.ArtifactParserFactory("Foo")
        foo_parsers = foo_factory.MultiResponseParsers()
        self.assertItemsEqual(map(type, foo_parsers), [FooParser])

        bar_factory = parsers.ArtifactParserFactory("Bar")
        bar_parsers = bar_factory.MultiResponseParsers()
        self.assertItemsEqual(map(type, bar_parsers), [BarParser])
Ejemplo n.º 2
0
  def testMultiResponseParsers(self):

    class FooParser(parsers.MultiResponseParser[None]):

      supported_artifacts = ["Foo"]

      def ParseResponses(
          self,
          knowledge_base: rdf_client.KnowledgeBase,
          responses: Iterable[rdfvalue.RDFValue],
      ) -> Iterator[None]:
        raise NotImplementedError()

    class BarParser(parsers.MultiResponseParser[None]):

      supported_artifacts = ["Bar"]

      def ParseResponses(
          self,
          knowledge_base: rdf_client.KnowledgeBase,
          responses: Iterable[rdfvalue.RDFValue],
      ) -> Iterator[None]:
        raise NotImplementedError()

    parsers.MULTI_RESPONSE_PARSER_FACTORY.Register("Foo", FooParser)
    parsers.MULTI_RESPONSE_PARSER_FACTORY.Register("Bar", BarParser)

    foo_factory = parsers.ArtifactParserFactory("Foo")
    foo_parsers = foo_factory.MultiResponseParsers()
    self.assertCountEqual(map(type, foo_parsers), [FooParser])

    bar_factory = parsers.ArtifactParserFactory("Bar")
    bar_parsers = bar_factory.MultiResponseParsers()
    self.assertCountEqual(map(type, bar_parsers), [BarParser])
Ejemplo n.º 3
0
  def testMultiFileParsers(self):

    class FooParser(parsers.MultiFileParser):

      supported_artifacts = ["Quux", "Norf"]

      def ParseFiles(self, knowledge_base, pathspecs, filedescs):
        raise NotImplementedError()

    class BarParser(parsers.MultiFileParser):

      supported_artifacts = ["Quux", "Thud"]

      def ParseFiles(self, knowledge_base, pathspecs, filedescs):
        raise NotImplementedError()

    parsers.MULTI_FILE_PARSER_FACTORY.Register("Foo", FooParser)
    parsers.MULTI_FILE_PARSER_FACTORY.Register("Bar", BarParser)

    quux_factory = parsers.ArtifactParserFactory("Quux")
    quux_parsers = quux_factory.MultiFileParsers()
    self.assertCountEqual(map(type, quux_parsers), [FooParser, BarParser])

    norf_factory = parsers.ArtifactParserFactory("Norf")
    norf_parsers = norf_factory.MultiFileParsers()
    self.assertCountEqual(map(type, norf_parsers), [FooParser])

    thud_factory = parsers.ArtifactParserFactory("Thud")
    thud_parsers = thud_factory.MultiFileParsers()
    self.assertCountEqual(map(type, thud_parsers), [BarParser])
Ejemplo n.º 4
0
  def testSingleResponseParsers(self):

    class FooParser(parsers.SingleResponseParser[None]):

      supported_artifacts = ["Quux", "Norf"]

      def ParseResponse(
          self,
          knowledge_base: rdf_client.KnowledgeBase,
          response: rdfvalue.RDFValue,
      ) -> Iterator[None]:
        raise NotImplementedError()

    class BarParser(parsers.SingleResponseParser[None]):

      supported_artifacts = ["Norf", "Thud"]

      def ParseResponse(
          self,
          knowledge_base: rdf_client.KnowledgeBase,
          response: rdfvalue.RDFValue,
      ) -> Iterator[None]:
        raise NotImplementedError()

    class BazParser(parsers.SingleResponseParser[None]):

      supported_artifacts = ["Thud", "Quux"]

      def ParseResponse(
          self,
          knowledge_base: rdf_client.KnowledgeBase,
          response: rdfvalue.RDFValue,
      ) -> Iterator[None]:
        raise NotImplementedError()

    parsers.SINGLE_RESPONSE_PARSER_FACTORY.Register("Foo", FooParser)
    parsers.SINGLE_RESPONSE_PARSER_FACTORY.Register("Bar", BarParser)
    parsers.SINGLE_RESPONSE_PARSER_FACTORY.Register("Baz", BazParser)

    quux_factory = parsers.ArtifactParserFactory("Quux")
    quux_parsers = quux_factory.SingleResponseParsers()
    self.assertCountEqual(map(type, quux_parsers), [FooParser, BazParser])

    norf_factory = parsers.ArtifactParserFactory("Norf")
    norf_parsers = norf_factory.SingleResponseParsers()
    self.assertCountEqual(map(type, norf_parsers), [FooParser, BarParser])

    thud_factory = parsers.ArtifactParserFactory("Thud")
    thud_parsers = thud_factory.SingleResponseParsers()
    self.assertCountEqual(map(type, thud_parsers), [BarParser, BazParser])
Ejemplo n.º 5
0
    def testApplySingleResponseError(self):
        class FooParseError(parsers.ParseError):
            pass

        class FooParser(parsers.SingleResponseParser):

            supported_artifacts = ["Foo"]

            def ParseResponse(
                self,
                knowledge_base: rdf_client.KnowledgeBase,
                response: rdf_client_fs.StatEntry,
            ) -> Iterable[rdfvalue.RDFString]:
                del knowledge_base, response  # Unused.
                raise FooParseError("Lorem ipsum.")

        with parser_test_lib._ParserContext("Foo", FooParser):
            factory = parsers.ArtifactParserFactory("Foo")
            client_id = self.client_id
            knowledge_base = rdf_client.KnowledgeBase()

            applicator = artifact.ParserApplicator(factory, client_id,
                                                   knowledge_base)
            applicator.Apply([rdf_client_fs.StatEntry()])

            errors = list(applicator.Errors())
            self.assertLen(errors, 1)
            self.assertIsInstance(errors[0], FooParseError)

            responses = list(applicator.Responses())
            self.assertEmpty(responses)
Ejemplo n.º 6
0
  def testAllParsers(self):

    class FooParser(parsers.SingleFileParser[None]):

      supported_artifacts = ["Quux"]

      def ParseFile(
          self,
          knowledge_base: rdf_client.KnowledgeBase,
          pathspec: rdf_paths.PathSpec,
          filedesc: IO[bytes],
      ):
        raise NotImplementedError()

    class BarParser(parsers.MultiResponseParser[None]):

      supported_artifacts = ["Quux"]

      def ParseResponses(
          self,
          knowledge_base: rdf_client.KnowledgeBase,
          responses: Iterable[rdfvalue.RDFValue],
      ) -> Iterator[None]:
        raise NotImplementedError()

    parsers.SINGLE_FILE_PARSER_FACTORY.Register("Foo", FooParser)
    parsers.MULTI_RESPONSE_PARSER_FACTORY.Register("Bar", BarParser)

    quux_factory = parsers.ArtifactParserFactory("Quux")
    quux_parsers = quux_factory.AllParserTypes()
    self.assertCountEqual(quux_parsers, [FooParser, BarParser])
Ejemplo n.º 7
0
    def testApplyMultipleParsersError(self):
        class QuuxParseError(parsers.ParseError):
            pass

        class QuuxParser(parsers.MultiResponseParser):

            supported_artifacts = ["Quux"]

            def ParseResponses(
                self,
                knowledge_base: rdf_client.KnowledgeBase,
                responses: Collection[rdf_client_fs.StatEntry],
            ) -> Iterable[rdfvalue.RDFInteger]:
                del knowledge_base, responses  # Unused.
                raise QuuxParseError("Lorem ipsum.")

        with parser_test_lib._ParserContext("Quux", QuuxParser):
            factory = parsers.ArtifactParserFactory("Quux")
            client_id = self.client_id
            knowledge_base = rdf_client.KnowledgeBase()

            applicator = artifact.ParserApplicator(factory, client_id,
                                                   knowledge_base)
            applicator.Apply([rdf_client_fs.StatEntry()])

            errors = list(applicator.Errors())
            self.assertLen(errors, 1)
            self.assertIsInstance(errors[0], QuuxParseError)

            responses = list(applicator.Responses())
            self.assertEmpty(responses)
Ejemplo n.º 8
0
    def testApplySingleResponseSuccessful(self):
        class FooParser(parsers.SingleResponseParser):

            supported_artifacts = ["Foo"]

            def ParseResponse(
                self,
                knowledge_base: rdf_client.KnowledgeBase,
                response: rdf_client_fs.StatEntry,
            ) -> Iterable[rdfvalue.RDFString]:
                return [
                    rdfvalue.RDFString(
                        f"{knowledge_base.os}:{response.st_dev}")
                ]

        with parser_test_lib._ParserContext("Foo", FooParser):
            factory = parsers.ArtifactParserFactory("Foo")
            client_id = self.client_id
            knowledge_base = rdf_client.KnowledgeBase(os="Redox")

            applicator = artifact.ParserApplicator(factory, client_id,
                                                   knowledge_base)
            applicator.Apply([rdf_client_fs.StatEntry(st_dev=1337)])

            errors = list(applicator.Errors())
            self.assertEmpty(errors)

            responses = list(applicator.Responses())
            self.assertEqual(responses, ["Redox:1337"])
Ejemplo n.º 9
0
    def testSingleFileResponse(self):
        class NorfParser(parsers.SingleFileParser):

            supported_artifacts = ["Norf"]

            def ParseFile(
                self,
                knowledge_base: rdf_client.KnowledgeBase,
                pathspec: rdf_paths.PathSpec,
                filedesc: file_store.BlobStream,
            ) -> Iterable[rdfvalue.RDFBytes]:
                del knowledge_base, pathspec  # Unused.
                return [rdfvalue.RDFBytes(filedesc.Read())]

        with parser_test_lib._ParserContext("Norf", NorfParser):
            factory = parsers.ArtifactParserFactory("Norf")
            client_id = self.client_id
            knowledge_base = rdf_client.KnowledgeBase()

            stat_entry = rdf_client_fs.StatEntry()
            stat_entry.pathspec.path = "foo/bar/baz"
            stat_entry.pathspec.pathtype = rdf_paths.PathSpec.PathType.OS
            self._WriteFile(stat_entry.pathspec.path, b"4815162342")

            applicator = artifact.ParserApplicator(factory, client_id,
                                                   knowledge_base)
            applicator.Apply([stat_entry])

            errors = list(applicator.Errors())
            self.assertEmpty(errors)

            responses = list(applicator.Responses())
            self.assertLen(responses, 1)
            self.assertEqual(responses[0], b"4815162342")
Ejemplo n.º 10
0
    def testApplyMultiResponseSuccess(self):
        class QuuxParser(parsers.MultiResponseParser):

            supported_artifacts = ["Quux"]

            def ParseResponses(
                self,
                knowledge_base: rdf_client.KnowledgeBase,
                responses: Collection[rdf_client_fs.StatEntry],
            ) -> Iterable[rdfvalue.RDFInteger]:
                return [stat_entry.st_dev for stat_entry in responses]

        with parser_test_lib._ParserContext("Quux", QuuxParser):
            factory = parsers.ArtifactParserFactory("Quux")
            client_id = self.client_id
            knowledge_base = rdf_client.KnowledgeBase()

            applicator = artifact.ParserApplicator(factory, client_id,
                                                   knowledge_base)
            applicator.Apply([
                rdf_client_fs.StatEntry(st_dev=42),
                rdf_client_fs.StatEntry(st_dev=1337),
            ])

            errors = list(applicator.Errors())
            self.assertEmpty(errors)

            responses = list(applicator.Responses())
            self.assertCountEqual(responses, [42, 1337])
Ejemplo n.º 11
0
  def _ParseResponses(self, responses, artifact_name, source):
    """Create a result parser sending different arguments for diff parsers.

    Args:
      responses: A list of responses.
      artifact_name: Name of the artifact that generated the responses.
      source: The source responsible for producing the responses.
    """
    artifact_return_types = self._GetArtifactReturnTypes(source)

    if self.args.apply_parsers:
      parser_factory = parsers.ArtifactParserFactory(artifact_name)
      results = artifact.ApplyParsersToResponses(parser_factory, responses,
                                                 self)
    else:
      results = responses

    # Increment artifact result count in flow progress.
    progress = self._GetOrInsertArtifactProgress(artifact_name)
    progress.num_results += len(results)

    for result in results:
      result_type = result.__class__.__name__
      if result_type == "Anomaly":
        self.SendReply(result)
      elif (not artifact_return_types or result_type in artifact_return_types):
        self.state.response_count += 1
        self.SendReply(result, tag="artifact:%s" % artifact_name)
Ejemplo n.º 12
0
    def testSingleFileParsers(self):
        class FooParser(parsers.SingleFileParser):

            supported_artifacts = ["Bar"]

            def ParseFile(self, knowledge_base, pathspec, filedesc):
                raise NotImplementedError()

        parsers.SINGLE_FILE_PARSER_FACTORY.Register("Foo", FooParser)

        bar_factory = parsers.ArtifactParserFactory("Bar")
        bar_parsers = bar_factory.SingleFileParsers()
        self.assertCountEqual(map(type, bar_parsers), [FooParser])

        baz_factory = parsers.ArtifactParserFactory("Baz")
        baz_parsers = baz_factory.SingleFileParsers()
        self.assertCountEqual(map(type, baz_parsers), [])
Ejemplo n.º 13
0
    def testMultiFileSuccess(self):
        class ThudParser(parsers.MultiFileParser):

            supported_artifacts = ["Thud"]

            def ParseFiles(
                self,
                knowledge_base: rdf_client.KnowledgeBase,
                pathspecs: Collection[rdf_paths.PathSpec],
                filedescs: Collection[file_store.BlobStream],
            ) -> Iterable[rdf_protodict.Dict]:
                results = []
                for pathspec, filedesc in zip(pathspecs, filedescs):
                    result = rdf_protodict.Dict()
                    result["path"] = pathspec.path
                    result["content"] = filedesc.Read()
                    results.append(result)
                return results

        with parser_test_lib._ParserContext("Thud", ThudParser):
            factory = parsers.ArtifactParserFactory("Thud")
            client_id = self.client_id
            knowledge_base = rdf_client.KnowledgeBase()

            stat_entry_foo = rdf_client_fs.StatEntry()
            stat_entry_foo.pathspec.path = "quux/foo"
            stat_entry_foo.pathspec.pathtype = rdf_paths.PathSpec.PathType.OS
            self._WriteFile(stat_entry_foo.pathspec.path, b"FOO")

            stat_entry_bar = rdf_client_fs.StatEntry()
            stat_entry_bar.pathspec.path = "quux/bar"
            stat_entry_bar.pathspec.pathtype = rdf_paths.PathSpec.PathType.OS
            self._WriteFile(stat_entry_bar.pathspec.path, b"BAR")

            applicator = artifact.ParserApplicator(factory, client_id,
                                                   knowledge_base)
            applicator.Apply([stat_entry_foo, stat_entry_bar])

            errors = list(applicator.Errors())
            self.assertEmpty(errors)

            responses = list(applicator.Responses())
            self.assertLen(responses, 2)
            self.assertEqual(responses[0], {
                "path": "quux/foo",
                "content": b"FOO"
            })
            self.assertEqual(responses[1], {
                "path": "quux/bar",
                "content": b"BAR"
            })
Ejemplo n.º 14
0
  def testSingleResponseAndSingleFileParser(self):

    class FooParser(parsers.SingleResponseParser[rdfvalue.RDFString]):

      supported_artifacts = ["Quux"]

      def ParseResponse(
          self,
          knowledge_base: rdf_client.KnowledgeBase,
          response: rdfvalue.RDFValue,
      ) -> Iterator[rdfvalue.RDFString]:
        del knowledge_base  # Unused.

        if not isinstance(response, rdfvalue.RDFString):
          raise TypeError(f"Unexpected response type: {type(response)}")

        yield rdfvalue.RDFString(f"FOO-{response}")

    class BarParser(parsers.SingleFileParser[rdfvalue.RDFString]):

      supported_artifacts = ["Quux"]

      def ParseFile(
          self,
          knowledge_base: rdf_client.KnowledgeBase,
          pathspec: rdf_paths.PathSpec,
          filedesc: IO[bytes],
      ) -> Iterator[rdfvalue.RDFString]:
        del knowledge_base, pathspec, filedesc  # Unused.
        yield rdfvalue.RDFString("BAR")

    with parser_test_lib._ParserContext("Foo", FooParser):
      with parser_test_lib._ParserContext("Bar", BarParser):
        factory = parsers.ArtifactParserFactory("Quux")
        knowledge_base = rdf_client.KnowledgeBase()

        applicator = artifact.ParserApplicator(
            factory, client_id=self.client_id, knowledge_base=knowledge_base)

        applicator.Apply([
            rdfvalue.RDFString("THUD"),
            rdfvalue.RDFString("BLARGH"),
        ])

        responses = list(applicator.Responses())
        self.assertLen(responses, 2)
        self.assertEqual(responses[0], rdfvalue.RDFString("FOO-THUD"))
        self.assertEqual(responses[1], rdfvalue.RDFString("FOO-BLARGH"))
Ejemplo n.º 15
0
  def testMultiResponseParserNames(self):

    class FooParser(parsers.MultiResponseParser[None]):

      supported_artifacts = ["Quux"]

      def ParseResponses(
          self,
          knowledge_base: rdf_client.KnowledgeBase,
          responses: Iterable[rdfvalue.RDFValue],
      ) -> Iterator[None]:
        raise NotImplementedError()

    with parser_test_lib._ParserContext("Foo", FooParser):
      quux_factory = parsers.ArtifactParserFactory("Quux")
      self.assertEqual(list(quux_factory.MultiResponseParserNames()), ["Foo"])
Ejemplo n.º 16
0
def GetArtifactParserDependencies(rdf_artifact):
    """Return the set of knowledgebase path dependencies required by the parser.

  Args:
    rdf_artifact: RDF artifact object.

  Returns:
    A set of strings for the required kb objects e.g.
    ["users.appdata", "systemroot"]
  """
    factory = parsers.ArtifactParserFactory(str(rdf_artifact.name))

    deps = set()
    for p in factory.AllParsers():
        deps.update(p.knowledgebase_dependencies)
    return deps
Ejemplo n.º 17
0
  def testSingleResponseAndSingleFileParserWithStatResponse(self):

    class FooParser(parsers.SingleResponseParser[rdfvalue.RDFString]):

      supported_artifacts = ["Quux"]

      def ParseResponse(
          self,
          knowledge_base: rdf_client.KnowledgeBase,
          response: rdfvalue.RDFValue,
      ) -> Iterator[rdfvalue.RDFString]:
        del knowledge_base  # Unused.

        if not isinstance(response, rdf_client_fs.StatEntry):
          raise TypeError(f"Unexpected response type: {type(response)}")

        yield rdfvalue.RDFString(f"PATH('{response.pathspec.path}')")

    class BarParser(parsers.SingleFileParser[rdfvalue.RDFString]):

      supported_artifacts = ["Quux"]

      def ParseFile(
          self,
          knowledge_base: rdf_client.KnowledgeBase,
          pathspec: rdf_paths.PathSpec,
          filedesc: IO[bytes],
      ) -> Iterator[rdfvalue.RDFString]:
        raise NotImplementedError()

    with parser_test_lib._ParserContext("Foo", FooParser):
      with parser_test_lib._ParserContext("Bar", BarParser):
        factory = parsers.ArtifactParserFactory("Quux")
        knowledge_base = rdf_client.KnowledgeBase()

        stat_entry = rdf_client_fs.StatEntry()
        stat_entry.pathspec.path = "foo/bar/baz"
        stat_entry.pathspec.pathtype = rdf_paths.PathSpec.PathType.OS

        applicator = artifact.ParserApplicator(
            factory, client_id=self.client_id, knowledge_base=knowledge_base)

        applicator.Apply([stat_entry])

        responses = list(applicator.Responses())
        self.assertLen(responses, 1)
        self.assertEqual(responses[0], "PATH('foo/bar/baz')")
Ejemplo n.º 18
0
  def testMultiFileParserNames(self):

    class FooParser(parsers.MultiFileParser[None]):

      supported_artifacts = ["Quux"]

      def ParseFiles(
          self,
          knowledge_base: rdf_client.KnowledgeBase,
          pathspecs: Iterable[rdf_paths.PathSpec],
          filedescs: Iterable[IO[bytes]],
      ) -> Iterator[None]:
        raise NotImplementedError()

    with parser_test_lib._ParserContext("Foo", FooParser):
      quux_factory = parsers.ArtifactParserFactory("Quux")
      self.assertEqual(list(quux_factory.MultiFileParserNames()), ["Foo"])
Ejemplo n.º 19
0
  def _CollectArtifact(self, artifact, apply_parsers):
    """Returns an `CollectedArtifact` rdf object for the requested artifact."""
    artifact_result = rdf_artifacts.CollectedArtifact(name=artifact.name)

    if apply_parsers:
      parser_factory = parsers.ArtifactParserFactory(str(artifact.name))
    else:
      parser_factory = None

    for source_result_list in self._ProcessSources(artifact.sources,
                                                   parser_factory):
      for response in source_result_list:
        action_result = rdf_artifacts.ClientActionResult()
        action_result.type = response.__class__.__name__
        action_result.value = response
        artifact_result.action_results.append(action_result)
        self.UpdateKnowledgeBase(response, artifact.provides)

    return artifact_result
Ejemplo n.º 20
0
    def testAllParsers(self):
        class FooParser(parsers.SingleFileParser):

            supported_artifacts = ["Quux"]

            def ParseFile(self, knowledge_base, pathspec, filedesc):
                raise NotImplementedError()

        class BarParser(parsers.MultiResponseParser):

            supported_artifacts = ["Quux"]

            def ParseResponses(self, knowledge_base, responses):
                raise NotImplementedError()

        parsers.SINGLE_FILE_PARSER_FACTORY.Register("Foo", FooParser)
        parsers.MULTI_RESPONSE_PARSER_FACTORY.Register("Bar", BarParser)

        quux_factory = parsers.ArtifactParserFactory("Quux")
        quux_parsers = quux_factory.AllParsers()
        self.assertCountEqual(map(type, quux_parsers), [FooParser, BarParser])
Ejemplo n.º 21
0
  def BuildArtifactDescriptors(self, artifacts_list):
    result = []
    for artifact_val in artifacts_list:
      descriptor = rdf_artifacts.ArtifactDescriptor(
          artifact=artifact_val,
          dependencies=sorted(
              artifact_registry.GetArtifactDependencies(artifact_val)),
          path_dependencies=sorted(
              artifact_registry.GetArtifactPathDependencies(artifact_val)),
          error_message=artifact_val.error_message,
          is_custom=artifact_val.loaded_from.startswith("datastore:"))

      factory = parsers.ArtifactParserFactory(str(artifact_val.name))
      for parser in factory.AllParsers():
        parser_cls = type(parser)
        descriptor.processors.append(
            rdf_artifacts.ArtifactProcessorDescriptor.FromParser(parser_cls))

      result.append(descriptor)

    return result
Ejemplo n.º 22
0
  def _RunProcessors(self, artifact_name, responses):
    """Manages processing of raw data from the artifact collection.

    The raw data and parsed results are stored in different result contexts:
    Anomaly, Parser and Raw. Demuxing these results makes the specific data
    types available to checks working in different contexts.

    Then, iterate over the parsers that should be applied to the raw data and
    map rdfvalues to the Parse context.

    Args:
      artifact_name: The name of the artifact being processed as a string.
      responses: A list of RDF value responses.
    """
    parser_factory = parsers.ArtifactParserFactory(artifact_name)
    artifact_data = self.state.host_data.get(artifact_name)

    results = artifact.ApplyParsersToResponses(parser_factory, responses, self)
    for result in results:
      if isinstance(result, rdf_anomaly.Anomaly):
        artifact_data["ANOMALY"].append(result)
      else:
        artifact_data["PARSER"].append(result)
Ejemplo n.º 23
0
    def testMultiFileError(self):
        class ThudParseError(parsers.ParseError):
            pass

        class ThudParser(parsers.MultiFileParser):

            supported_artifacts = ["Thud"]

            def ParseFiles(
                self,
                knowledge_base: rdf_client.KnowledgeBase,
                pathspecs: Collection[rdf_paths.PathSpec],
                filedescs: Collection[file_store.BlobStream],
            ) -> Iterable[rdf_protodict.Dict]:
                del knowledge_base, pathspecs, filedescs  # Unused.
                raise ThudParseError("Lorem ipsum.")

        with parser_test_lib._ParserContext("Thud", ThudParser):
            factory = parsers.ArtifactParserFactory("Thud")
            client_id = self.client_id
            knowledge_base = rdf_client.KnowledgeBase()

            stat_entry = rdf_client_fs.StatEntry()
            stat_entry.pathspec.path = "foo/bar/baz"
            stat_entry.pathspec.pathtype = rdf_paths.PathSpec.PathType.OS
            self._WriteFile(stat_entry.pathspec.path, b"\xff\x00\xff")

            applicator = artifact.ParserApplicator(factory, client_id,
                                                   knowledge_base)
            applicator.Apply([stat_entry])

            errors = list(applicator.Errors())
            self.assertLen(errors, 1)
            self.assertIsInstance(errors[0], ThudParseError)

            responses = list(applicator.Responses())
            self.assertEmpty(responses)
Ejemplo n.º 24
0
    def Handle(
        self,
        args: ApiListParsedFlowResultsArgs,
        token: access_control.ACLToken,
    ) -> ApiListParsedFlowResultsResult:
        client_id = str(args.client_id)
        flow_id = str(args.flow_id)

        flow_obj = data_store.REL_DB.ReadFlowObject(client_id, flow_id)
        if flow_obj.flow_class_name != collectors.ArtifactCollectorFlow.__name__:
            message = "Not an artifact-collector flow: {}"
            raise ValueError(message.format(flow_obj.flow_class_name))

        if flow_obj.args.apply_parsers:
            message = "Flow already parsed its results"
            raise ValueError(message)

        flow_results = data_store.REL_DB.ReadFlowResults(client_id=client_id,
                                                         flow_id=flow_id,
                                                         offset=args.offset,
                                                         count=args.count)

        # We determine results collection timestamp as the maximum of timestamps of
        # individual flow results. We cannot use just the flow timestamp for this,
        # because flows can be modified, affecting the timestamp. We also don't want
        # to use flow start time, because it can be to "early" to do parsing.
        if flow_results:
            flow_results_timestamp = max([_.timestamp for _ in flow_results])
        else:
            flow_results_timestamp = None

        flow_results_by_artifact = {}

        for flow_result in flow_results:
            artifact_name_match = self._TAG_ARTIFACT_NAME.match(
                flow_result.tag)
            if artifact_name_match is None:
                continue

            artifact_name = artifact_name_match["name"]
            artifact_results = flow_results_by_artifact.setdefault(
                artifact_name, [])
            artifact_results.append(flow_result)

        knowledge_base = flow_obj.persistent_data["knowledge_base"]

        result = ApiListParsedFlowResultsResult()

        for artifact_name, flow_results in flow_results_by_artifact.items():
            factory = parsers.ArtifactParserFactory(artifact_name)

            applicator = artifact.ParserApplicator(
                factory,
                client_id=client_id,
                knowledge_base=knowledge_base,
                timestamp=flow_results_timestamp)
            applicator.Apply(
                [flow_result.payload for flow_result in flow_results])

            for response in applicator.Responses():
                item = ApiFlowResult()
                item.payload_type = response.__class__.__name__
                item.payload = response
                item.tag = f"artifact:{artifact_name}"
                result.items.Append(item)

            result.errors.Extend(map(str, applicator.Errors()))

        return result