Example #1
0
    def run(self, fuzz: bool = True, retry: bool = True) -> bool:
        """
        Run the test case, transmitting the full path

        Args:
            fuzz:   (default True) Send the fuzzed node. If it is false, it transmit the original (for tests)
            retry:  (default True) Retry if connection fails

        Returns: True if the TestCase was run and data was transmitted (even if transmission was cut)
                 False if there was a connection issue and the target was paused, so the TestCase was not run
        """
        # First step is to open the target
        # TODO: Mechanism for not opening if want to keep an open connection between fuzzed packets
        #  (e.g. CLI in Telnet Session)
        try:
            self.logger.open_test_case(
                f"{self.id}: {self.name} {'[SENDING ORIGINAL]' if not fuzz else ''}",
                name=self.name,
                index=self.id)
            self.logger.log_info(
                f"Type: {type(self.request.mutant).__name__}. "
                f"Default value: {repr(self.request.mutant.original_value)}. "
                f"Case {self.id} of {self.session.num_mutations} overall.")

            self.open_fuzzing_target(retry=retry)

            fuzzed_sent = False
            for idx, edge in enumerate(
                    self.path, start=1
            ):  # Now we go through our path, sending each request
                request = edge.dst
                callback = edge.callback

                if request == self.request:
                    # This is the node we are fuzzing
                    if fuzz:
                        self.logger.open_test_step(
                            f'Fuzzing node {request.name}')
                        callback_data = self._callback_current_node(
                            node=request, edge=edge)
                        self.transmit(request, callback_data=callback_data)
                        fuzzed_sent = True
                    else:
                        self.logger.open_test_step(
                            f'Transmit node {request.name}')
                        callback_data = self._callback_current_node(
                            node=request, edge=edge, original=True)
                        self.transmit(request,
                                      callback_data=callback_data,
                                      original=True)

                else:
                    # This is a node we are not fuzzing right now
                    self.logger.open_test_step(f'Transmit node {request.name}')
                    callback_data = self._callback_current_node(node=request,
                                                                edge=edge,
                                                                original=True)
                    self.transmit(request,
                                  callback_data=callback_data,
                                  original=not fuzzed_sent)

                if self.session.opts.new_connection_between_requests and len(
                        self.path) > idx:  # Reopen connection
                    try:
                        self.session.target.close()
                        self.open_fuzzing_target(retry=False)
                    except (exception.FuzzowskiTargetConnectionFailedError,
                            Exception) as e:
                        self.add_error(e)
                        self.session.add_suspect(self)
                        raise exception.FuzzowskiTestCaseAborted(str(e))

            self.session.target.close()
            self.session.add_latest_test(self)
            return True
        except exception.FuzzowskiPaused:
            return False  # Returns False when the fuzzer got paused, as it did not run the TestCase
        except exception.FuzzowskiTestCaseAborted as e:  # There was a transmission Error, we end the test case
            self.logger.log_info(
                f'Test case aborted due to transmission error: {str(e)}')
            self.session.add_latest_test(self)
            return True
Example #2
0
    def transmit(self,
                 request: Request,
                 callback_data: bytes = None,
                 original: bool = False,
                 receive=True):
        """
        Render and transmit a fuzzed node, process callbacks accordingly.

        Args:
            request: Request that is being fuzzed
            callback_data: callback data from a previous callback
            original: if True, will send the original value and not render
            receive: if True, it will try to receive data after sending the request

        Returns: None
        Raises: FuzzowskiTestCaseAborted when a transmission error occurs
        """
        if callback_data:
            data = callback_data
        else:
            if original:
                data = request.original_value
            else:
                data = request.render()

        # 1. SEND DATA
        try:
            self.last_send = data
            self.session.target.send(data)
        except exception.FuzzowskiTargetConnectionReset as e:  # Connection was reset
            self.logger.log_info("Target connection reset.")
            condition = self.session.opts.ignore_transmission_errors if original \
                else self.session.opts.ignore_connection_issues_after_fuzz
            if not condition:
                self.add_error(e)
                self.session.add_suspect(self)
            raise exception.FuzzowskiTestCaseAborted(
                str(e))  # Abort TestCase, Connection Reset
        except exception.FuzzowskiTargetConnectionAborted as e:
            msg = f"Target connection lost (socket error: {e.socket_errno} {e.socket_errmsg})"
            condition = self.session.opts.ignore_transmission_errors if original \
                else self.session.opts.ignore_connection_issues_after_fuzz
            if condition:
                self.logger.log_info(msg)
            else:
                self.logger.log_fail(msg)
                self.add_error(e)
                self.session.add_suspect(self)
                raise exception.FuzzowskiTestCaseAborted(
                    str(e))  # Abort TestCase, Connection Failed

        # 2. RECEIVE DATA
        if receive:
            try:
                receive_failed = False
                error = ''
                self.last_recv = self.session.target.recv_all(DEFAULT_MAX_RECV)
                if not self.last_recv:  # Nothing received, probably conn reset
                    receive_failed = True
                    error = "Nothing received. Connection Reset?"
                    # raise exception.FuzzowskiTestCaseAborted("Receive failed. Aborting Test Case")
                elif len(request.responses
                         ) > 0:  # Data received, Responses defined
                    try:
                        self.logger.log_check(
                            "Parsing response with data received")
                        response_str = request.parse_response(self.last_recv)
                        self.logger.log_info(response_str)
                        receive_failed = False
                    except exception.FuzzowskiRuntimeError as e:  # Data received, Response do not match
                        self.logger.log_fail(str(e))  # Abort TestCase
                        receive_failed = False
                        raise exception.FuzzowskiTestCaseAborted(str(e))
                    except Exception as e:  # Any other exception not controlled by the Restarter module
                        self.logger.log_fail(str(e))
                        self.session.is_paused = True  # Pause the session if an uncontrolled error occurs
                        raise exception.FuzzowskiTestCaseAborted(str(e))
                else:  # Data received, no Responses defined
                    receive_failed = False

                if self.session.opts.check_data_received_each_request:
                    self.logger.log_check("Checking data received...")
                    if receive_failed:
                        # Assume a crash?
                        self.logger.log_fail(
                            f"Nothing received from target. {error}")
                        self.session.add_suspect(self)
                        raise exception.FuzzowskiTestCaseAborted(
                            "Receive failed. Aborting Test Case")

            except exception.FuzzowskiTargetConnectionReset as e:  # Connection reset
                self.logger.log_info("Target connection reset.")
                if self.session.opts.check_data_received_each_request:
                    self.logger.log_fail("Target connection reset.")
                    self.add_error(e)
                    self.session.add_suspect(self)
                raise exception.FuzzowskiTestCaseAborted(str(e))
            except exception.FuzzowskiTargetConnectionAborted as e:
                msg = f"Target connection lost (socket error: {e.socket_errno} {e.socket_errmsg})"
                if self.session.opts.check_data_received_each_request:
                    self.logger.log_fail(msg)
                    self.add_error(e)
                    self.session.add_suspect(self)
                else:
                    self.logger.log_info(msg)
                raise exception.FuzzowskiTestCaseAborted(str(e))