Configuration of a session

In Fuzzungus, just like in Boofuzz, configuration files define a fuzzing session, not a protocol to fuzz. The main difference here is that Boofuzz session configuration was quite basic, only giving examples of standalone scripts. In Fuzzungus, we tried to normalize the configuration process, with three steps :

  1. Instead of standalone configuration scripts, we now have a BaseConfig, from which every configuration file should enherit. That class creates and connect to the session and the targets in the backend through methods that shouldn’t be overriden, and defines a number of parameters that can be fixed in a subclass.

  2. Addition of a main.py file, that calls the configuration file and runs the session. This file is the one that should be run to start the fuzzing session. It also provides a useful number of CLI arguments.

  3. Normalization of the callback process, that now enherit from the BaseCallback class, or even from other callback classes, only overriding a few of the parent class’ methods. For more information on callbacks, see Callbacks.

Configuration files

Let’s take a look at how the BaseConfig is made, and then at an example configuration file.

BaseConfig

class boofuzz.BaseConfig(campaign_folder: str = None, log_level_stdout: int = 0, db_name: str = None, db_table_name: str | None = None)[source]

Bases: object

Base class for every configuration file. Below are the attributes of the general configuration :

Parameters:
  • host (str) – Host to connect to

  • port (int) – Port to connect to

  • callback_module (BaseCallback) – Callback module to use

  • socket (BaseSocketConnection) – Socket connection to use

  • recv_timeout (float) – Time to wait for a response

  • fuzz (bool) – Enable fuzzing

  • target_number (int) – Number of targets to add

  • external_monitor – External monitor to use. Should be instantiated in the configuration file.

  • meth_for_monitor_alive (list[Callable]) – List of methods to call for when the target is alive

  • pre_send (Callable) – Pre send callback

  • post_test_case (Callable) – Post test case callback

External_monitor:

BaseMonitor()

And here every Session attributes:

class Session(session_filename=None, index_start=1, index_end=None, sleep_time=0.0, restart_interval=0, web_port=26000, keep_web_open=True, console_gui=False, crash_threshold_request=12, crash_threshold_element=3, restart_sleep_time=5, restart_callbacks=None, restart_threshold=None, restart_timeout=None, pre_send_callbacks=None, post_test_case_callbacks=None, post_start_target_callbacks=None, rto_alpha_value: None | float = 0.125, rto_beta_value: None | float = 0.25, log_level_stdout=None, fuzz_loggers=None, fuzz_db_keep_only_n_pass_cases=0, receive_data_after_each_request=True, check_data_received_each_request=False, receive_data_after_fuzz=True, ignore_connection_reset=False, ignore_connection_aborted=False, ignore_connection_issues_when_sending_fuzz_data=True, ignore_connection_ssl_errors=False, reuse_target_connection=False, target: Target = None, target_to_use=0, web_address='127.0.0.1', db_filename=None, db_name: str = None, db_table_name: str | None = None, campaign_folder=None, seed_index: int = 0, round_type: str = 'library', max_number_of_rounds: int = 0, _total_random_mutation_rounds=0, nominal_test_interval: int = 50, nominal_data: list[Request | Callable] | None = None, nominal_recv_test: Callable[[Session], bool] | None = None, seconds_to_wait_after_restart: int = 3, max_depth: int = 1)

Extends pgraph.graph and provides a container for architecting protocol dialogs.

Parameters:
  • session_filename (str) – Filename to serialize persistent data to. Default None.

  • index_start (int)

  • index_end (int)

  • sleep_time (float) – Time in seconds to sleep in between tests. Default 0.

  • restart_interval (int) – Restart the target after n test cases, disable by setting to 0 (default).

  • console_gui (bool) – Use curses to generate a static console screen similar to the webinterface. Has not been tested under Windows. Works only if fuzz_loggers and log_level_stdout are kept to None. Default False.

  • crash_threshold_request (int) – Maximum number of crashes allowed before a request is exhausted. Default 12.

  • crash_threshold_element (int) – Maximum number of crashes allowed before an element is exhausted. Default 3.

  • restart_sleep_time (int) – Time in seconds to sleep when target can’t be restarted. Default 5.

  • restart_callbacks (list of method) – The registered method will be called after a failed post_test_case_callback Default None.

  • restart_threshold (int) – Maximum number of retries on lost target connection. Default None (indefinitely).

  • restart_timeout (float) – Time in seconds for that a connection attempt should be retried. Default None (indefinitely).

  • pre_send_callbacks (list of method) – The registered method will be called prior to each fuzz request. Default None.

  • post_test_case_callbacks (list of method) – The registered method will be called after each fuzz test case. Default None.

  • post_start_target_callbacks (list of method) – Method(s) will be called after the target is started or restarted, say, by a process monitor.

  • web_port (int or None) – Port for monitoring fuzzing campaign via a web browser. Set to None to disable the web app. Default 26000.

  • keep_web_open (bool) – Keep the webinterface open after session completion. Default True.

  • log_level_stdout (int) – If fuzz_loggers is kept to None, a FuzzLoggerText to stdout will be created with this log level. See FuzzLoggerText for explanation on log levels.

  • fuzz_loggers (list of ifuzz_logger.IFuzzLogger) – For saving test data and results. Default Log to stdout with a log level of 0.

  • fuzz_db_keep_only_n_pass_cases (int) – Minimize disk usage by only saving passing test cases if they are in the n test cases preceding a failure or error. Set to 0 to save after every test case (high disk I/O!). Default 0.

  • receive_data_after_each_request (bool) – If True, Session will attempt to receive a reply after transmitting each non-fuzzed node. Default True.

  • check_data_received_each_request (bool) – If True, Session will verify that some data has been received after transmitting each non-fuzzed node, and if not, register a failure. If False, this check will not be performed. Default False. A reception attempt is still made unless receive_data_after_each_request is False.

  • receive_data_after_fuzz (bool) – If True, Session will attempt to receive a reply after transmitting a fuzzed message. Default False.

  • ignore_connection_reset (bool) – Log ECONNRESET errors (“Target connection reset”) as “info” instead of failures.

  • ignore_connection_aborted (bool) – Log ECONNABORTED errors as “info” instead of failures.

  • ignore_connection_issues_when_sending_fuzz_data (bool) – Ignore fuzz data transmission failures. Default True. This is usually a helpful setting to enable, as targets may drop connections once a message is clearly invalid.

  • ignore_connection_ssl_errors (bool) – Log SSL related errors as “info” instead of failures. Default False.

  • reuse_target_connection (bool) – If True, only use one target connection instead of reconnecting each test case. Default False.

  • target (Target) – Target for fuzz session. Target must be fully initialized. Default None.

  • db_filename (str) – Not in use. Filename to store sqlite db for test results and case information. Defaults to ./boofuzz-results/{uniq_timestamp}.db

  • db_name (str) – Name of database. Defaults to {uniq_timestamp}

  • db_table_name (str | None) – Name of table in database.

  • campaign_folder (str) – Folder to store campaign files. Default None.

  • web_address – Address where’s Boofuzz logger exposed. Default ‘localhost’

  • round_type (str) – library - random_mutation - random_generation define how to mutate in the current round. Default “library”

  • seed_index (int) – Starting seed index that will be incremented for each round, Default 0. seed_index is concatenated with round_type to create a unique seed for each round.

  • max_number_of_rounds (int) – Maximum number of round. Useful in replay mode. Default to 0 (infinite.)

  • nominal_test_interval (int) – Test the health of target with nominal data after n test cases.

  • nominal_data (list[Request | CallbackFunction] | None) – List of nominal data. Call set_nominal_data().

  • nominal_recv_test (Callable[['Session'], bool] | None) – Test function after nominal data test.

  • seconds_to_wait_after_restart (int) – Time in seconds to wait after a target restart. Default 3.

  • rto_alpha_value (float) – See the Request.calculate_rto() method for more details.

  • rto_beta_value (float) – See the Request.calculate_rto() method for more details.

  • max_depth (int) – Maximum combinatorial depth used for fuzzing. num_mutations will return None if this value is None or greater than 1, as the number of mutations is typically very large when using combinatorial fuzzing. Set to 1 for “simple” fuzzing.

Changed in version 0.4.2: This class has been moved into the sessions subpackage. The full path is now boofuzz.sessions.session.Session.

Note

Not every Session attributes are hard-wired as parameters of this class below. We thougth of using a dictionnary to reproduce the behavior of *args and **kwargs in __init__ methods. But we decided to restrain the number of parameters to avoid confusion. So if you need a Session attribute that is not in the list below, you should edit this file and add it below.

callback_module

alias of BaseCallback

config() None[source]

Configuration file for every session

config_nominal() None[source]

Configuration of nominal data for test

external_monitor: BaseMonitor | None = None
fuzz: bool = True
graph_generation(graph_name) None[source]

Generate the graph of the session

host: str = ''
max_depth: int = 1
meth_for_monitor_alive: list[Callable] | None = None
static nominal_recv_test(session: Session) bool[source]
nominal_test_interval: int = 50
port: int = 0
post_test_case: Callable = None
pre_send: Callable = None
receive_data_after_each_request: bool = True
receive_data_after_fuzz: bool = True
recv_timeout: float = 10
restart_sleep_time: float = 1
round_type: str = 'library'
session_init() None[source]

Initialize the session with the target and the callbacks

sleep_time: float = 0
socket

alias of UDPSocketConnection

target_number: int = 1
uri: str = ''

Example configuration file

Here the example configuration file for TFTP overrides only some of the BaseConfig parameters, letting some of them to their default values.

Warning

For standardization purposes, the class name for every configuration module should always be Config. This can be changed or improved in the module boofuzz.BaseConfig, if you want more flexibility.

Nominal Data

During fuzzing, you can use nominal data to check if the target is still alive.

In the campaign configuration file, you have two functions that perform these tests.

Define

One is to define the nominal data :

def config_nominal(self) -> None:
    rrq = Request("rrq", children=(
        Static(name="opcode", default_value="\x00\x01"),
        Static(name="filename", default_value="nominal_test"),
        Static(name="null", default_value=b'\0'),
        Static(name="mode", default_value="octet"),
        Static(name="null2", default_value=b'\0'),
    ))
    self.session.set_nominal_data([rrq])

All primitives are Static because they are not fuzz.

The function set_nominal_data() accept a table of nominal data to send. These data can be request with only Static primitive or callback functions.

Example with FTP :

self.session.set_nominal_data([user, passw, cwd, pasv, callback.ParserPortPASV, type, ...])

Verify

The other function is to verify that the target respond well to the nominal data :

@staticmethod
def nominal_recv_test(session: Session) -> bool:
    expected_data = b'\x00\x03\x00\x01nominal_data\n'
    test = session.last_recv == expected_data
    if not test:
        session.get_fuzz_data_logger().log_info(f'Error in recv data (nominal test). The recv data should have been'
                                                f'"{expected_data}"')
    return test

This function must return a boolean.

You can see the skeleton of these both functions in the BaseConfig class.

Frequency

By default, this nominal test is perform every 50 test case, but this can be change.

nominal_test_interval: int = 50