Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parallel targets support #680

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 28 additions & 26 deletions boofuzz/sessions.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import zlib
from builtins import input
from io import open
from itertools import cycle

from tornado.httpserver import HTTPServer
from tornado.ioloop import IOLoop
Expand Down Expand Up @@ -1058,7 +1059,7 @@ def _restart_target(self, target):

if restarted:
for monitor in target.monitors:
monitor.post_start_target(target=self.targets[0], fuzz_data_logger=self._fuzz_data_logger, session=self)
monitor.post_start_target(target=target, fuzz_data_logger=self._fuzz_data_logger, session=self)
else:
self._fuzz_data_logger.log_info(
"No reset handler available... sleeping for {} seconds".format(self.restart_sleep_time)
Expand All @@ -1075,7 +1076,7 @@ def server_init(self):
# spawn the web interface.
self.web_interface_thread.start()

def _callback_current_node(self, node, edge, test_case_context):
def _callback_current_node(self, target, node, edge, test_case_context):
"""Execute callback preceding current node.

Args:
Expand All @@ -1092,7 +1093,7 @@ def _callback_current_node(self, node, edge, test_case_context):
if edge.callback:
self._fuzz_data_logger.open_test_step("Callback function '{0}'".format(edge.callback.__name__))
data = edge.callback(
self.targets[0],
target,
self._fuzz_data_logger,
session=self,
node=node,
Expand All @@ -1102,7 +1103,7 @@ def _callback_current_node(self, node, edge, test_case_context):

return data

def transmit_normal(self, sock, node, edge, callback_data, mutation_context):
def transmit_normal(self, target, node, edge, callback_data, mutation_context):
"""Render and transmit a non-fuzzed node, process callbacks accordingly.

Args:
Expand All @@ -1118,7 +1119,7 @@ def transmit_normal(self, sock, node, edge, callback_data, mutation_context):
data = node.render(mutation_context=mutation_context)

try: # send
self.targets[0].send(data)
target.send(data)
self.last_send = data
except exception.BoofuzzTargetConnectionReset:
# TODO: Switch _ignore_connection_reset for _ignore_transmission_error, or provide retry mechanism
Expand All @@ -1141,7 +1142,7 @@ def transmit_normal(self, sock, node, edge, callback_data, mutation_context):

try: # recv
if self._receive_data_after_each_request:
self.last_recv = self.targets[0].recv()
self.last_recv = target.recv()

if self._check_data_received_each_request:
self._fuzz_data_logger.log_check("Verify some data was received from the target.")
Expand All @@ -1167,7 +1168,7 @@ def transmit_normal(self, sock, node, edge, callback_data, mutation_context):
else:
raise BoofuzzFailure(str(e))

def transmit_fuzz(self, sock, node, edge, callback_data, mutation_context):
def transmit_fuzz(self, target, node, edge, callback_data, mutation_context):
"""Render and transmit a fuzzed node, process callbacks accordingly.

Args:
Expand All @@ -1183,7 +1184,7 @@ def transmit_fuzz(self, sock, node, edge, callback_data, mutation_context):
data = self.fuzz_node.render(mutation_context)

try: # send
self.targets[0].send(data)
target.send(data)
self.last_send = data
except exception.BoofuzzTargetConnectionReset:
if self._ignore_connection_issues_when_sending_fuzz_data:
Expand All @@ -1205,7 +1206,7 @@ def transmit_fuzz(self, sock, node, edge, callback_data, mutation_context):
received = b""
try: # recv
if self._receive_data_after_fuzz:
received = self.targets[0].recv()
received = target.recv()
except exception.BoofuzzTargetConnectionReset:
if self._check_data_received_each_request:
raise BoofuzzFailure(message=constants.ERR_CONN_RESET)
Expand Down Expand Up @@ -1349,7 +1350,8 @@ def _message_check(self, path):
self.server_init()

try:
self._check_message(MutationContext(message_path=path, mutations={}))
for target in self.targets:
self._check_message(MutationContext(message_path=path, mutations={}), target)
except KeyboardInterrupt:
# TODO: should wait for the end of the ongoing test case, and stop gracefully netmon and procmon
self.export_file()
Expand Down Expand Up @@ -1382,13 +1384,15 @@ def _main_fuzz_loop(self, fuzz_case_iterator):
self.server_init()

try:
self._start_target(self.targets[0])
for target in self.targets:
self._start_target(target)

if self._reuse_target_connection:
target.open()

if self._reuse_target_connection:
self.targets[0].open()
self.num_cases_actually_fuzzed = 0
self.start_time = time.time()
for mutation_context in fuzz_case_iterator:
for mutation_context, target in zip(fuzz_case_iterator, cycle(self.targets)):
if self.total_mutant_index < self._index_start:
continue

Expand All @@ -1399,17 +1403,18 @@ def _main_fuzz_loop(self, fuzz_case_iterator):
and self.num_cases_actually_fuzzed % self.restart_interval == 0
):
self._fuzz_data_logger.open_test_step("restart interval of %d reached" % self.restart_interval)
self._restart_target(self.targets[0])
self._restart_target(target)

self._fuzz_current_case(mutation_context)
self._fuzz_current_case(mutation_context, target)

self.num_cases_actually_fuzzed += 1

if self._index_end is not None and self.total_mutant_index >= self._index_end:
break

if self._reuse_target_connection:
self.targets[0].close()
for target in self.targets:
target.close()

if self._keep_web_open and self.web_port is not None:
self.end_time = time.time()
Expand Down Expand Up @@ -1622,15 +1627,14 @@ def _path_names_to_edges(self, node_names):
cur_node = next_node
return edge_path

def _check_message(self, mutation_context):
def _check_message(self, mutation_context, target):
"""Sends the current message without fuzzing.

Current test case is controlled by fuzz_case_iterator().

Args:
mutation_context (MutationContext): Current mutation context.
"""
target = self.targets[0]
self.total_mutant_index += 1

self._pause_if_pause_flag_is_set()
Expand Down Expand Up @@ -1659,7 +1663,7 @@ def _check_message(self, mutation_context):
)
mutation_context.protocol_session = protocol_session
self._fuzz_data_logger.open_test_step("Prep Node '{0}'".format(node.name))
callback_data = self._callback_current_node(node=node, edge=e, test_case_context=protocol_session)
callback_data = self._callback_current_node(target=target, node=node, edge=e, test_case_context=protocol_session)
self.transmit_normal(target, node, e, callback_data=callback_data, mutation_context=mutation_context)

prev_node = self.nodes[mutation_context.message_path[-1].src]
Expand All @@ -1670,7 +1674,7 @@ def _check_message(self, mutation_context):
)
mutation_context.protocol_session = protocol_session
callback_data = self._callback_current_node(
node=self.fuzz_node, edge=mutation_context.message_path[-1], test_case_context=protocol_session
target=target, node=self.fuzz_node, edge=mutation_context.message_path[-1], test_case_context=protocol_session
)

self._fuzz_data_logger.open_test_step("Node Under Test '{0}'".format(self.fuzz_node.name))
Expand Down Expand Up @@ -1700,7 +1704,7 @@ def _check_message(self, mutation_context):
self._fuzz_data_logger.close_test_case()
self.export_file()

def _fuzz_current_case(self, mutation_context):
def _fuzz_current_case(self, mutation_context, target):
"""
Fuzzes the current test case. Current test case is controlled by
fuzz_case_iterator().
Expand All @@ -1709,8 +1713,6 @@ def _fuzz_current_case(self, mutation_context):
mutation_context (MutationContext): Current mutation context.

"""
target = self.targets[0]

self._pause_if_pause_flag_is_set()

test_case_name = self._test_case_name(mutation_context)
Expand Down Expand Up @@ -1753,7 +1755,7 @@ def _fuzz_current_case(self, mutation_context):
current_message=node,
)
mutation_context.protocol_session = protocol_session
callback_data = self._callback_current_node(node=node, edge=e, test_case_context=protocol_session)
callback_data = self._callback_current_node(target=target, node=node, edge=e, test_case_context=protocol_session)
self._fuzz_data_logger.open_test_step("Transmit Prep Node '{0}'".format(node.name))
self.transmit_normal(target, node, e, callback_data=callback_data, mutation_context=mutation_context)

Expand All @@ -1765,7 +1767,7 @@ def _fuzz_current_case(self, mutation_context):
)
mutation_context.protocol_session = protocol_session
callback_data = self._callback_current_node(
node=self.fuzz_node, edge=mutation_context.message_path[-1], test_case_context=protocol_session
target=target, node=self.fuzz_node, edge=mutation_context.message_path[-1], test_case_context=protocol_session
)
self._fuzz_data_logger.open_test_step("Fuzzing Node '{0}'".format(self.fuzz_node.name))
self.transmit_fuzz(
Expand Down