def _GetSignedBinaryMetadata(binary_type, relative_path): """Fetches metadata for the given binary from the datastore. Args: binary_type: ApiGrrBinary.Type of the binary. relative_path: Relative path of the binary, relative to the canonical URN roots for signed binaries (see _GetSignedBlobsRoots()). Returns: An ApiGrrBinary RDFProtoStruct containing metadata for the binary. """ root_urn = _GetSignedBlobsRoots()[binary_type] binary_urn = root_urn.Add(relative_path) blob_iterator, timestamp = signed_binary_utils.FetchBlobsForSignedBinaryByURN( binary_urn) binary_size = 0 has_valid_signature = True for blob in blob_iterator: binary_size += len(blob.data) if not has_valid_signature: # No need to check the signature if a previous blob had an invalid # signature. continue try: blob.Verify(config.CONFIG["Client.executable_signing_public_key"]) except rdf_crypto.Error: has_valid_signature = False return ApiGrrBinary(path=relative_path, type=binary_type, size=binary_size, timestamp=timestamp, has_valid_signature=has_valid_signature)
def testMissingSignedBinary(self): missing_urn = rdfvalue.RDFURN("aff4:/config/executables/not/exist") with self.assertRaises(signed_binary_utils.SignedBinaryNotFoundError): signed_binary_utils.DeleteSignedBinary(missing_urn) with self.assertRaises(signed_binary_utils.SignedBinaryNotFoundError): signed_binary_utils.FetchBlobsForSignedBinaryByURN(missing_urn) with self.assertRaises(signed_binary_utils.SignedBinaryNotFoundError): signed_binary_utils.FetchSizeOfSignedBinary(missing_urn)
def _BlobIterator(self, binary_urn): try: blob_iterator, _ = signed_binary_utils.FetchBlobsForSignedBinaryByURN( binary_urn) except signed_binary_utils.SignedBinaryNotFoundError: raise flow_base.FlowError("Executable binary %s not found." % self.args.binary) return blob_iterator
def _WriteTestBinaryAndGetBlobIterator(self, binary_data, chunk_size): binary_urn = rdfvalue.RDFURN("aff4:/config/executables/foo") signed_binary_utils.WriteSignedBinary(binary_urn, binary_data, private_key=self._private_key, public_key=self._public_key, chunk_size=chunk_size) blob_iterator, _ = signed_binary_utils.FetchBlobsForSignedBinaryByURN( binary_urn) return blob_iterator
def Handle(self, args, token=None): root_urn = _GetSignedBlobsRoots()[args.type] binary_urn = root_urn.Add(args.path) binary_size = signed_binary_utils.FetchSizeOfSignedBinary(binary_urn) blob_iterator, _ = signed_binary_utils.FetchBlobsForSignedBinaryByURN( binary_urn) chunk_iterator = signed_binary_utils.StreamSignedBinaryContents( blob_iterator, chunk_size=self.CHUNK_SIZE) return api_call_handler_base.ApiBinaryStream( filename=binary_urn.Basename(), content_generator=chunk_iterator, content_length=binary_size)
def testWriteSignedBinaryBlobs(self): test_urn = rdfvalue.RDFURN("aff4:/config/executables/foo") test_blobs = [ rdf_crypto.SignedBlob().Sign(b"\x00\x11\x22", self._private_key), rdf_crypto.SignedBlob().Sign(b"\x33\x44\x55", self._private_key), rdf_crypto.SignedBlob().Sign(b"\x66\x77\x88", self._private_key), rdf_crypto.SignedBlob().Sign(b"\x99", self._private_key) ] signed_binary_utils.WriteSignedBinaryBlobs(test_urn, test_blobs) blobs_iter, timestamp = signed_binary_utils.FetchBlobsForSignedBinaryByURN( test_urn) self.assertGreater(timestamp.AsMicrosecondsSinceEpoch(), 0) self.assertCountEqual(list(blobs_iter), test_blobs)
def testExecuteLargeBinaries(self): client_mock = action_mocks.ActionMock(standard.ExecuteBinaryCommand) code = b"I am a large binary file" * 100 upload_path = signed_binary_utils.GetAFF4ExecutablesRoot().Add( config.CONFIG["Client.platform"]).Add("test.exe") maintenance_utils.UploadSignedConfigBlob(code, aff4_path=upload_path, limit=100) binary_urn = rdfvalue.RDFURN(upload_path) binary_size = signed_binary_utils.FetchSizeOfSignedBinary(binary_urn) blob_iterator, _ = signed_binary_utils.FetchBlobsForSignedBinaryByURN( binary_urn) # Total size is 2400. self.assertEqual(binary_size, 2400) # There should be 24 parts to this binary. self.assertLen(list(blob_iterator), 24) # This flow has an acl, the user needs to be admin. acl_test_lib.CreateAdminUser(self.token.username) with utils.Stubber(subprocess, "Popen", client_test_lib.Popen): flow_test_lib.TestFlowHelper(compatibility.GetName( administrative.LaunchBinary), client_mock, client_id=self.SetupClient(0), binary=upload_path, command_line="--value 356", token=self.token) # Check that the executable file contains the code string. self.assertEqual(client_test_lib.Popen.binary, code) # At this point, the actual binary should have been cleaned up by the # client action so it should not exist. self.assertRaises(IOError, open, client_test_lib.Popen.running_args[0]) # Check the binary was run with the correct command line. self.assertEqual(client_test_lib.Popen.running_args[1], "--value") self.assertEqual(client_test_lib.Popen.running_args[2], "356") # Check the command was in the tmp file. self.assertStartsWith(client_test_lib.Popen.running_args[0], config.CONFIG["Client.tempdir_roots"][0])
def Start(self): """The start method.""" python_hack_urn = signed_binary_utils.GetAFF4PythonHackRoot().Add( self.args.hack_name) try: blob_iterator, _ = signed_binary_utils.FetchBlobsForSignedBinaryByURN( python_hack_urn) except signed_binary_utils.SignedBinaryNotFoundError: raise flow_base.FlowError("Python hack %s not found." % self.args.hack_name) # TODO(amoser): This will break if someone wants to execute lots of Python. for python_blob in blob_iterator: self.CallClient(server_stubs.ExecutePython, python_code=python_blob, py_args=self.args.py_args, next_state=compatibility.GetName(self.Done))
def testUploadPythonHack(self): with utils.TempDirectory() as dir_path: python_hack_path = os.path.join(dir_path, "hello_world.py") with open(python_hack_path, "wb") as f: f.write(b"print('Hello, world!')") config_updater_util.UploadSignedBinary( python_hack_path, objects_pb2.SignedBinaryID.BinaryType.PYTHON_HACK, "linux", upload_subdirectory="test") python_hack_urn = rdfvalue.RDFURN( "aff4:/config/python_hacks/linux/test/hello_world.py") blob_iterator, _ = signed_binary_utils.FetchBlobsForSignedBinaryByURN( python_hack_urn) uploaded_blobs = list( signed_binary_utils.StreamSignedBinaryContents(blob_iterator)) uploaded_content = b"".join(uploaded_blobs) self.assertEqual(uploaded_content, b"print('Hello, world!')")
def testUploadExecutable(self): with utils.TempDirectory() as dir_path: executable_path = os.path.join(dir_path, "foo.exe") with open(executable_path, "wb") as f: f.write(b"\xaa\xbb\xcc\xdd") config_updater_util.UploadSignedBinary( executable_path, objects_pb2.SignedBinaryID.BinaryType.EXECUTABLE, "windows", upload_subdirectory="anti-malware/registry-tools") executable_urn = rdfvalue.RDFURN( "aff4:/config/executables/windows/anti-malware/registry-tools/" "foo.exe") blob_iterator, _ = signed_binary_utils.FetchBlobsForSignedBinaryByURN( executable_urn) uploaded_blobs = list( signed_binary_utils.StreamSignedBinaryContents(blob_iterator)) uploaded_content = b"".join(uploaded_blobs) self.assertEqual(uploaded_content, b"\xaa\xbb\xcc\xdd")
def Handle(self, args, context=None): if not args.path: raise ValueError("Invalid binary path: %s" % args.path) root_urn = _GetBinaryRootUrn(args.type) urn = root_urn.Add(args.path) # If GRR binaries are readonly, check if a binary with the given # name and type exists and raise if it does. if config.CONFIG["Server.grr_binaries_readonly"]: try: signed_binary_utils.FetchBlobsForSignedBinaryByURN(urn) raise GrrBinaryIsNotOverwritableError( f"GRR binary ({args.path}, {args.type}) can't be overwritten: " "all binaries are read-only.") except signed_binary_utils.SignedBinaryNotFoundError: pass signed_binary_utils.WriteSignedBinaryBlobs(urn, list(args.blobs))
def testWriteSignedBinary(self): binary_data = b"\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99" # 10 bytes. test_urn = rdfvalue.RDFURN("aff4:/config/executables/foo") signed_binary_utils.WriteSignedBinary(test_urn, binary_data, private_key=self._private_key, public_key=self._public_key, chunk_size=3) blobs_iter, timestamp = signed_binary_utils.FetchBlobsForSignedBinaryByURN( test_urn) self.assertGreater(timestamp.AsMicrosecondsSinceEpoch(), 0) self.assertIsInstance(blobs_iter, collections.Iterator) # We expect blobs to have at most 3 contiguous bytes of data. expected_blobs = [ rdf_crypto.SignedBlob().Sign(b"\x00\x11\x22", self._private_key), rdf_crypto.SignedBlob().Sign(b"\x33\x44\x55", self._private_key), rdf_crypto.SignedBlob().Sign(b"\x66\x77\x88", self._private_key), rdf_crypto.SignedBlob().Sign(b"\x99", self._private_key) ] self.assertCountEqual(list(blobs_iter), expected_blobs)
def testUpdateClientSingleBlob(self): client_mock = action_mocks.UpdateAgentClientMock() fake_installer = b"FakeGRRDebInstaller" * 20 upload_path = signed_binary_utils.GetAFF4ExecutablesRoot().Add( config.CONFIG["Client.platform"]).Add("test.deb") maintenance_utils.UploadSignedConfigBlob(fake_installer, aff4_path=upload_path, limit=1000) blob_list, _ = signed_binary_utils.FetchBlobsForSignedBinaryByURN( upload_path) self.assertLen(list(blob_list), 1) acl_test_lib.CreateAdminUser(self.token.username) flow_test_lib.TestFlowHelper( compatibility.GetName(administrative.UpdateClient), client_mock, client_id=self.SetupClient(0, system=""), binary_path=os.path.join(config.CONFIG["Client.platform"], "test.deb"), token=self.token) self.assertEqual(client_mock.GetDownloadedFileContents(), fake_installer)