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() return flow_test_lib.TestFlowHelper( flow_name, args=flow_args, runner_args=runner_args, client_mock=client_mock, client_id=self.client_id, token=self.token)
def setUp(self): super(DeleteGRRTempFiles, self).setUp() filename = "%s_blah" % config.CONFIG["Client.tempfile_prefix"] self.tempfile = utils.JoinPath(self.temp_dir, "delete_test", filename) self.dirname = os.path.dirname(self.tempfile) os.makedirs(self.dirname) self.tempdir_overrider = test_lib.ConfigOverrider({ "Client.tempdir_roots": [os.path.dirname(self.dirname)], "Client.grr_tempdir": os.path.basename(self.dirname) }) self.tempdir_overrider.Start() self.not_tempfile = os.path.join(self.temp_dir, "notatempfile") open(self.not_tempfile, "wb").write("something") self.temp_fd = tempfiles.CreateGRRTempFile(filename="file1") self.temp_fd2 = tempfiles.CreateGRRTempFile(filename="file2") self.assertTrue(os.path.exists(self.not_tempfile)) self.assertTrue(os.path.exists(self.temp_fd.name)) self.assertTrue(os.path.exists(self.temp_fd2.name)) self.pathspec = rdf_paths.PathSpec( path=self.dirname, pathtype=rdf_paths.PathSpec.PathType.OS)
def testShowsNotificationIfArchiveStreamingFailsInProgress(self): pathspec = rdf_paths.PathSpec(path=os.path.join( self.base_path, "test.plist"), pathtype=rdf_paths.PathSpec.PathType.OS) flow_urn = flow.StartAFF4Flow( flow_name=flows_transfer.GetFile.__name__, client_id=self.client_id, pathspec=pathspec, token=self.token) flow_test_lib.TestFlowHelper(flow_urn, self.action_mock, client_id=self.client_id, token=self.token) def RaisingStub(*unused_args, **unused_kwargs): yield b"foo" yield b"bar" raise RuntimeError("something went wrong") with utils.Stubber(api_call_handler_utils.CollectionArchiveGenerator, "Generate", RaisingStub): self.Open("/#/clients/%s" % self.client_id) self.Click("css=a[grrtarget='client.flows']") self.Click("css=td:contains('GetFile')") self.Click("link=Results") self.Click("css=button.DownloadButton") self.WaitUntil( self.IsUserNotificationPresent, "Archive generation failed for flow %s" % flow_urn.Basename()) # There will be no failure message, as we can't get a status from an # iframe that triggers the download. self.WaitUntilNot(self.IsTextPresent, "Can't generate archive: Unknown error")
def testShowsNotificationWhenArchiveGenerationIsDone(self): pathspec = rdf_paths.PathSpec(path=os.path.join( self.base_path, "test.plist"), pathtype=rdf_paths.PathSpec.PathType.OS) flow_urn = flow.StartAFF4Flow( flow_name=flows_transfer.GetFile.__name__, client_id=self.client_id, pathspec=pathspec, token=self.token) flow_test_lib.TestFlowHelper(flow_urn, self.action_mock, client_id=self.client_id, token=self.token) self.Open("/#/clients/%s" % self.client_id) self.Click("css=a[grrtarget='client.flows']") self.Click("css=td:contains('GetFile')") self.Click("link=Results") self.Click("css=button.DownloadButton") self.WaitUntil(self.IsTextPresent, "Generation has started") self.WaitUntil(self.IsUserNotificationPresent, "Downloaded archive of flow %s" % flow_urn.Basename())
def testNestedProtobufAssignment(self): """Check that we can assign a nested protobuf.""" container = rdf_client.BufferReference() test_path = "C:\\test" pathspec = rdf_paths.PathSpec(path=test_path, pathtype=1) # Should raise - incompatible RDFType. self.assertRaises(ValueError, setattr, container, "pathspec", rdfvalue.RDFString("hello")) # Should raise - incompatible RDFProto type. self.assertRaises(ValueError, setattr, container, "pathspec", rdf_client_fs.StatEntry(st_size=5)) # Assign directly. container.device = pathspec self.assertEqual(container.device.path, test_path) # Clear the field. container.device = None # Check the protobuf does not have the field set at all. self.assertFalse(container.HasField("pathspec"))
def testExistingFileStat(self): bash_stat = { "st_ctime": rdfvalue.RDFDatetimeSeconds(1299502221), "st_rdev": 0, "st_mtime": rdfvalue.RDFDatetimeSeconds(1284154642), "st_blocks": 16, "st_nlink": 1, "st_gid": 0, "st_blksize": 4096, "pathspec": rdf_paths.PathSpec(path="/bin/bash", pathtype="OS", path_options="CASE_LITERAL"), "st_dev": 51713, "st_size": 4874, "st_ino": 1026148, "st_uid": 0, "st_mode": rdf_client_fs.StatMode(33261), "st_atime": rdfvalue.RDFDatetimeSeconds(1299502220) } bash_path = os.path.join("/", self.client_name, "fs/os/c/bin/bash") self.assertItemsEqual(self.passthrough.getattr(bash_path), bash_stat)
def Run(self, args): """Use eficheck to extract the binary image of the flash. Args: args: EficheckConfig Returns: DumpEfiImageResponse This action executes eficheck multiple times: * First to get the binary version, using --version. * Use --save -b firmware.bin to save the image. """ eficheck_version = self._GetVersion(args) if not eficheck_version: return False with tempfiles.TemporaryDirectory(cleanup=False) as tmp_dir: res = client_utils_common.Execute(args.cmd_path, ["--save", "-b", "firmware.bin"], cwd=tmp_dir.path) stdout, stderr, exit_status, time_used = res binary_response = rdf_client_action.ExecuteBinaryResponse( stdout=stdout, stderr=stderr, exit_status=exit_status, time_used=time_used) response = rdf_apple_firmware.DumpEfiImageResponse( eficheck_version=eficheck_version, response=binary_response) if exit_status: tmp_dir.cleanup = True else: response.path = rdf_paths.PathSpec( path=os.path.join(tmp_dir.path, "firmware.bin"), pathtype=rdf_paths.PathSpec.PathType.TMPFILE) self.SendReply(response)
def testGuessPathSpecPartial(self): """Test that we can guess a pathspec from a partial pathspec.""" path = os.path.join(self.base_path, "test_img.dd") pathspec = rdf_paths.PathSpec( path=path, pathtype=rdf_paths.PathSpec.PathType.OS) pathspec.nested_path.path = "/home/image2.img/home/a.txt" pathspec.nested_path.pathtype = rdf_paths.PathSpec.PathType.TSK fd = vfs.VFSOpen(pathspec) self.assertEqual(fd.read(3), "yay") # Open as a directory pathspec.nested_path.path = "/home/image2.img/home/" fd = vfs.VFSOpen(pathspec) names = [] for s in fd.ListFiles(): # Make sure that the stat pathspec is correct - it should be 3 levels # deep. self.assertEqual(s.pathspec.nested_path.path, "/home/image2.img") names.append(s.pathspec.nested_path.nested_path.path) self.assertIn("home/a.txt", names)
def testCopyHuntPreservesRuleType(self): implementation.StartHunt( hunt_name=standard.GenericHunt.__name__, 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.TSK, )), client_rule_set=foreman_rules.ForemanClientRuleSet(rules=[ foreman_rules.ForemanClientRule( rule_type=foreman_rules.ForemanClientRule.Type.OS, os=foreman_rules.ForemanOsClientRule(os_darwin=True)) ]), token=self.token) 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 checkClickingOnDownloadAsStartsDownloadForType(self, mock_method, plugin, plugin_display_name): pathspec = rdf_paths.PathSpec(path=os.path.join( self.base_path, "test.plist"), pathtype=rdf_paths.PathSpec.PathType.OS) session_id = flow_test_lib.TestFlowHelper( flows_transfer.GetFile.__name__, pathspec=pathspec, client_mock=self.action_mock, client_id=self.client_id, token=self.token) if not data_store.RelationalDBFlowsEnabled(): session_id = session_id.Basename() self.Open("/#/clients/%s/flows/%s" % (self.client_id, session_id)) self.Click("link=Results") self.Select("id=plugin-select", plugin_display_name) self.Click("css=grr-download-collection-as button[name='download-as']") def MockMethodIsCalled(): try: # Mock should be called twice: once for HEAD (to check permissions) # and once for GET methods. mock_method.assert_called_with( api_flow.ApiGetExportedFlowResultsArgs( client_id=self.client_id, flow_id=session_id, plugin_name=plugin), token=mock.ANY) return True except AssertionError: return False self.WaitUntil(MockMethodIsCalled)
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.Basename()], 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.Basename()) self.assertEmpty(flows)
def ListDeviceDirectories(self, responses): """Flow state that calls ListDirectory action for each shadow copy.""" if not responses.success: raise flow_base.FlowError( "Unable to query Volume Shadow Copy information.") shadows_found = False for response in responses: device_object = response.GetItem("DeviceObject", "") global_root = r"\\?\GLOBALROOT\Device" if device_object.startswith(global_root): # The VSC device path is returned as \\?\GLOBALROOT\Device\ # HarddiskVolumeShadowCopy1 and need to pass it as # \\.\HarddiskVolumeShadowCopy1 to the ListDirectory flow device_object = r"\\." + device_object[len(global_root):] path_spec = rdf_paths.PathSpec( path=device_object, pathtype=rdf_paths.PathSpec.PathType.OS) path_spec.Append(path="/", pathtype=rdf_paths.PathSpec.PathType.TSK) self.Log("Listing Volume Shadow Copy device: %s.", device_object) self.CallClient( server_stubs.ListDirectory, pathspec=path_spec, next_state=compatibility.GetName(self.ProcessListDirectory)) shadows_found = True if not shadows_found: raise flow_base.FlowError("No Volume Shadow Copies were found.\n" "The volume could have no Volume Shadow Copies " "as Windows versions pre Vista or the Volume " "Shadow Copy Service has been disabled.")
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.assertItemsEqual(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 testDownloadFilesPanelIsShownWhenNewResultsAreAdded(self): f = flow.StartFlow(client_id=self.client_id, flow_name=gui_test_lib.RecursiveTestFlow.__name__, token=self.token) with data_store.DB.GetMutationPool() as pool: flow.GRRFlow.ResultCollectionForFID(f).Add( rdfvalue.RDFString("foo-result"), mutation_pool=pool) self.Open("/#/clients/%s" % self.client_id) # Ensure auto-refresh updates happen every second. self.GetJavaScriptValue( "grrUi.core.resultsCollectionDirective.setAutoRefreshInterval(1000);" ) # Go to the flows page without refreshing the page, so that # AUTO_REFRESH_INTERVAL_MS setting is not reset. self.Click("css=a[grrtarget='client.flows']") self.Click("css=tr:contains('%s')" % f.Basename()) self.Click("css=li[heading=Results]:not([disabled]") self.WaitUntil(self.IsElementPresent, "css=grr-results-collection td:contains('foo-result')") self.WaitUntilNot( self.IsElementPresent, "css=grr-results-collection grr-download-collection-files") stat_entry = rdf_client_fs.StatEntry(pathspec=rdf_paths.PathSpec( path="/foo/bar", pathtype=rdf_paths.PathSpec.PathType.OS)) with data_store.DB.GetMutationPool() as pool: flow.GRRFlow.ResultCollectionForFID(f).Add(stat_entry, mutation_pool=pool) self.WaitUntil( self.IsElementPresent, "css=grr-results-collection grr-download-collection-files")
def _Recurse(self, path, depth): """Recurses to the given path if necessary up to the given depth.""" if self.opts.pathtype == rdf_paths.PathSpec.PathType.OS: try: stat_entry = os.stat(path) except OSError: # Can happen for links pointing to non existent files/directories. return if (self._allowed_devices is not _XDEV_ALL_ALLOWED and stat_entry.st_dev not in self._allowed_devices): return if not stat.S_ISDIR(stat_entry.st_mode): return # Cannot use S_ISLNK here because we uses os.stat above which resolves # links. if not self.opts.follow_links and os.path.islink(path): return elif self.opts.pathtype == rdf_paths.PathSpec.PathType.REGISTRY: pathspec = rdf_paths.PathSpec( path=path, pathtype=rdf_paths.PathSpec.PathType.REGISTRY) try: with vfs.VFSOpen(pathspec) as filedesc: if not filedesc.IsDirectory(): return except IOError: return # Skip inaccessible Registry parts (e.g. HKLM\SAM\SAM) silently. else: raise AssertionError("Invalid pathtype {}".format( self.opts.pathtype)) for childpath in self._Generate(path, depth + 1): yield childpath
def testFindAction(self): """Test the find action.""" # First get all the files at once pathspec = rdf_paths.PathSpec( path="/mock2/", pathtype=rdf_paths.PathSpec.PathType.OS) request = rdf_client_fs.FindSpec(pathspec=pathspec, path_regex=".") request.iterator.number = 200 result = self.RunAction(searching.Find, request) all_files = [x.hit for x in result if isinstance(x, rdf_client_fs.FindSpec)] # Ask for the files one at the time files = [] request = rdf_client_fs.FindSpec(pathspec=pathspec, path_regex=".") request.iterator.number = 1 while True: result = self.RunAction(searching.Find, request) if request.iterator.state == rdf_client_action.Iterator.State.FINISHED: break self.assertLen(result, 2) self.assertIsInstance(result[0], rdf_client_fs.FindSpec) self.assertIsInstance(result[1], rdf_client_action.Iterator) files.append(result[0].hit) request.iterator = result[1].Copy() for x, y in zip(all_files, files): self.assertEqual(x, y) # Make sure the iterator is finished self.assertEqual(request.iterator.state, rdf_client_action.Iterator.State.FINISHED) # Ensure we remove old states from client_state self.assertEmpty(request.iterator.client_state.dat)
def StatFSFromClient(args): """Call os.statvfs for a given list of paths. Args: args: An `rdf_client_action.StatFSRequest`. Yields: `rdf_client_fs.UnixVolume` instances. Raises: RuntimeError: if called on a Windows system. """ if platform.system() == "Windows": raise RuntimeError("os.statvfs not available on Windows") for path in args.path_list: try: fd = vfs.VFSOpen(rdf_paths.PathSpec(path=path, pathtype=args.pathtype)) st = fd.StatFS() mount_point = fd.GetMountPoint() except (IOError, OSError): continue unix = rdf_client_fs.UnixVolume(mount_point=mount_point) # On linux pre 2.6 kernels don't have frsize, so we fall back to bsize. # The actual_available_allocation_units attribute is set to blocks # available to the unprivileged user, root may have some additional # reserved space. yield rdf_client_fs.Volume( bytes_per_sector=(st.f_frsize or st.f_bsize), sectors_per_allocation_unit=1, total_allocation_units=st.f_blocks, actual_available_allocation_units=st.f_bavail, unixvolume=unix)
def CreateSampleHunt(self, path=None, stopped=False, output_plugins=None, client_limit=0, client_count=10, creator=None): 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, creator=creator or self.token.username, paused=stopped) return self.hunt_urn
def testNotificationWhenListingRegistry(self): # Change the username so notifications get written. token = self.token.Copy() token.username = "******" acl_test_lib.CreateUser(token.username) with vfs_test_lib.RegistryVFSStubber(): client_id = self.SetupClient(0) pb = rdf_paths.PathSpec( path="/HKEY_LOCAL_MACHINE/SOFTWARE/ListingTest", pathtype=rdf_paths.PathSpec.PathType.REGISTRY) client_mock = action_mocks.ListDirectoryClientMock() flow_test_lib.TestFlowHelper( compatibility.GetName(filesystem.ListDirectory), client_mock, client_id=client_id, pathspec=pb, token=token) if data_store.RelationalDBEnabled(): notifications = data_store.REL_DB.ReadUserNotifications(token.username) self.assertLen(notifications, 1) n = notifications[0] self.assertEqual(n.reference.vfs_file.path_type, rdf_objects.PathInfo.PathType.REGISTRY) self.assertEqual(n.reference.vfs_file.path_components, ["HKEY_LOCAL_MACHINE", "SOFTWARE", "ListingTest"]) else: user = aff4.FACTORY.Open("aff4:/users/%s" % token.username, token=token) notifications = user.Get(user.Schema.PENDING_NOTIFICATIONS) self.assertLen(notifications, 1) expected_urn = ("aff4:/C.1000000000000000/registry/" "HKEY_LOCAL_MACHINE/SOFTWARE/ListingTest") self.assertEqual(notifications[0].subject, expected_urn)
def testExtAttrsCollection(self): with temp.AutoTempDirPath(remove_non_empty=True) as temp_dirpath: foo_filepath = temp.TempFilePath(dir=temp_dirpath) client_test_lib.SetExtAttr(foo_filepath, name="user.quux", value="foo") bar_filepath = temp.TempFilePath(dir=temp_dirpath) client_test_lib.SetExtAttr(bar_filepath, name="user.quux", value="bar") baz_filepath = temp.TempFilePath(dir=temp_dirpath) client_test_lib.SetExtAttr(baz_filepath, name="user.quux", value="baz") request = rdf_client_fs.FindSpec(pathspec=rdf_paths.PathSpec( path=temp_dirpath, pathtype=rdf_paths.PathSpec.PathType.OS), path_glob="*", collect_ext_attrs=True) request.iterator.number = 100 hits = [] for response in self.RunAction(searching.Find, request): if isinstance(response, rdf_client_fs.FindSpec): hits.append(response.hit) self.assertLen(hits, 3) values = [] for hit in hits: self.assertLen(hit.ext_attrs, 1) values.append(hit.ext_attrs[0].value) self.assertCountEqual(values, ["foo", "bar", "baz"])
def testRegistryListing(self): """Test our ability to list registry keys.""" reg = rdf_paths.PathSpec.PathType.REGISTRY with vfs_test_lib.VFSOverrider(reg, vfs_test_lib.FakeRegistryVFSHandler): pathspec = rdf_paths.PathSpec( pathtype=rdf_paths.PathSpec.PathType.REGISTRY, path=("/HKEY_USERS/S-1-5-20/Software/Microsoft" "/Windows/CurrentVersion/Run")) expected_names = { "MctAdmin": stat.S_IFDIR, "Sidebar": stat.S_IFDIR } expected_data = [ u"%ProgramFiles%\\Windows Sidebar\\Sidebar.exe /autoRun", u"%TEMP%\\Sidebar.exe" ] for f in vfs.VFSOpen(pathspec).ListFiles(): base, name = os.path.split(f.pathspec.CollapsePath()) self.assertEqual(base, pathspec.CollapsePath()) self.assertIn(name, expected_names) self.assertIn(f.registry_data.GetValue(), expected_data)
def testGetFile(self): """Test that the GetFile flow works.""" client_mock = action_mocks.GetFileClientMock() pathspec = rdf_paths.PathSpec(pathtype=rdf_paths.PathSpec.PathType.OS, path=os.path.join( self.base_path, "test_img.dd")) flow_test_lib.TestFlowHelper(transfer.GetFile.__name__, client_mock, token=self.token, client_id=self.client_id, pathspec=pathspec) # Fix path for Windows testing. pathspec.path = pathspec.path.replace("\\", "/") # Test the AFF4 file that was created. urn = pathspec.AFF4Path(self.client_id) fd1 = aff4.FACTORY.Open(urn, token=self.token) fd2 = open(pathspec.path, "rb") fd2.seek(0, 2) self.assertEqual(fd2.tell(), int(fd1.Get(fd1.Schema.SIZE))) self.CompareFDs(fd1, fd2)
def Start(self): self.SendReply( rdf_client_fs.StatEntry(pathspec=rdf_paths.PathSpec( path="/some/unique/path", pathtype=rdf_paths.PathSpec.PathType.OS)))
def testUnicodeSupport(self): pathspec = rdf_paths.PathSpec( path="/foobar", pathtype=rdf_paths.PathSpec.PathType.TSK) pathspec.path = u"Grüezi" self.assertEqual(pathspec.path, u"Grüezi")
def CreateStat(self, path, uid=0, gid=0, mode=0o0100640): """Given path, uid, gid and file mode, this returns a StatEntry.""" pathspec = rdf_paths.PathSpec(path=path, pathtype="OS") return rdf_client_fs.StatEntry( pathspec=pathspec, st_uid=uid, st_gid=gid, st_mode=mode)
def StoreResults(self, responses): """Stores the results.""" if not responses.success: self.state.plugin_errors.append( unicode(responses.status.error_message)) # Keep processing to read out the debug messages from the json. self.Log("Rekall returned %s responses." % len(responses)) for response in responses: if response.missing_profile: profile = self.GetProfileByName(response.missing_profile, response.repository_version) if profile: self.CallClient(server_stubs.WriteRekallProfile, profile, next_state="UpdateProfile") else: self.Log( "Needed profile %s not found! See " "https://github.com/google/grr-doc/blob/master/" "troubleshooting.adoc#missing-rekall-profiles", response.missing_profile) if response.json_messages: response.client_urn = self.client_id if self.state.rekall_context_messages: response.json_context_messages = json.dumps( list(iteritems(self.state.rekall_context_messages)), separators=(",", ":")) json_data = json.loads(response.json_messages) for message in json_data: if len(message) >= 1: if message[0] in ["t", "s"]: self.state.rekall_context_messages[ message[0]] = message[1] if message[0] == "file": pathspec = rdf_paths.PathSpec(**message[1]) self.state.output_files.append(pathspec) if message[0] == "L": if len(message) > 1: log_record = message[1] self.Log("%s:%s:%s", log_record["level"], log_record["name"], log_record["msg"]) self.SendReply(response) if (responses.iterator and # This will be None if an error occurred. responses.iterator.state != rdf_client.Iterator.State.FINISHED): self.state.rekall_request.iterator = responses.iterator self.CallClient(server_stubs.RekallAction, self.state.rekall_request, next_state="StoreResults") else: if self.state.output_files: self.Log("Getting %i files.", len(self.state.output_files)) self.CallFlow(transfer.MultiGetFile.__name__, pathspecs=self.state.output_files, file_size=self.args.max_file_size_download, next_state="DeleteFiles")
def testMultiGetFileMultiFiles(self): """Test MultiGetFile downloading many files at once.""" client_mock = action_mocks.MultiGetFileClientMock() pathspecs = [] # Make 30 files to download. for i in range(30): path = os.path.join(self.temp_dir, "test_%s.txt" % i) with open(path, "wb") as fd: fd.write("Hello") pathspecs.append( rdf_paths.PathSpec(pathtype=rdf_paths.PathSpec.PathType.OS, path=path)) args = transfer.MultiGetFileArgs(pathspecs=pathspecs, maximum_pending_files=10) session_id = flow_test_lib.TestFlowHelper( transfer.MultiGetFile.__name__, client_mock, token=self.token, client_id=self.client_id, args=args) if data_store.RelationalDBReadEnabled(): # Now open each file and make sure the data is there. for pathspec in pathspecs: cp = db.ClientPath.FromPathSpec(self.client_id.Basename(), pathspec) fd_rel_db = file_store.OpenFile(cp) self.assertEqual("Hello", fd_rel_db.read()) # Check that SHA256 hash of the file matches the contents # hash and that MD5 and SHA1 are set. history = data_store.REL_DB.ReadPathInfoHistory( cp.client_id, cp.path_type, cp.components) self.assertEqual(history[-1].hash_entry.sha256, fd_rel_db.hash_id.AsBytes()) self.assertIsNotNone(history[-1].hash_entry.sha1) self.assertIsNotNone(history[-1].hash_entry.md5) else: # Check up on the internal flow state. flow_state = flow_test_lib.GetFlowState(self.client_id, session_id, token=self.token) # All the pathspecs should be in this list. self.assertLen(flow_state.indexed_pathspecs, 30) # At any one time, there should not be more than 10 files or hashes # pending. self.assertLessEqual(len(flow_state.pending_files), 10) self.assertLessEqual(len(flow_state.pending_hashes), 10) # When we finish there should be no pathspecs stored in the flow state. for flow_pathspec in flow_state.indexed_pathspecs: self.assertIsNone(flow_pathspec) for flow_request_data in flow_state.request_data_list: self.assertIsNone(flow_request_data) for pathspec in pathspecs: urn = pathspec.AFF4Path(self.client_id) fd = aff4.FACTORY.Open(urn, token=self.token) self.assertEqual("Hello", fd.read())
def testMultiGetFileOfSpecialFiles(self): """Test that special /proc/ files are handled correctly. /proc/ files have the property that they are non seekable from their end (i.e. seeking them relative to the end is not supported). They also return an st_size of 0. For example: $ stat /proc/self/maps File: '/proc/self/maps' Size: 0 Blocks: 0 IO Block: 1024 regular empty file $ head /proc/self/maps 00400000-00409000 r-xp 00000000 fc:01 9180740 /usr/bin/head 00608000-00609000 r--p 00008000 fc:01 9180740 /usr/bin/head ... When we try to use the MultiGetFile flow, it deduplicates the files and since it thinks the file has a zero size, the flow will not download the file, and instead copy the zero size file into it. """ client_mock = action_mocks.MultiGetFileClientMock() # # Create a zero sized file. zero_sized_filename = os.path.join(self.temp_dir, "zero_size") with open(zero_sized_filename, "wb") as fd: pass pathspec = rdf_paths.PathSpec(pathtype=rdf_paths.PathSpec.PathType.OS, path=zero_sized_filename) flow_test_lib.TestFlowHelper(transfer.MultiGetFile.__name__, client_mock, token=self.token, file_size="1MiB", client_id=self.client_id, pathspecs=[pathspec]) # Now if we try to fetch a real /proc/ filename this will fail because the # filestore already contains the zero length file # aff4:/files/nsrl/da39a3ee5e6b4b0d3255bfef95601890afd80709. pathspec = rdf_paths.PathSpec(pathtype=rdf_paths.PathSpec.PathType.OS, path="/proc/self/environ") flow_test_lib.TestFlowHelper(transfer.MultiGetFile.__name__, client_mock, token=self.token, file_size=1024 * 1024, client_id=self.client_id, pathspecs=[pathspec]) data = open(pathspec.last.path, "rb").read() if data_store.RelationalDBReadEnabled(): cp = db.ClientPath.FromPathSpec(self.client_id.Basename(), pathspec) fd_rel_db = file_store.OpenFile(cp) self.assertEqual(fd_rel_db.size, len(data)) self.assertMultiLineEqual(fd_rel_db.read(), data) # Check that SHA256 hash of the file matches the contents # hash and that MD5 and SHA1 are set. history = data_store.REL_DB.ReadPathInfoHistory( cp.client_id, cp.path_type, cp.components) self.assertEqual(history[-1].hash_entry.sha256, fd_rel_db.hash_id.AsBytes()) self.assertIsNotNone(history[-1].hash_entry.sha1) self.assertIsNotNone(history[-1].hash_entry.md5) else: # Test the AFF4 file that was created - it should be empty since by # default we judge the file size based on its stat.st_size. urn = pathspec.AFF4Path(self.client_id) fd = aff4.FACTORY.Open(urn, token=self.token) self.assertEqual(fd.size, len(data)) self.assertMultiLineEqual(fd.read(len(data)), data)
def testReadMaxDword(self): fd = vfs.VFSOpen( rdf_paths.PathSpec( path=r"/HKEY_LOCAL_MACHINE/SOFTWARE/GRR_TEST/maxdword", pathtype="REGISTRY")) self.assertEqual(fd.value, 0xFFFFFFFF)
def testFileReadLongUnicodeValue(self): fd = vfs.VFSOpen( rdf_paths.PathSpec( path=r"/HKEY_LOCAL_MACHINE/SOFTWARE/GRR_TEST/{}".format(_LONG_KEY), pathtype="REGISTRY")) self.assertEqual(fd.Read(-1).decode("utf-8"), _LONG_STRING_VALUE)