def testCopyHuntPreservesRuleType(self): self.StartHunt( description="model hunt", flow_runner_args=rdf_flow_runner.FlowRunnerArgs( flow_name=transfer.GetFile.__name__), flow_args=transfer.GetFileArgs(pathspec=rdf_paths.PathSpec( path="/tmp/evil.txt", pathtype=rdf_paths.PathSpec.PathType.NTFS, )), client_rule_set=foreman_rules.ForemanClientRuleSet(rules=[ foreman_rules.ForemanClientRule( rule_type=foreman_rules.ForemanClientRule.Type.OS, os=foreman_rules.ForemanOsClientRule(os_darwin=True)) ]), creator=self.token.username) self.Open("/#main=ManageHunts") self.Click("css=tr:contains('model hunt')") self.Click("css=button[name=CopyHunt]:not([disabled])") # Wait until dialog appears. self.WaitUntil(self.IsTextPresent, "What to run?") # Click on "Next" button self.Click("css=grr-new-hunt-wizard-form button.Next") self.WaitUntil(self.IsElementPresent, "css=grr-wizard-form:contains('Hunt parameters')") # Click on "Next" button. self.Click("css=grr-new-hunt-wizard-form button.Next") self.WaitUntil(self.IsTextPresent, "How to process results") # Click on "Next" button self.Click("css=grr-new-hunt-wizard-form button.Next") self.WaitUntil(self.IsTextPresent, "Where to run?") self.WaitUntil( self.IsElementPresent, "css=grr-new-hunt-wizard-form " "label:contains('Os darwin') ~ * input:checked")
def CreateSampleHunt(self, path=None, stopped=False, output_plugins=None, client_limit=0, client_count=10, token=None): token = token or self.token self.client_ids = self.SetupClients(client_count) self.hunt_urn = self.StartHunt( flow_runner_args=rdf_flow_runner.FlowRunnerArgs( flow_name=compatibility.GetName(transfer.GetFile)), flow_args=transfer.GetFileArgs(pathspec=rdf_paths.PathSpec( path=path or "/tmp/evil.txt", pathtype=rdf_paths.PathSpec.PathType.OS, )), client_rule_set=self._CreateForemanClientRuleSet(), output_plugins=output_plugins or [], client_rate=0, client_limit=client_limit, token=token, paused=stopped) return self.hunt_urn
def Run(self): acl_test_lib.CreateUser(self.token.username) client_id = self.SetupClient(0) runner_args = rdf_flow_runner.FlowRunnerArgs( flow_name=transfer.GetFile.__name__) flow_args = transfer.GetFileArgs(pathspec=rdf_paths.PathSpec( path="/tmp/evil.txt", pathtype=rdf_paths.PathSpec.PathType.OS)) client_mock = hunt_test_lib.SampleHuntMock() with test_lib.FakeTime(42): flow_urn = flow.StartAFF4Flow(client_id=client_id, args=flow_args, runner_args=runner_args, token=self.token) flow_test_lib.TestFlowHelper(flow_urn, client_mock=client_mock, client_id=client_id, token=self.token) self.Check("ListFlowResults", args=flow_plugin.ApiListFlowResultsArgs( client_id=client_id.Basename(), flow_id=flow_urn.Basename()), replace={flow_urn.Basename(): "W:ABCDEF"})
def testVariableHuntSchedulesAllFlowsOnStart(self): client_ids = self.SetupClients(10) hunt_obj = rdf_hunt_objects.Hunt(client_rate=0) hunt_obj.args.hunt_type = hunt_obj.args.HuntType.VARIABLE for index, pair in enumerate(collection.Batch(client_ids, 2)): hunt_obj.args.variable.flow_groups.append( rdf_hunt_objects.VariableHuntFlowGroup( client_ids=pair, flow_name=compatibility.GetName(transfer.GetFile), flow_args=transfer.GetFileArgs(pathspec=rdf_paths.PathSpec( path="/tmp/evil_%d.txt" % index, pathtype=rdf_paths.PathSpec.PathType.OS, )))) data_store.REL_DB.WriteHuntObject(hunt_obj) hunt.StartHunt(hunt_obj.hunt_id) hunt_counters = data_store.REL_DB.ReadHuntCounters(hunt_obj.hunt_id) self.assertEqual(hunt_counters.num_clients, 10) all_flows = data_store.REL_DB.ReadHuntFlows(hunt_obj.hunt_id, 0, sys.maxsize) self.assertCountEqual(client_ids, [f.client_id for f in all_flows]) for index, pair in enumerate(collection.Batch(client_ids, 2)): for client_id in pair: all_flows = data_store.REL_DB.ReadAllFlowObjects(client_id) self.assertLen(all_flows, 1) self.assertEqual(all_flows[0].flow_class_name, compatibility.GetName(transfer.GetFile)) self.assertEqual(all_flows[0].args.pathspec.path, "/tmp/evil_%d.txt" % index)
def _RunFlow(self, client_id): flow_args = transfer.GetFileArgs(pathspec=rdf_paths.PathSpec( path="/tmp/evil.txt", pathtype=rdf_paths.PathSpec.PathType.OS)) client_mock = hunt_test_lib.SampleHuntMock(failrate=2) if data_store.RelationalDBFlowsEnabled(): with test_lib.FakeTime(42): return flow_test_lib.StartAndRunFlow(transfer.GetFile, client_id=client_id, client_mock=client_mock, flow_args=flow_args) else: runner_args = rdf_flow_runner.FlowRunnerArgs( flow_name=transfer.GetFile.__name__) with test_lib.FakeTime(42): flow_urn = flow.StartAFF4Flow(client_id=client_id, args=flow_args, runner_args=runner_args, token=self.token) flow_test_lib.TestFlowHelper(flow_urn, client_mock=client_mock, client_id=client_id, token=self.token) return flow_urn.Basename()
def GetFileHuntArgs(self): return rdf_hunt_objects.HuntArguments.Standard( flow_name=compatibility.GetName(transfer.GetFile), flow_args=transfer.GetFileArgs(pathspec=rdf_paths.PathSpec( path="/tmp/evil.txt", pathtype=rdf_paths.PathSpec.PathType.OS, )))
def CreateSampleHunt(self, path=None, stopped=False, output_plugins=None, client_limit=0, client_count=10, token=None): token = token or self.token self.client_ids = self.SetupClients(client_count) with implementation.StartHunt( hunt_name=standard.GenericHunt.__name__, flow_runner_args=rdf_flow_runner.FlowRunnerArgs( flow_name=transfer.GetFile.__name__), flow_args=transfer.GetFileArgs(pathspec=rdf_paths.PathSpec( path=path or "/tmp/evil.txt", pathtype=rdf_paths.PathSpec.PathType.OS, )), client_rule_set=self._CreateForemanClientRuleSet(), output_plugins=output_plugins or [], client_rate=0, client_limit=client_limit, token=token) as hunt: if not stopped: hunt.Run() foreman_obj = foreman.GetForeman(token=token) for client_id in self.client_ids: foreman_obj.AssignTasksToClient(client_id.Basename()) self.hunt_urn = hunt.urn return aff4.FACTORY.Open(hunt.urn, mode="rw", token=token, age=aff4.ALL_TIMES)
def CreateHunt(self, flow_runner_args=None, flow_args=None, client_rule_set=None, original_object=None, client_rate=0, token=None, **kwargs): # Only initialize default flow_args value if default flow_runner_args value # is to be used. if not flow_runner_args: flow_args = (flow_args or transfer.GetFileArgs(pathspec=rdf_paths.PathSpec( path="/tmp/evil.txt", pathtype=rdf_paths.PathSpec.PathType.OS))) flow_runner_args = (flow_runner_args or rdf_flow_runner.FlowRunnerArgs( flow_name=transfer.GetFile.__name__)) client_rule_set = (client_rule_set or self._CreateForemanClientRuleSet()) return implementation.StartHunt( hunt_name=standard.GenericHunt.__name__, flow_runner_args=flow_runner_args, flow_args=flow_args, client_rule_set=client_rule_set, client_rate=client_rate, original_object=original_object, token=token or self.token, **kwargs)
def RunFlow(self, flow_name=None, plugins=None, flow_args=None, client_mock=None): runner_args = rdf_flow_runner.FlowRunnerArgs( flow_name=flow_name or transfer.GetFile.__name__, output_plugins=plugins) if flow_args is None: flow_args = transfer.GetFileArgs(pathspec=rdf_paths.PathSpec( path="/tmp/evil.txt", pathtype=rdf_paths.PathSpec.PathType.OS)) if client_mock is None: client_mock = hunt_test_lib.SampleHuntMock() flow_urn = flow.StartFlow(client_id=self.client_id, args=flow_args, runner_args=runner_args, token=self.token) flow_test_lib.TestFlowHelper(flow_urn, client_mock=client_mock, client_id=self.client_id, token=self.token) return flow_urn
def GetFileHuntArgs(self): args = transfer.GetFileArgs() args.pathspec.path = "/tmp/evil.txt" args.pathspec.pathtype = rdf_paths.PathSpec.PathType.OS return rdf_hunt_objects.HuntArguments.Standard( flow_name=compatibility.GetName(transfer.GetFile), flow_args=rdf_structs.AnyValue.Pack(args))
def testHuntModificationWorksCorrectly(self): """This tests running the hunt on some clients.""" with implementation.StartHunt( hunt_name=standard.GenericHunt.__name__, flow_runner_args=rdf_flow_runner.FlowRunnerArgs( flow_name=transfer.GetFile.__name__), flow_args=transfer.GetFileArgs( pathspec=rdf_paths.PathSpec( path="/tmp/evil.txt", pathtype=rdf_paths.PathSpec.PathType.OS),), client_rule_set=self._CreateForemanClientRuleSet(), client_limit=1, client_rate=0, token=self.token) as hunt: hunt.Run() # Forget about hunt object, we'll use AFF4 for everything. hunt_session_id = hunt.session_id hunt = None # Pretend to be the foreman now and dish out hunting jobs to all the # client.. self.AssignTasksToClients() # Run the hunt. client_mock = hunt_test_lib.SampleHuntMock() hunt_test_lib.TestHuntHelper(client_mock, self.client_ids, False, self.token) # Re-open the hunt to get fresh data. hunt_obj = aff4.FACTORY.Open( hunt_session_id, age=aff4.ALL_TIMES, token=self.token) # There should be only one client, due to the limit started, _, _ = hunt_obj.GetClientsCounts() self.assertEqual(started, 1) # Check the hunt is paused. self.assertEqual(hunt_obj.Get(hunt_obj.Schema.STATE), "PAUSED") with aff4.FACTORY.Open( hunt_session_id, mode="rw", token=self.token) as hunt_obj: runner = hunt_obj.GetRunner() runner.runner_args.client_limit = 10 runner.Start() # Pretend to be the foreman now and dish out hunting jobs to all the # clients. self.AssignTasksToClients() hunt_test_lib.TestHuntHelper(client_mock, self.client_ids, False, self.token) hunt_obj = aff4.FACTORY.Open( hunt_session_id, age=aff4.ALL_TIMES, token=self.token) # There should be only one client, due to the limit started, _, _ = hunt_obj.GetClientsCounts() self.assertEqual(started, 10)
def _AppendFlowRequest(self, flows, client_id, file_id): flows.Append( client_ids=["C.1%015d" % client_id], runner_args=rdf_flow_runner.FlowRunnerArgs( flow_name=transfer.GetFile.__name__), args=transfer.GetFileArgs( pathspec=rdf_paths.PathSpec( path="/tmp/evil%s.txt" % file_id, pathtype=rdf_paths.PathSpec.PathType.OS),))
def testResourceUsageStats(self): client_ids = self.SetupClients(10) with implementation.StartHunt( hunt_name=standard.GenericHunt.__name__, flow_runner_args=rdf_flow_runner.FlowRunnerArgs( flow_name=transfer.GetFile.__name__), flow_args=transfer.GetFileArgs( pathspec=rdf_paths.PathSpec( path="/tmp/evil.txt", pathtype=rdf_paths.PathSpec.PathType.OS, )), client_rule_set=self._CreateForemanClientRuleSet(), output_plugins=[], client_rate=0, token=self.token) as hunt: hunt.Run() self.AssignTasksToClients(client_ids=client_ids) client_mock = hunt_test_lib.SampleHuntMock() hunt_test_lib.TestHuntHelper(client_mock, client_ids, False, self.token) hunt = aff4.FACTORY.Open( hunt.urn, aff4_type=standard.GenericHunt, token=self.token) # This is called once for each state method. Each flow above runs the # Start and the StoreResults methods. usage_stats = hunt.context.usage_stats self.assertEqual(usage_stats.user_cpu_stats.num, 10) self.assertTrue(math.fabs(usage_stats.user_cpu_stats.mean - 5.5) < 1e-7) self.assertTrue( math.fabs(usage_stats.user_cpu_stats.std - 2.8722813) < 1e-7) self.assertEqual(usage_stats.system_cpu_stats.num, 10) self.assertTrue(math.fabs(usage_stats.system_cpu_stats.mean - 11) < 1e-7) self.assertTrue( math.fabs(usage_stats.system_cpu_stats.std - 5.7445626) < 1e-7) self.assertEqual(usage_stats.network_bytes_sent_stats.num, 10) self.assertTrue( math.fabs(usage_stats.network_bytes_sent_stats.mean - 16.5) < 1e-7) self.assertTrue( math.fabs(usage_stats.network_bytes_sent_stats.std - 8.61684396) < 1e-7) # NOTE: Not checking histograms here. RunningStatsTest tests that mean, # standard deviation and histograms are calculated correctly. Therefore # if mean/stdev values are correct histograms should be ok as well. self.assertLen(usage_stats.worst_performers, 10) prev = usage_stats.worst_performers[0] for p in usage_stats.worst_performers[1:]: self.assertTrue( prev.cpu_usage.user_cpu_time + prev.cpu_usage.system_cpu_time > p.cpu_usage.user_cpu_time + p.cpu_usage.system_cpu_time) prev = p
def _RunFlow(self, client_id): flow_args = transfer.GetFileArgs(pathspec=rdf_paths.PathSpec( path="/tmp/evil.txt", pathtype=rdf_paths.PathSpec.PathType.OS)) client_mock = hunt_test_lib.SampleHuntMock(failrate=2) with test_lib.FakeTime(42): return flow_test_lib.StartAndRunFlow(transfer.GetFile, client_id=client_id, client_mock=client_mock, flow_args=flow_args)
def CreateHunt(self, flow_runner_args=None, flow_args=None, client_rule_set=None, original_object=None, client_rate=0, duration=None, token=None, **kwargs): # Only initialize default flow_args value if default flow_runner_args value # is to be used. if not flow_runner_args: flow_args = ( flow_args or transfer.GetFileArgs( pathspec=rdf_paths.PathSpec( path="/tmp/evil.txt", pathtype=rdf_paths.PathSpec.PathType.OS))) flow_runner_args = ( flow_runner_args or rdf_flow_runner.FlowRunnerArgs(flow_name=transfer.GetFile.__name__)) client_rule_set = (client_rule_set or self._CreateForemanClientRuleSet()) if data_store.RelationalDBEnabled(): token = token or self.token hunt_args = rdf_hunt_objects.HuntArguments( hunt_type=rdf_hunt_objects.HuntArguments.HuntType.STANDARD, standard=rdf_hunt_objects.HuntArgumentsStandard( flow_name=flow_runner_args.flow_name, flow_args=flow_args)) hunt_obj = rdf_hunt_objects.Hunt( creator=token.username, client_rule_set=client_rule_set, original_object=original_object, client_rate=client_rate, duration=duration, args=hunt_args, **kwargs) hunt.CreateHunt(hunt_obj) return hunt_obj.hunt_id return implementation.StartHunt( hunt_name=standard.GenericHunt.__name__, flow_runner_args=flow_runner_args, flow_args=flow_args, client_rule_set=client_rule_set, client_rate=client_rate, original_object=original_object, token=token or self.token, **kwargs)
def testHuntExpiration(self): """This tests that hunts with a client limit terminate correctly.""" with test_lib.FakeTime(1000): with implementation.StartHunt( hunt_name=standard.GenericHunt.__name__, flow_runner_args=rdf_flow_runner.FlowRunnerArgs( flow_name=transfer.GetFile.__name__), flow_args=transfer.GetFileArgs( pathspec=rdf_paths.PathSpec( path="/tmp/evil.txt", pathtype=rdf_paths.PathSpec.PathType.OS)), client_rule_set=self._CreateForemanClientRuleSet(), client_limit=5, expiry_time=rdfvalue.Duration("1000s"), token=self.token) as hunt: hunt.Run() # Pretend to be the foreman now and dish out hunting jobs to all the # clients (Note we have 10 clients here). self.AssignTasksToClients() hunt_obj = aff4.FACTORY.Open( hunt.session_id, age=aff4.ALL_TIMES, token=self.token) self.assertEqual(hunt_obj.Get(hunt_obj.Schema.STATE), "STARTED") # Now advance the time such that the hunt expires. time.time = lambda: 5000 # Run the hunt. client_mock = hunt_test_lib.SampleHuntMock() hunt_test_lib.TestHuntHelper( client_mock, self.client_ids, check_flow_errors=False, token=self.token) # No client should be processed since the hunt is expired. started, finished, errors = hunt_obj.GetClientsCounts() self.assertEqual(started, 0) self.assertEqual(finished, 0) self.assertEqual(errors, 0) hunt_obj = aff4.FACTORY.Open( hunt.session_id, age=aff4.ALL_TIMES, token=self.token) # Hunts are automatically stopped when they expire. self.assertEqual(hunt_obj.Get(hunt_obj.Schema.STATE), "COMPLETED")
def testPageTitleReflectsSelectedFlow(self): pathspec = rdf_paths.PathSpec( path=os.path.join(self.base_path, "test.plist"), pathtype=rdf_paths.PathSpec.PathType.OS) args = flows_transfer.GetFileArgs(pathspec=pathspec) flow_id = flow_test_lib.StartFlow( flows_transfer.GetFile, self.client_id, flow_args=args, creator=self.token.username) self.Open("/#/clients/%s/flows/" % self.client_id) self.WaitUntilEqual("GRR | %s | Flows" % self.client_id, self.GetPageTitle) self.Click("css=td:contains('GetFile')") self.WaitUntilEqual("GRR | %s | %s" % (self.client_id, flow_id), self.GetPageTitle)
def CreateSampleHunt(self, description, token=None): self.StartHunt( description=description, flow_runner_args=rdf_flow_runner.FlowRunnerArgs( flow_name=transfer.GetFile.__name__), flow_args=transfer.GetFileArgs(pathspec=rdf_paths.PathSpec( path="/tmp/evil.txt", pathtype=rdf_paths.PathSpec.PathType.NTFS, )), client_rule_set=self._CreateForemanClientRuleSet(), output_plugins=[ rdf_output_plugin.OutputPluginDescriptor( plugin_name="DummyOutputPlugin", plugin_args=gui_test_lib.DummyOutputPlugin.args_type( filename_regex="blah!", fetch_binaries=True)) ], client_rate=60, paused=True, token=token)
def _ReadBytesWithGetFile(self, path, stat_available=False, offset=None, file_size_override=None, read_length=None): if stat_available: client_mock = action_mocks.GetFileClientMock() else: client_mock = action_mocks.GetFileWithFailingStatClientMock() pathspec = rdf_paths.PathSpec( pathtype=rdf_paths.PathSpec.PathType.OS, path=path, ) if offset is not None: pathspec.offset = offset if file_size_override is not None: pathspec.file_size_override = file_size_override args = transfer.GetFileArgs( pathspec=pathspec, ignore_stat_failure=not stat_available, ) if read_length is not None: args.read_length = read_length flow_id = flow_test_lib.TestFlowHelper(transfer.GetFile.__name__, client_mock, token=self.token, client_id=self.client_id, args=args) results = flow_test_lib.GetFlowResults(self.client_id, flow_id) self.assertLen( results, 1, f"Expected 1 result for offset={offset}, " f"file_size_override={file_size_override}, " f"read_length={read_length}, ") res_pathspec = results[0].pathspec cp = db.ClientPath.FromPathSpec(self.client_id, res_pathspec) return file_store.OpenFile(cp).Read()
def testFailsIfStatFailsAndIgnoreStatFailureFlagNotSet(self): with temp.AutoTempFilePath() as test_path: with open(test_path, "wb") as fd: fd.write(b"foo") pathspec = rdf_paths.PathSpec( pathtype=rdf_paths.PathSpec.PathType.OS, path=test_path, ) args = transfer.GetFileArgs( pathspec=pathspec, read_length=1, ) client_mock = action_mocks.GetFileWithFailingStatClientMock() with self.assertRaises(RuntimeError): flow_test_lib.TestFlowHelper(transfer.GetFile.__name__, client_mock, creator=self.test_username, client_id=self.client_id, args=args)
def RunFlow(self, flow_cls=None, output_plugins=None, flow_args=None, client_mock=None): if flow_args is None: flow_args = transfer.GetFileArgs(pathspec=rdf_paths.PathSpec( path="/tmp/evil.txt", pathtype=rdf_paths.PathSpec.PathType.OS)) if client_mock is None: client_mock = hunt_test_lib.SampleHuntMock(failrate=2) flow_urn = flow_test_lib.StartAndRunFlow(flow_cls or transfer.GetFile, client_mock=client_mock, client_id=self.client_id, flow_args=flow_args, output_plugins=output_plugins) return flow_urn
def testWorksIfStatFailsAndIgnoreStatFailureFlagIsSet(self): with temp.AutoTempFilePath() as test_path: with open(test_path, "wb") as fd: fd.write(b"foo") pathspec = rdf_paths.PathSpec( pathtype=rdf_paths.PathSpec.PathType.OS, path=test_path, ) args = transfer.GetFileArgs( pathspec=pathspec, read_length=1, ignore_stat_failure=True, ) client_mock = action_mocks.GetFileWithFailingStatClientMock() flow_test_lib.TestFlowHelper(transfer.GetFile.__name__, client_mock, token=self.token, client_id=self.client_id, args=args)
def testStartVariableHuntRaisesIfMoreThanOneFlowPerClient(self): client_id = self.SetupClients(1)[0] hunt_obj = rdf_hunt_objects.Hunt(client_rate=0) hunt_obj.args.hunt_type = hunt_obj.args.HuntType.VARIABLE for index in range(2): hunt_obj.args.variable.flow_groups.append( rdf_hunt_objects.VariableHuntFlowGroup( client_ids=[client_id], flow_name=compatibility.GetName(transfer.GetFile), flow_args=transfer.GetFileArgs(pathspec=rdf_paths.PathSpec( path="/tmp/evil_%d.txt" % index, pathtype=rdf_paths.PathSpec.PathType.OS, )))) data_store.REL_DB.WriteHuntObject(hunt_obj) with self.assertRaises(hunt.CanStartAtMostOneFlowPerClientError): hunt.StartHunt(hunt_obj.hunt_id) # Check that no flows were scheduled on the client. flows = data_store.REL_DB.ReadAllFlowObjects(client_id) self.assertEmpty(flows)
def CreateHunt(self, flow_runner_args=None, flow_args=None, client_rule_set=None, original_object=None, client_rate=0, duration=None, creator=None, **kwargs): # Only initialize default flow_args value if default flow_runner_args value # is to be used. if not flow_runner_args: flow_args = (flow_args or transfer.GetFileArgs(pathspec=rdf_paths.PathSpec( path="/tmp/evil.txt", pathtype=rdf_paths.PathSpec.PathType.OS))) flow_runner_args = (flow_runner_args or rdf_flow_runner.FlowRunnerArgs( flow_name=transfer.GetFile.__name__)) client_rule_set = (client_rule_set or self._CreateForemanClientRuleSet()) hunt_args = rdf_hunt_objects.HuntArguments.Standard( flow_name=flow_runner_args.flow_name, flow_args=rdf_structs.AnyValue.Pack(flow_args)) hunt_obj = rdf_hunt_objects.Hunt(creator=creator, client_rule_set=client_rule_set, original_object=original_object, client_rate=client_rate, duration=duration, args=hunt_args, **kwargs) hunt.CreateHunt(hunt_obj) return hunt_obj.hunt_id