Session
- class boofuzz.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)[source]
Bases:
GraphExtends 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.
- _callback_current_node(node, edge, test_case_context)[source]
Execute callback preceding current node.
- Parameters:
test_case_context (ProtocolSession) – Context for test case-scoped data.
node (pgraph.node.node (Node), optional) – Current Request/Node
edge (pgraph.edge.edge (pgraph.edge), optional) – Edge along the current fuzz path from “node” to next node.
- Returns:
Data rendered by current node if any; otherwise None.
- Return type:
bytes
- _check_for_passively_detected_failures(target: Target, failure_already_detected=False)[source]
Check for and log passively detected failures. Return True if any found.
- Parameters:
target (Target) – Target to be checked for failures.
failure_already_detected (bool) – If a failure was already detected.
- Returns:
True if failures were found. False otherwise.
- Return type:
bool
- _check_message(mutation_context)[source]
Sends the current message without fuzzing.
Current test case is controlled by fuzz_case_iterator().
- Parameters:
mutation_context (MutationContext) – Current mutation context.
- _fuzz_current_case(mutation_context: MutationContext)[source]
Fuzzes the current test case. Current test case is controlled by fuzz_case_iterator().
- Parameters:
mutation_context (MutationContext) – Current mutation context.
- _fuzz_single_node_by_path(node_names)[source]
Fuzz a particular node via the path in node_names.
- Parameters:
node_names (list of str) – List of node names leading to target.
- _generate_mutations_for_request(path, skip_elements=None)[source]
Yield each mutation for a specific message (the last message in path).
- Parameters:
path (iter of str) – Nodes (Requests) along the path to the current one being fuzzed.
path – Qualified names of elements to skip while fuzzing.
- Yields:
Mutation – Mutation object describing a single mutation.
- _generate_mutations_indefinitely(path=None)[source]
Yield MutationContext with n mutations per message over all messages, with n increasing indefinitely.
- _generate_n_mutations(depth, path)[source]
Yield MutationContext with n mutations per message over all messages.
- _generate_n_mutations_for_path(path, depth)[source]
Yield MutationContext with n mutations for a specific message.
- Parameters:
path (list of Connection) – Nodes (Requests) along the path to the current one being fuzzed.
depth (int) – Yield sets of depth mutations.
- Yields:
MutationContext – A MutationContext containing one mutation.
- _get_monitor_data(target)[source]
Query monitors for any data they may want to add to this test case.
- Parameters:
target (Target) – Monitor to query data from.
- _iterate_protocol_message_paths(path=None)[source]
Iterates over protocol and yields a path (list of Connection) leading to a given message.
- Parameters:
path (list of Connection) – Provide a specific path to yield only that specific path.
- Yields:
list of Connection – List of edges along the path to the current one being fuzzed.
- Raises:
exception.SulleyRuntimeError – If no requests defined or no targets specified
- _iterate_protocol_message_paths_recursive(this_node, path)[source]
Recursive helper for _iterate_protocol.
- Parameters:
this_node (node.Node) – Current node that is being fuzzed.
path (list of Connection) – List of edges along the path to the current one being fuzzed.
- Yields:
list of Connection – List of edges along the path to the current one being fuzzed.
- _main_fuzz_loop(fuzz_case_iterator)[source]
Execute main fuzz logic; takes an iterator of test cases.
Preconditions: self.total_mutant_index and self.total_num_mutations are set properly.
- Parameters:
fuzz_case_iterator (Iterable) – An iterator that walks through fuzz cases and yields MutationContext objects. See _iterate_single_node() for details.
- Returns:
None
- _message_check(path)[source]
Check messages for compatibility.
Preconditions: self.total_mutant_index and self.total_num_mutations are set properly.
- Parameters:
path (list of Connection) – Nodes (Requests) along the path to the target one.
- Returns:
None
- _message_path_to_str(message_path)[source]
Converts a message path, iterable, to a string. Uses the dst key to get the name of the node. -> is used to separate the nodes.
- _num_mutations_recursive(this_node=None, path=None)[source]
Helper for num_mutations.
- Parameters:
this_node (request (node)) – Current node that is being fuzzed. Default None.
path (list) – Nodes along the path to the current one being fuzzed. Default [].
- Returns:
Total number of mutations in this session.
- Return type:
int
- _open_connection_keep_trying(target: Target)[source]
Open connection and if it fails, keep retrying.
- Parameters:
target (Target) – Target to open.
- _path_names_to_edges(node_names)[source]
Take a list of node names and return a list of edges describing that path.
- Parameters:
node_names (list of str) – List of node names describing a path.
- Returns:
List of edges describing the path in node_names.
- Return type:
list of Connection
- _pause_if_pause_flag_is_set()[source]
If that pause flag is raised, enter an endless loop until it is lowered.
- _pre_send(target: Target)[source]
Execute custom methods to run prior to each fuzz request. The order of events is as follows:
pre_send() - req - callback ... req - callback - post_send()
When fuzzing RPC for example, register this method to establish the RPC bind.
- Parameters:
target (session.target) – Target we are sending data to
- _process_failures(target)[source]
Process any failures in crash_synopses.
- If crash_synopses contains any entries, perform these failure-related actions:
log failure summary if needed
save failures to self.monitor_results (for website)
exhaust node if crash threshold is reached
target restart
Should be called after each fuzz test case.
- Parameters:
target (Target) – Target to restart if failure occurred.
- Returns:
True if any failures were found; False otherwise.
- Return type:
bool
- _restart_target(target: Target)[source]
Restart the fuzz target. If a VMControl is available revert the snapshot, if a process monitor is available restart the target process. If custom restart methods are registered, execute them. Otherwise, do nothing.
- Parameters:
target (session.target) – Target we are restarting
- Raises:
exception.BoofuzzRestartFailedError – if restart fails.
- _test_case_name(mutation_context)[source]
Get long test case name.
- Parameters:
mutation_context (MutationContext) – MutationContext to get name from.
- Returns:
Long formatted test case name
- add_node(node)[source]
Add a pgraph node to the graph. We overload this routine to automatically generate and assign an ID whenever a node is added.
- Parameters:
node (pgraph.Node) – Node to add to session graph
- add_target(target: Target)[source]
Add a target to the session. Multiple targets can be added for parallel fuzzing.
- Parameters:
target (Target) – Target to add to session
- calculate_total_round()[source]
Check how many random_mutation round is needed
Check the max(min(sizeof(Seclist), max_rounds_mutation)) and set _total_random_mutation_rounds
- Returns:
None
- check_max_number_of_rounds() None[source]
Function use to increment and check if the total number of round go beyond the max number of round.
- connect_boofuzz(src, dst=None, callback=None)[source]
Create a connection between the two requests (nodes) and register an optional callback to process in between transmissions of the source and destination request. The session class maintains a top level node that all initial requests must be connected to. Example:
sess = sessions.session() sess.connect(sess.root, s_get("HTTP"))
If given only a single parameter, sess.connect() will default to attaching the supplied node to the root node. This is a convenient alias. The following line is identical to the second line from the above example:
sess.connect(s_get("HTTP"))
Leverage callback methods to handle situations such as challenge response systems. A callback method must follow the message signature of
Session.example_test_case_callback(). Remember to include **kwargs for forward-compatibility.- Parameters:
- Returns:
The edge between the src and dst.
- Return type:
pgraph.Edge
- example_test_case_callback(target, fuzz_data_logger, session, test_case_context, *args, **kwargs)[source]
Example call signature for methods given to
connect()orregister_post_test_case_callback()- Parameters:
target (Target) – Target with sock-like interface.
fuzz_data_logger (ifuzz_logger.IFuzzLogger) – Allows logging of test checks and passes/failures. Provided with a test case and test step already opened.
session (Session) – Session object calling post_send. Useful properties include last_send and last_recv.
test_case_context (ProtocolSession) – Context for test case-scoped data.
ProtocolSessionsession_variablesvalues are generally set within a callback and referenced in elements via default values of typeProtocolSessionReference.args – Implementations should include *args and **kwargs for forward-compatibility.
kwargs – Implementations should include *args and **kwargs for forward-compatibility.
- property exec_speed
- fragmentation_check(sock, node: Request, edge, callback_data, mutation_context, transmit_type)[source]
Fragment data is needed, then call the original transmit_fuzz() method.
- Parameters:
sock (Target, optional) – Socket-like object on which to transmit node
node (pgraph.node.node (Node), optional) – Request/Node to transmit
edge (pgraph.edge.edge (pgraph.edge), optional) – Edge along the current fuzz path from “node” to next node.
callback_data (bytes) – Data from previous callback.
mutation_context (MutationContext) – Current mutation context.
- fuzz(name=None)[source]
Fuzz the entire protocol tree.
Iterates through and fuzzes all fuzz cases, skipping according to self.skip and restarting based on self.restart_interval.
If you want the web server to be available, your program must persist after calling this method. helpers.pause_for_signal() is available to this end.
- Parameters:
name (str) – Pass in a Request name to fuzz only a single request message. Pass in a test case name to fuzz only a single test case.
- Returns:
None
- fuzz_by_name(name)[source]
Fuzz a particular test case or node by name.
- Parameters:
name (str) – Name of node.
Deprecated since version 0.4.0: Use
Session.fuzz()instead.
- fuzz_indefinitely(name=None)[source]
Parent function of fuzz(). Is only used to call fuzz() in a loop. It fuzzes first with library mutations, then with random mutations, and then indefinitely with random generations.
- fuzz_single_case(mutant_index)[source]
Deprecated: Fuzz a test case by mutant_index.
Deprecation note: The new approach is to set Session’s start and end indices to the same value.
- Parameters:
mutant_index (int) – Positive non-zero integer.
- Returns:
None
- Raises:
sex.SulleyRuntimeError – If any error is encountered while executing the test case.
- get_fuzz_data_logger()[source]
Getter for the data logger. The data logger can be used to add log to the database. You can choose the log type (error, info, …)
- property netmon_results
- nominal_test() None[source]
This function is call each time the nominal_test_interval is reach.
- It is responsible for :
Open the target’s connection
Send the static requests or call the callback functions in order
Detect a failure
Close the target’s connection
Log everything
- num_mutations()[source]
Number of total mutations in the graph. The logic of this routine is identical to that of fuzz(). See fuzz() for inline comments. The member variable self.total_num_mutations is updated appropriately by this routine.
- Returns:
Total number of mutations in this session.
- Return type:
int
- property parent_session
Reference to the parent session of this request, so children can now access parameters of session.
- register_post_test_case_callback(method)[source]
Register a post-test case method.
The registered method will be called after each fuzz test case.
- Potential uses:
Closing down a connection.
Checking for expected responses.
The order of callback events is as follows:
pre_send() - req - callback ... req - callback - post-test-case-callback
- Parameters:
method (function) – A method with the same parameters as
post_send()
- property runtime
- set_nominal_data(nominal_data: list[Request | Callable] | None) None[source]
This function is used to set the nominal to test the target application every time the nominal_test_interval is reach.
The input is a list which contain Requests or Callback Functions. These elements will be used in order to test the target function. It’s like a tree in fuzzungus but with only one path.
All primitive who constitute the Requests have to be Static. Because it’s nominal data, fuzzungus didn’t have to fuzz these data.
If the input is None it will remove any nominal data.
- test_case_data(index)[source]
Return test case data object (for use by web server)
- Parameters:
index (int) – Test case index
- Returns:
Test case data object
- Return type:
DataTestCase
- transmit_all(sock, node: Request, edge, callback_data, mutation_context, transmit_type)[source]
Parent method for all transmission (normal and fuzzed) methods. This method is used to call the appropriate transmit method based on the current fuzzing state. This is done to allow to measure elapsed time between each transmission and to log it.
- Args :
sock (Target, optional): Socket-like object on which to transmit node node (pgraph.node.node (Node), optional): Request/Node to transmit edge (pgraph.edge.edge (pgraph.edge), optional): Edge along the current fuzz path from “node” to next node. callback_data (bytes): Data from previous callback. mutation_context (MutationContext): active mutation context transmit_type (str): Type of transmit. “normal” or “fuzz”.
- transmit_fuzz(sock, node: Request, edge, callback_data, mutation_context)[source]
Original transmit_fuzz() method of boofuzz, now encapsulated in a parent method that allows for fragmentation. Render and transmit a fuzzed node, process callbacks accordingly.
- Parameters:
sock (Target, optional) – Socket-like object on which to transmit node
node (pgraph.node.node (Node), optional) – Request/Node to transmit
edge (pgraph.edge.edge (pgraph.edge), optional) – Edge along the current fuzz path from “node” to next node.
callback_data (bytes) – Data from previous callback.
mutation_context (MutationContext) – Current mutation context.
- transmit_normal(sock, node: Request, edge, callback_data, mutation_context)[source]
Render and transmit a non-fuzzed node, process callbacks accordingly.
- Parameters:
sock (Target, optional) – Socket-like object on which to transmit node
node (pgraph.node.node (Node), optional) – Request/Node to transmit
edge (pgraph.edge.edge (pgraph.edge), optional) – Edge along the current fuzz path from “node” to next node.
callback_data (bytes) – Data from previous callback.
mutation_context (MutationContext) – active mutation context
Request-Graph visualisation options
The following methods are available to render data, which can then be used to visualise the request structure.
- Session.render_graph_gml()
Render the GML graph description.
- Returns:
GML graph description.
- Return type:
str
- Session.render_graph_graphviz()
Render the graphviz graph structure.
Example to create a png:
with open('somefile.png', 'wb') as file: file.write(session.render_graph_graphviz().create_png())
- Returns:
Pydot object representing entire graph
- Return type:
pydot.Dot
- Session.render_graph_udraw()
Render the uDraw graph description.
- Returns:
uDraw graph description.
- Return type:
str
- Session.render_graph_udraw_update()
Render the uDraw graph update description.
- Returns:
uDraw graph description.
- Return type:
str
Backward link to the session
Originally in Boofuzz, the children elements of a Session (e.g. Target, Request…) didn’t have a way to get back to the session.
This caused two problems :
In each primitive, we needed a way to know the current round type (e.g Library, Random Mutation, or Random Generation), and for the last two, to get a seed for the random. We found that the best way to standardized the process of choosing the round type and the seed accross all primitives of a session was to define those elements in a
Sessionobject, thus the need to access it from each primitive. Considering that they already had access to their request, we decided to simply give access to theRequestof its session. Each of them can now access it using theself.request.parent_sessionattribute. The process of linking the request to the session is done in theSession.connect()method.In the target, we needed a way to inform the session of a socket timeout from one of the
BaseSocketConnectioninherited classes. That was necessary to be able to skip the test case causing the timeout, not to stay stuck in it. We first add to give access to the Target with theBaseSocketConnection.parent_target, then to link theTargetobject to itSessionobject through theTarget.parent_sessionattribute. This is done in theBaseConfigclass.
Timeout calculation
In Fuzzungus, we wanted to be able to flag a timeout on a test case to identify delay variations of the target that could be a sign of a crash. To do that, we needed to calculate the timeout of each test case separatly.
We added a new attributes to the Request object : timeout_check : A boolean to be able to skip the timeout check on a specific request, for example for data nodes for which the timeout is not relevant.
For timeout calculation, we used the TCP formula :
See the RFC 6298 - Computing TCP’s Retransmission Timer for more informations on the calculations.
They are implemented in Request through the Request.calculate_rto() method. This method is called in Session.transmit_all(), that calculates RTO the same way for fuzzed and normally transmited nodes.
Session.transmit_all() is another addition to Boofuzz, to avoid implementing the same action two times for the Session._transmit_fuzz() and Session._transmit_normal() methods.
Fragmentation
In some protocols, the length of some packets depends on the configuration of the communication. When the fragmentation must be done in the application layer, we have to define it in the Request definition.
For that, we have to define 2 attributes, Request.fragmentation_length and Request.fragmentation.
Request.fragmentation_length is the packet’s data size.
Request.fragmentation is a function that must be defined by your own in the callback file that you import for the session.
We implemented a TFTP fragmentation function in tftp_callback.py which increment the block’s number properly and concatenate it with the maximum of data that it can.
When a request with the attribute Request.fragmentation is fuzzed, the whole of the data are generated by first and then cut. Send and receive are looped while the fragmentation function yield something.
Multiple Acks
Multiple acks are used in case of an application has to send us data which are truncated, and we have to reply to each data block before fuzz the rest of the session.
That case is handled by a callback function which has to be defined in the callback file that we import for the session, and it has to be connected. (refer to callbacks)
An example of multiple acks is given for the TFTP protocols in the tftp_callback.py file. The callback function is connected after a read request. It receives the data, get the numblock, and send an ack with the right block.