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

Alternative interfaces #93

Open
wants to merge 15 commits into
base: sulley_refactor
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 7 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
79 changes: 79 additions & 0 deletions sulley/fuzz_logger.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import ifuzz_logger
import os
import errno


class FuzzLogger(ifuzz_logger.IFuzzLogger):
"""
IFuzzLogger that saves sent and received data to files within a directory.

File format is: <mutation nubmer>-(rx|tx)-<sequence number>.txt
"""

def __init__(self, path):
"""
:param path: Directory in which to save fuzz data.
"""
self._path = path
self._current_id = ''
self._rx_count = 0
self._tx_count = 0

# mkdir -p self._path
try:
os.makedirs(self._path)
except OSError as exc:
if exc.errno == errno.EEXIST and os.path.isdir(path):
pass
else:
raise

def open_test_case(self, test_case_id):
"""
Open a test case - i.e., a fuzzing mutation.

:param test_case_id: Test case name/number. Should be unique.

:return: None
"""
self._current_id = str(test_case_id)
self._rx_count = 0
self._tx_count = 0

def log_send(self, data):
"""
Records data as about to be sent to the target.

:param data: Transmitted data
:type data: buffer

:return: None
:rtype: None
"""
self._tx_count += 1

filename = "{0}-tx-{1}.txt".format(self._current_id, self._tx_count)
full_name = os.path.join(self._path, filename)

# Write data in binary mode to avoid newline conversion
with open(full_name, "wb") as file_handle:
file_handle.write(data)

def log_recv(self, data):
"""
Records data as having been received from the target.

:param data: Received data.
:type data: buffer

:return: None
:rtype: None
"""
self._rx_count += 1

filename = "{0}-rx-{1}.txt".format(self._current_id, self._tx_count)
full_name = os.path.join(self._path, filename)

# Write data in binary mode to avoid newline conversion
with open(full_name, "wb") as file_handle:
file_handle.write(data)
45 changes: 45 additions & 0 deletions sulley/ifuzz_logger.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import abc


class IFuzzLogger(object):
"""
Abstract class for logging fuzz data. Allows for logging approaches.
"""
__metaclass__ = abc.ABCMeta

@abc.abstractmethod
def open_test_case(self, test_case_id):
"""
Open a test case - i.e., a fuzzing mutation.

:param test_case_id: Test case name/number. Should be unique.

:return: None
"""
raise NotImplementedError

@abc.abstractmethod
def log_send(self, data):
"""
Records data as about to be sent to the target.

:param data: Transmitted data
:type data: buffer

:return: None
:rtype: None
"""
raise NotImplementedError

@abc.abstractmethod
def log_recv(self, data):
"""
Records data as having been received from the target.

:param data: Received data.
:type data: buffer

:return: None
:rtype: None
"""
raise NotImplementedError
51 changes: 51 additions & 0 deletions sulley/itarget_connection.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import abc


class ITargetConnection(object):
"""
Interface for connections to fuzzing targets.
Target connections may be opened and closed multiple times. You must open before using send/recv and close
afterwards.
"""
__metaclass__ = abc.ABCMeta

@abc.abstractmethod
def close(self):
"""
Close connection.

:return: None
"""
raise NotImplementedError

@abc.abstractmethod
def open(self):
"""
Opens connection to the target. Make sure to call close!

:return: None
"""
raise NotImplementedError

@abc.abstractmethod
def recv(self, max_bytes):
"""
Receive up to max_bytes data.

:param max_bytes: Maximum number of bytes to receive.
:type max_bytes: int

:return: Received data. bytes('') if no data is received.
"""
raise NotImplementedError

@abc.abstractmethod
def send(self, data):
"""
Send data to the target.

:param data: Data to send.

:return: None
"""
raise NotImplementedError
85 changes: 85 additions & 0 deletions sulley/serial_connection.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import itarget_connection
import serial


class SerialConnection(itarget_connection.ITargetConnection):
"""
ITargetConnection implementation using serial ports.

Messages are time-delimited, based on a parameter given to the constructor.
"""

def __init__(self, port, baudrate, message_separator_time=0.300):
"""
@type port: int | str
@param port: Serial port name or number.
@type baudrate: int
@param baudrate: Baud rate for port.
@type message_separator_time: float
@param message_separator_time: The amount of time to wait before considering a reply from the target complete.
"""
self._device = None
self.port = port
self.baudrate = baudrate
self.logger = None
self.message_separator_time = message_separator_time

def close(self):
"""
Close connection to the target.

:return: None
"""
self._device.close()

def open(self):
"""
Opens connection to the target. Make sure to call close!

:return: None
"""
self._device = serial.Serial(port=self.port, baudrate=self.baudrate)

def recv(self, max_bytes):
"""
Receive up to max_bytes data from the target.

:param max_bytes: Maximum number of bytes to receive.
:type max_bytes: int

:return: Received data.
"""

self._device.timeout = self.message_separator_time

fragment = self._device.read(size=1024)
data = fragment

# Serial ports can be slow and render only a few bytes at a time.
# Therefore, we keep reading until we get nothing, in hopes of getting a full packet.
while fragment:
fragment = self._device.read(size=1024)
data += fragment

return data

def send(self, data):
"""
Send data to the target. Only valid after calling open!

:param data: Data to send.

:return: None
"""
self._device.write(data)

def set_logger(self, logger):
"""
Set this object's (and it's aggregated classes') logger.

:param logger: Logger to use.
:type logger: logging.Logger

:return: None
"""
self.logger = logger
35 changes: 35 additions & 0 deletions sulley/serial_target.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import sessions
import serial_connection


class SerialTarget(sessions.Target):
"""
Target class that uses a SerailConnection. Serial messages are assumed to be time-separated.
Encapsulates connection logic for the target, as well as pedrpc connection logic.

Contains a logger which is configured by Session.add_target().
"""

def __init__(self, port=0, baudrate=9600, message_separator_time=0.300):
"""
@type port: int | str
@param port: Serial port name or number.
@type baudrate: int
@param baudrate: Baud rate for port.
@type message_separator_time: float
@param message_separator_time: The amount of time to wait before considering a reply from the target complete.
"""
super(SerialTarget, self).__init__(host="", port=1)

self._target_connection = serial_connection.SerialConnection(
port=port,
baudrate=baudrate,
message_separator_time=message_separator_time)

# set these manually once target is instantiated.
self.netmon = None
self.procmon = None
self.vmcontrol = None
self.netmon_options = {}
self.procmon_options = {}
self.vmcontrol_options = {}
Loading