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 :
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.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.
Normalization of the callback process, that now enherit from the
BaseCallbackclass, 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:
objectBase 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
Sessionattributes:- 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
Sessionattributes 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 aSessionattribute that is not in the list below, you should edit this file and add it below.- callback_module
alias of
BaseCallback
- external_monitor: BaseMonitor | None = None
- fuzz: bool = True
- host: str = ''
- max_depth: int = 1
- meth_for_monitor_alive: list[Callable] | None = None
- 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'
- 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