def ExecuteCommandFromClient(command): """Executes one of the predefined commands. Args: command: An `ExecuteRequest` object. Yields: `rdf_client_action.ExecuteResponse` objects. """ cmd = command.cmd args = command.args time_limit = command.time_limit res = client_utils_common.Execute(cmd, args, time_limit) (stdout, stderr, status, time_used) = res # Limit output to 10MB so our response doesn't get too big. stdout = stdout[:10 * 1024 * 1024] stderr = stderr[:10 * 1024 * 1024] yield rdf_client_action.ExecuteResponse( request=command, stdout=stdout, stderr=stderr, exit_status=status, # We have to return microseconds. time_used=int(1e6 * time_used))
def testLaunchBinaryFlowResultsHaveReadableStdOutAndStdErr(self): flow_urn = flow.StartAFF4Flow( client_id=self.client_id, flow_name=gui_test_lib.RecursiveTestFlow.__name__, token=self.token) stderr = "Oh, ok, this is just a string 昨" stdout = "\00\00\00\00" response = rdf_client_action.ExecuteResponse( stderr=stderr.encode("utf-8"), stdout=stdout.encode("utf-8")) with data_store.DB.GetMutationPool() as pool: flow.GRRFlow.ResultCollectionForFID(flow_urn).Add( response, mutation_pool=pool) self.Open("/#/clients/%s/flows/%s/results" % (self.client_id, flow_urn.Basename())) # jQuery treats the backslash ('\') character as a special one, hence we # have to escape it twice: once for Javascript itself and second time # for jQuery. self.WaitUntil( self.IsElementPresent, r"css=grr-flow-inspector:contains('Oh, ok, " r"this is just a string \\\\xe6\\\\x98\\\\xa8')") self.WaitUntil( self.IsElementPresent, r"css=grr-flow-inspector:contains('\\\\x00\\\\x00\\\\x00\\\\x00')")
def testLaunchBinaryFlowResultsHaveReadableStdOutAndStdErr(self): flow_id = flow_test_lib.StartFlow(gui_test_lib.RecursiveTestFlow, client_id=self.client_id) stderr = "Oh, ok, this is just a string 昨" stdout = "\00\00\00\00" response = rdf_client_action.ExecuteResponse( stderr=stderr.encode("utf-8"), stdout=stdout.encode("utf-8")) if data_store.RelationalDBEnabled(): data_store.REL_DB.WriteFlowResults([ rdf_flow_objects.FlowResult(client_id=self.client_id, flow_id=flow_id, payload=response) ]) else: with data_store.DB.GetMutationPool() as pool: flow.GRRFlow.ResultCollectionForFID( rdfvalue.RDFURN( self.client_id).Add("flows").Add(flow_id)).Add( response, mutation_pool=pool) self.Open("/#/clients/%s/flows/%s/results" % (self.client_id, flow_id)) # jQuery treats the backslash ('\') character as a special one, hence we # have to escape it twice: once for Javascript itself and second time # for jQuery. self.WaitUntil( self.IsElementPresent, r"css=grr-flow-inspector:contains('Oh, ok, " r"this is just a string \\\\xe6\\\\x98\\\\xa8')") self.WaitUntil( self.IsElementPresent, r"css=grr-flow-inspector:contains('\\\\x00\\\\x00\\\\x00\\\\x00')")
def testCmdArtifact(self): """Test the parsing of an Echo Command with a TestParser.""" client_test_lib.Command("/bin/echo", args=["1"]) processor = parser.Parser.GetClassesByArtifact( "TestEchoCmdArtifact")[0]() self.assertIsInstance(processor, TestEchoCmdParser) request = rdf_client_action.ExecuteRequest(cmd="/bin/echo", args=["1"]) res = client_utils_common.Execute(request.cmd, request.args) (stdout, stderr, status, time_used) = res response = rdf_client_action.ExecuteResponse(request=request, stdout=stdout, stderr=stderr, exit_status=status, time_used=int(1e6 * time_used)) path_type = rdf_paths.PathSpec.PathType.OS results = [] for res in artifact_collector.ParseSingleResponse( processor, response, {}, path_type): results.append(res) self.assertEqual(len(results), 1) self.assertIsInstance(results[0], rdf_client.SoftwarePackage) self.assertEqual(results[0].description, "1\n")
def testExportsValueCorrectly(self): sample = rdf_client_action.ExecuteResponse( request=rdf_client_action.ExecuteRequest( cmd="some cmd", args=["-foo", "-bar"], time_limit=42, ), exit_status=-1, stdout=b"stdout", stderr=b"stderr", time_used=420, ) converter = execute_response.ExecuteResponseConverter() converted = list(converter.Convert(self.metadata, sample)) self.assertLen(converted, 1) c = converted[0] self.assertEqual(c.metadata, self.metadata) self.assertEqual(c.cmd, "some cmd") self.assertEqual(c.args, "-foo -bar") self.assertEqual(c.exit_status, -1) self.assertEqual(c.stdout, b"stdout") self.assertEqual(c.stderr, b"stderr") self.assertEqual(c.time_used_us, 420)
def ExecuteCommand( self, args: rdf_client_action.ExecuteRequest, ) -> Iterable[rdf_client_action.ExecuteResponse]: response = rdf_client_action.ExecuteResponse() response.stdout = " ".join(args.args).encode("utf-8") response.exit_status = 0 return [response]
def ExecuteCommand( self, args: rdf_client_action.ExecuteRequest, ) -> Iterable[rdf_client_action.ExecuteResponse]: if args.cmd != "/bin/echo": raise ValueError(f"Unsupported command: {args.cmd}") stdout = " ".join(args.args).encode("utf-8") return [rdf_client_action.ExecuteResponse(stdout=stdout)]
def ParseResponse( self, knowledge_base: rdf_client.KnowledgeBase, response: rdf_client_action.ExecuteResponse, ) -> Iterable[rdf_client_action.ExecuteResponse]: precondition.AssertType(response, rdf_client_action.ExecuteResponse) parsed_response = rdf_client_action.ExecuteResponse() parsed_response.stdout = response.stdout parsed_response.stderr = knowledge_base.os.encode("utf-8") return [parsed_response]
def testOSXSPHardwareDataTypeParserInvalidInput(self): parser = osx_file_parser.OSXSPHardwareDataTypeParser() response = rdf_client_action.ExecuteResponse() response.request.cmd = "/usr/sbin/system_profiler" response.request.args = ["-xml", "SPHardwareDataType"] response.stdout = "chrząszcz brzmi w trzcinie".encode("utf-8") response.stdout = b"" response.exit_status = 0 with self.assertRaises(parsers.ParseError) as context: list(parser.ParseResponse(None, response)) exception = context.exception self.assertIsInstance(exception.cause, plistlib.InvalidFileException)
def testExportsEmptyValueCorrectly(self): sample = rdf_client_action.ExecuteResponse() converter = execute_response.ExecuteResponseConverter() converted = list(converter.Convert(self.metadata, sample)) self.assertLen(converted, 1) c = converted[0] self.assertEqual(c.metadata, self.metadata) self.assertEqual(c.cmd, "") self.assertEqual(c.args, "") self.assertEqual(c.exit_status, 0) self.assertEqual(c.stdout, b"") self.assertEqual(c.stderr, b"") self.assertEqual(c.time_used_us, 0)
def ParseResponse( self, knowledge_base: rdf_client.KnowledgeBase, response: rdf_client_action.ExecuteResponse, ) -> Iterable[rdf_client_action.ExecuteResponse]: del knowledge_base # Unused. if not isinstance(response, rdf_client_action.ExecuteResponse): raise TypeError( f"Unexpected response type: {type(response)}") parsed_response = rdf_client_action.ExecuteResponse() parsed_response.stdout = response.stderr return [parsed_response]
def Start(cls, command): cmd = command.cmd args = command.args time_limit = command.time_limit res = client_utils_common.Execute(cmd, args, time_limit) (stdout, stderr, status, time_used) = res # Limit output to 10MB so our response doesn't get too big. stdout = stdout[:10 * 1024 * 1024] stderr = stderr[:10 * 1024 * 1024] yield rdf_client_action.ExecuteResponse( request=command, stdout=stdout, stderr=stderr, exit_status=status, # We have to return microseconds. time_used=int(1e6 * time_used))
def testListFlowApplicableParsers(self): client_id = self.SetupClient(0) flow_id = "4815162342ABCDEF" flow = rdf_flow_objects.Flow() flow.client_id = client_id flow.flow_id = flow_id flow.flow_class_name = collectors.ArtifactCollectorFlow.__name__ flow.args = rdf_artifacts.ArtifactCollectorFlowArgs( apply_parsers=False) data_store.REL_DB.WriteFlowObject(flow) result = rdf_flow_objects.FlowResult() result.client_id = client_id result.flow_id = flow_id result.tag = "artifact:Fake" result.payload = rdf_client_action.ExecuteResponse(stderr=b"foobar") data_store.REL_DB.WriteFlowResults([result]) class FakeParser(parser.SingleResponseParser[None]): supported_artifacts = ["Fake"] def ParseResponse( self, knowledge_base: rdf_client.KnowledgeBase, response: rdfvalue.RDFValue, ) -> Iterable[None]: raise NotImplementedError() with parser_test_lib._ParserContext("Fake", FakeParser): results = self.api.Client(client_id).Flow( flow_id).ListApplicableParsers() self.assertLen(results.parsers, 1) result = results.parsers[0] self.assertEqual(result.name, "Fake") self.assertEqual(result.type, flow_pb2.ApiParserDescriptor.SINGLE_RESPONSE)
def testLaunchBinaryFlowResultsHaveReadableStdOutAndStdErr(self): flow_id = flow.StartFlow( client_id=self.client_id, flow_cls=gui_test_lib.RecursiveTestFlow) stderr = "Oh, ok, this is just a string 昨" stdout = "\00\00\00\00" response = rdf_client_action.ExecuteResponse( stderr=stderr.encode("utf-8"), stdout=stdout.encode("utf-8")) flow_result = rdf_flow_objects.FlowResult(tag="tag", payload=response) data_store.REL_DB.WriteFlowResults(self.client_id, flow_id, [flow_result]) self.Open("/#/clients/%s/flows/%s/results" % (self.client_id, flow_id)) # jQuery treats the backslash ('\') character as a special one, hence we # have to escape it twice: once for Javascript itself and second time # for jQuery. self.WaitUntil( self.IsElementPresent, r"css=grr-flow-inspector:contains('Oh, ok, " r"this is just a string \\\\xe6\\\\x98\\\\xa8')") self.WaitUntil( self.IsElementPresent, r"css=grr-flow-inspector:contains('\\\\x00\\\\x00\\\\x00\\\\x00')")
def testListParsedFlowResults(self): client_id = self.SetupClient(0) flow_id = "4815162342ABCDEF" flow = rdf_flow_objects.Flow() flow.client_id = client_id flow.flow_id = flow_id flow.flow_class_name = collectors.ArtifactCollectorFlow.__name__ flow.args = rdf_artifacts.ArtifactCollectorFlowArgs( apply_parsers=False) flow.persistent_data = {"knowledge_base": rdf_client.KnowledgeBase()} data_store.REL_DB.WriteFlowObject(flow) result = rdf_flow_objects.FlowResult() result.client_id = client_id result.flow_id = flow_id result.tag = "artifact:Echo" response = rdf_client_action.ExecuteResponse() response.stderr = "Lorem ipsum.".encode("utf-8") result.payload = response data_store.REL_DB.WriteFlowResults([result]) response = rdf_client_action.ExecuteResponse() response.stderr = "Dolor sit amet.".encode("utf-8") result.payload = response data_store.REL_DB.WriteFlowResults([result]) class StderrToStdoutParser( parser.SingleResponseParser[rdf_client_action.ExecuteResponse] ): supported_artifacts = ["Echo"] def ParseResponse( self, knowledge_base: rdf_client.KnowledgeBase, response: rdf_client_action.ExecuteResponse, ) -> Iterable[rdf_client_action.ExecuteResponse]: del knowledge_base # Unused. if not isinstance(response, rdf_client_action.ExecuteResponse): raise TypeError( f"Unexpected response type: {type(response)}") parsed_response = rdf_client_action.ExecuteResponse() parsed_response.stdout = response.stderr return [parsed_response] with parser_test_lib._ParserContext("StderrToStdout", StderrToStdoutParser): results = self.api.Client(client_id).Flow( flow_id).ListParsedResults() stdouts = [result.payload.stdout.decode("utf-8") for result in results] self.assertLen(stdouts, 2) self.assertEqual(stdouts[0], "Lorem ipsum.") self.assertEqual(stdouts[1], "Dolor sit amet.")