예제 #1
0
    def WmiQuery(self, query):
        expected_query = "SELECT * FROM Win32_ShadowCopy"
        if query.query != expected_query:
            raise RuntimeError("Received unexpected query.")

        return [rdf_protodict.Dict(**self._RESPONSES)]
예제 #2
0
  def CallClient(self,
                 action_cls,
                 request=None,
                 next_state=None,
                 client_id=None,
                 request_data=None,
                 start_time=None,
                 **kwargs):
    """Calls the client asynchronously.

    This sends a message to the client to invoke an Action. The run
    action may send back many responses. These will be queued by the
    framework until a status message is sent by the client. The status
    message will cause the entire transaction to be committed to the
    specified state.

    Args:
       action_cls: The function to call on the client.

       request: The request to send to the client. If not specified (Or None) we
             create a new RDFValue using the kwargs.

       next_state: The state in this flow, that responses to this
             message should go to.

       client_id: rdf_client.ClientURN to send the request to.

       request_data: A dict which will be available in the RequestState
             protobuf. The Responses object maintains a reference to this
             protobuf for use in the execution of the state method. (so you can
             access this data by responses.request). Valid values are
             strings, unicode and protobufs.

       start_time: Call the client at this time. This Delays the client request
         for into the future.

       **kwargs: These args will be used to construct the client action semantic
         protobuf.

    Raises:
       FlowRunnerError: If next_state is not one of the allowed next states.
       RuntimeError: The request passed to the client does not have the correct
                     type.
    """
    if client_id is None:
      client_id = self.runner_args.client_id

    if client_id is None:
      raise FlowRunnerError("CallClient() is used on a flow which was not "
                            "started with a client.")

    if not isinstance(client_id, rdf_client.ClientURN):
      # Try turning it into a ClientURN
      client_id = rdf_client.ClientURN(client_id)

    if action_cls.in_rdfvalue is None:
      if request:
        raise RuntimeError(
            "Client action %s does not expect args." % action_cls.__name__)
    else:
      if request is None:
        # Create a new rdf request.
        request = action_cls.in_rdfvalue(**kwargs)
      else:
        # Verify that the request type matches the client action requirements.
        if not isinstance(request, action_cls.in_rdfvalue):
          raise RuntimeError("Client action expected %s but got %s" %
                             (action_cls.in_rdfvalue, type(request)))

    outbound_id = self.GetNextOutboundId()

    # Create a new request state
    state = rdf_flows.RequestState(
        id=outbound_id,
        session_id=self.session_id,
        next_state=next_state,
        client_id=client_id)

    if request_data is not None:
      state.data = rdf_protodict.Dict(request_data)

    # Send the message with the request state
    msg = rdf_flows.GrrMessage(
        session_id=utils.SmartUnicode(self.session_id),
        name=action_cls.__name__,
        request_id=outbound_id,
        priority=self.runner_args.priority,
        require_fastpoll=self.runner_args.require_fastpoll,
        queue=client_id.Queue(),
        payload=request,
        generate_task_id=True)

    cpu_usage = self.context.client_resources.cpu_usage
    if self.runner_args.cpu_limit:
      msg.cpu_limit = max(self.runner_args.cpu_limit - cpu_usage.user_cpu_time -
                          cpu_usage.system_cpu_time, 0)

      if msg.cpu_limit == 0:
        raise FlowRunnerError("CPU limit exceeded.")

    if self.runner_args.network_bytes_limit:
      msg.network_bytes_limit = max(self.runner_args.network_bytes_limit -
                                    self.context.network_bytes_sent, 0)
      if msg.network_bytes_limit == 0:
        raise FlowRunnerError("Network limit exceeded.")

    state.request = msg
    self.QueueRequest(state, timestamp=start_time)
예제 #3
0
  def CallFlow(self,
               flow_name=None,
               next_state=None,
               sync=True,
               request_data=None,
               client_id=None,
               base_session_id=None,
               **kwargs):
    """Creates a new flow and send its responses to a state.

    This creates a new flow. The flow may send back many responses which will be
    queued by the framework until the flow terminates. The final status message
    will cause the entire transaction to be committed to the specified state.

    Args:
       flow_name: The name of the flow to invoke.

       next_state: The state in this flow, that responses to this
       message should go to.

       sync: If True start the flow inline on the calling thread, else schedule
         a worker to actually start the child flow.

       request_data: Any dict provided here will be available in the
             RequestState protobuf. The Responses object maintains a reference
             to this protobuf for use in the execution of the state method. (so
             you can access this data by responses.request). There is no
             format mandated on this data but it may be a serialized protobuf.

       client_id: If given, the flow is started for this client.

       base_session_id: A URN which will be used to build a URN.

       **kwargs: Arguments for the child flow.

    Raises:
       FlowRunnerError: If next_state is not one of the allowed next states.

    Returns:
       The URN of the child flow which was created.
    """
    client_id = client_id or self.runner_args.client_id

    # This looks very much like CallClient() above - we prepare a request state,
    # and add it to our queue - any responses from the child flow will return to
    # the request state and the stated next_state. Note however, that there is
    # no client_id or actual request message here because we directly invoke the
    # child flow rather than queue anything for it.
    state = rdf_flows.RequestState(
        id=self.GetNextOutboundId(),
        session_id=utils.SmartUnicode(self.session_id),
        client_id=client_id,
        next_state=next_state,
        response_count=0)

    if request_data:
      state.data = rdf_protodict.Dict().FromDict(request_data)

    # If the urn is passed explicitly (e.g. from the hunt runner) use that,
    # otherwise use the urn from the flow_runner args. If both are None, create
    # a new collection and give the urn to the flow object.
    logs_urn = self._GetLogCollectionURN(
        kwargs.pop("logs_collection_urn", None) or
        self.runner_args.logs_collection_urn)

    # If we were called with write_intermediate_results, propagate down to
    # child flows.  This allows write_intermediate_results to be set to True
    # either at the top level parent, or somewhere in the middle of
    # the call chain.
    write_intermediate = (kwargs.pop("write_intermediate_results", False) or
                          self.runner_args.write_intermediate_results)

    try:
      event_id = self.runner_args.event_id
    except AttributeError:
      event_id = None

    # Create the new child flow but do not notify the user about it.
    child_urn = self.flow_obj.StartFlow(
        client_id=client_id,
        flow_name=flow_name,
        base_session_id=base_session_id or self.session_id,
        event_id=event_id,
        request_state=state,
        token=self.token,
        notify_to_user=False,
        parent_flow=self.flow_obj,
        sync=sync,
        queue=self.runner_args.queue,
        write_intermediate_results=write_intermediate,
        logs_collection_urn=logs_urn,
        **kwargs)

    self.QueueRequest(state)

    return child_urn
예제 #4
0
 def testWMIEventConsumerParser_EmptyConsumersYieldBlank(self):
   parser = wmi_parser.WMIActiveScriptEventConsumerParser()
   rdf_dict = rdf_protodict.Dict()
   result_list = list(parser.Parse(None, rdf_dict, None))
   self.assertEqual(1, len(result_list))
   self.assertEqual(True, not result_list[0])
예제 #5
0
  def CallState(self,
                messages=None,
                next_state="",
                request_data=None,
                start_time=None):
    """This method is used to schedule a new state on a different worker.

    This is basically the same as CallFlow() except we are calling
    ourselves. The state will be invoked in a later time and receive all the
    messages we send.

    Args:
       messages: A list of rdfvalues to send. If the last one is not a
            GrrStatus, we append an OK Status.

       next_state: The state in this flow to be invoked with the responses.

       request_data: Any dict provided here will be available in the
             RequestState protobuf. The Responses object maintains a reference
             to this protobuf for use in the execution of the state method. (so
             you can access this data by responses.request).

       start_time: Start the flow at this time. This Delays notification for
         flow processing into the future. Note that the flow may still be
         processed earlier if there are client responses waiting.

    Raises:
       FlowRunnerError: if the next state is not valid.
    """
    if messages is None:
      messages = []

    # Check if the state is valid
    if not getattr(self.flow_obj, next_state):
      raise FlowRunnerError("Next state %s is invalid.")

    # Queue the response message to the parent flow
    request_state = rdf_flows.RequestState(
        id=self.GetNextOutboundId(),
        session_id=self.context.session_id,
        client_id=self.runner_args.client_id,
        next_state=next_state)
    if request_data:
      request_state.data = rdf_protodict.Dict().FromDict(request_data)

    self.QueueRequest(request_state, timestamp=start_time)

    # Add the status message if needed.
    if not messages or not isinstance(messages[-1], rdf_flows.GrrStatus):
      messages.append(rdf_flows.GrrStatus())

    # Send all the messages
    for i, payload in enumerate(messages):
      if isinstance(payload, rdfvalue.RDFValue):
        msg = rdf_flows.GrrMessage(
            session_id=self.session_id,
            request_id=request_state.id,
            response_id=1 + i,
            auth_state=rdf_flows.GrrMessage.AuthorizationState.AUTHENTICATED,
            payload=payload,
            type=rdf_flows.GrrMessage.Type.MESSAGE)

        if isinstance(payload, rdf_flows.GrrStatus):
          msg.type = rdf_flows.GrrMessage.Type.STATUS
      else:
        raise FlowRunnerError("Bad message %s of type %s." % (payload,
                                                              type(payload)))

      self.QueueResponse(msg, start_time)

    # Notify the worker about it.
    self.QueueNotification(session_id=self.session_id, timestamp=start_time)
예제 #6
0
    def CallState(self,
                  messages=None,
                  next_state="",
                  client_id=None,
                  request_data=None,
                  start_time=None):
        """This method is used to asynchronously schedule a new hunt state.

    The state will be invoked in a later time and receive all the messages
    we send.

    Args:
      messages: A list of rdfvalues to send. If the last one is not a
              GrrStatus, we append an OK Status.

      next_state: The state in this hunt to be invoked with the responses.

      client_id: ClientURN to use in scheduled requests.

      request_data: Any dict provided here will be available in the
                    RequestState protobuf. The Responses object maintains a
                    reference to this protobuf for use in the execution of the
                    state method. (so you can access this data by
                    responses.request).

      start_time: Schedule the state at this time. This delays notification
                  and messages for processing into the future.
    Raises:
      ValueError: on arguments error.
    """

        if messages is None:
            messages = []

        if not next_state:
            raise ValueError("next_state can't be empty.")

        # Now we construct a special response which will be sent to the hunt
        # flow. Randomize the request_id so we do not overwrite other messages in
        # the queue.
        request_state = rdf_flows.RequestState(
            id=utils.PRNG.GetULong(),
            session_id=self.context.session_id,
            client_id=client_id,
            next_state=next_state)

        if request_data:
            request_state.data = rdf_protodict.Dict().FromDict(request_data)

        self.QueueRequest(request_state, timestamp=start_time)

        # Add the status message if needed.
        if not messages or not isinstance(messages[-1], rdf_flows.GrrStatus):
            messages.append(rdf_flows.GrrStatus())

        # Send all the messages
        for i, payload in enumerate(messages):
            if isinstance(payload, rdfvalue.RDFValue):
                msg = rdf_flows.GrrMessage(
                    session_id=self.session_id,
                    request_id=request_state.id,
                    response_id=1 + i,
                    auth_state=rdf_flows.GrrMessage.AuthorizationState.
                    AUTHENTICATED,
                    payload=payload,
                    type=rdf_flows.GrrMessage.Type.MESSAGE)

                if isinstance(payload, rdf_flows.GrrStatus):
                    msg.type = rdf_flows.GrrMessage.Type.STATUS
            else:
                raise flow_runner.FlowRunnerError(
                    "Bad message %s of type %s." % (payload, type(payload)))

            self.QueueResponse(msg, timestamp=start_time)

        # Add the status message if needed.
        if not messages or not isinstance(messages[-1], rdf_flows.GrrStatus):
            messages.append(rdf_flows.GrrStatus())

        # Notify the worker about it.
        self.QueueNotification(session_id=self.session_id,
                               timestamp=start_time)
예제 #7
0
파일: flow.py 프로젝트: switters72/grr
    def __init__(self, request=None, responses=None, auth_required=True):
        self.status = None  # A GrrStatus rdfvalue object.
        self.success = True
        self.request = request
        self._auth_required = auth_required
        if request:
            self.request_data = rdf_protodict.Dict(request.data)
        self._responses = []
        self._dropped_responses = []

        if responses:
            # This may not be needed if we can assume that responses are
            # returned in lexical order from the data_store.
            responses.sort(key=operator.attrgetter("response_id"))

            # The iterator that was returned as part of these responses. This should
            # be passed back to actions that expect an iterator.
            self.iterator = None

            # Filter the responses by authorized states
            for msg in responses:
                # Check if the message is authenticated correctly.
                if msg.auth_state == msg.AuthorizationState.DESYNCHRONIZED or (
                        self._auth_required and msg.auth_state !=
                        msg.AuthorizationState.AUTHENTICATED):
                    logging.warning(
                        "%s: Messages must be authenticated (Auth state %s)",
                        msg.session_id, msg.auth_state)
                    self._dropped_responses.append(msg)
                    # Skip this message - it is invalid
                    continue

                # Check for iterators
                if msg.type == msg.Type.ITERATOR:
                    self.iterator = rdf_client.Iterator(msg.payload)
                    continue

                # Look for a status message
                if msg.type == msg.Type.STATUS:
                    # Our status is set to the first status message that we see in
                    # the responses. We ignore all other messages after that.
                    self.status = rdf_flows.GrrStatus(msg.payload)

                    # Check this to see if the call succeeded
                    self.success = self.status.status == self.status.ReturnedStatus.OK

                    # Ignore all other messages
                    break

                # Use this message
                self._responses.append(msg)

            if self.status is None:
                # This is a special case of de-synchronized messages.
                if self._dropped_responses:
                    logging.error("De-synchronized messages detected:\n" +
                                  "\n".join([
                                      utils.SmartUnicode(x)
                                      for x in self._dropped_responses
                                  ]))

                if responses:
                    self._LogFlowState(responses)

                raise FlowError("No valid Status message.")

        # This is the raw message accessible while going through the iterator
        self.message = None
예제 #8
0
 def testIsMapping(self):
   test_dict = rdf_protodict.Dict(a=1)
   self.assertTrue(isinstance(test_dict, collections.Mapping))
예제 #9
0
from grr.lib.rdfvalues import protodict as rdf_protodict
from grr.test_lib import client_test_lib
from grr.test_lib import fixture_test_lib
from grr.test_lib import flow_test_lib
from grr.test_lib import rekall_test_lib
from grr.test_lib import test_lib
from grr.test_lib import vfs_test_lib

# pylint: mode=test

WMI_SAMPLE = [
    rdf_protodict.Dict({
        u"Version": u"65.61.49216",
        u"InstallDate2": u"",
        u"Name": u"Google Chrome",
        u"Vendor": u"Google, Inc.",
        u"Description": u"Google Chrome",
        u"IdentifyingNumber": u"{35790B21-ACFE-33F5-B320-9DA320D96682}",
        u"InstallDate": u"20130710"
    }),
    rdf_protodict.Dict({
        u"Version": u"7.0.1",
        u"InstallDate2": u"",
        u"Name": u"Parity Agent",
        u"Vendor": u"Bit9, Inc.",
        u"Description": u"Parity Agent",
        u"IdentifyingNumber": u"{ADC7EB41-4CC2-4FBA-8FBE-9338A9FB7666}",
        u"InstallDate": u"20130710"
    }),
    rdf_protodict.Dict({
        u"Version": u"8.0.61000",
예제 #10
0
 def testEmbeddedDict(self):
   state = rdf_flow_runner.RequestState(data=rdf_protodict.Dict({"a": 1}))
   serialized = state.SerializeToString()
   deserialized = rdf_flow_runner.RequestState.FromSerializedString(serialized)
   self.assertEqual(deserialized.data, state.data)
예제 #11
0
 def GenerateSample(self, number=0):
   return rdf_protodict.Dict(foo=number, bar="hello")
예제 #12
0
 def testBool(self):
   sample = rdf_protodict.Dict(a=True)
   self.assertTrue(isinstance(sample["a"], bool))
   sample = rdf_protodict.Dict(a="true")
   self.assertEqual(sample["a"], "true")
예제 #13
0
 def Parse(self, stat, knowledge_base):
   _ = stat, knowledge_base
   test_dict = {"environ_temp": rdfvalue.RDFString("tempvalue"),
                "environ_path": rdfvalue.RDFString("pathvalue")}
   yield rdf_protodict.Dict(test_dict)
예제 #14
0
 def GetConfiguration(self, _):
   self.response_count += 1
   return [rdf_protodict.Dict({
       "Client.server_urls": ["http://localhost:8001/"],
       "Client.poll_min": 1.0
   })]