Skip to content

Commit

Permalink
Merge pull request #143 from jtpereyda/procmon-upgrades
Browse files Browse the repository at this point in the history
Procmon upgrades
  • Loading branch information
jtpereyda authored Apr 30, 2017
2 parents 6dfa4ba + 37ea667 commit 40ef710
Show file tree
Hide file tree
Showing 15 changed files with 235 additions and 177 deletions.
12 changes: 12 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,22 @@ Features
--------
- Console output - now with colors!
- process_monitor_unix.py: added option to move coredumps for later analysis
- The process monitor (procmon) now tracks processes by PID rather than searching by name. Therefore, stop_commands
and proc_name are no longer required.
- SIGINT (AKA Ctrl+C) now works to close both boofuzz and process_monitor.py (usually).
- Made Unix procmon more compatible with Windows.
- Improved procmon debugger error handling, e.g., when running 64-bit apps.
- Windows procmon now runs even if pydbg fails.
- Added `--help` parameter to process monitor.
- Target class now takes `procmon` and `procmon_options` in constructor.

Fixes
-----
- Fixed: The pedrpc module was not being properly included in imports.
- Made process_monitor.py --crash_bin optional (as documented).
- Improved procmon behavior when certain parameters aren't given.
- Improved procmon error handling.
- Fixed a bug in which the procmon would not properly restart a target that had failed without crashing.

0.0.7
=====
Expand Down
1 change: 1 addition & 0 deletions boofuzz/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ def __exit__(self, type, value, traceback):

return ScopedBlock(block)


def s_block_start(name, *args, **kwargs):
"""
Open a new block under the current request. This routine always returns an instance so you can make your fuzzer pretty
Expand Down
46 changes: 25 additions & 21 deletions boofuzz/pedrpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import socket
import cPickle

import select


class Client:
def __init__(self, host, port):
Expand Down Expand Up @@ -43,14 +45,14 @@ def __connect(self):
self.__server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.__server_sock.settimeout(3.0)
self.__server_sock.connect((self.__host, self.__port))
except:
except Exception:
if self.__retry != 5:
self.__retry += 1
time.sleep(5)
self.__connect()
else:
sys.stderr.write("PED-RPC> unable to connect to server %s:%d\n" % (self.__host, self.__port))
raise Exception
raise
# disable timeouts and lingering.
self.__server_sock.settimeout(None)
self.__server_sock.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, self.NOLINGER)
Expand Down Expand Up @@ -104,7 +106,7 @@ def __method_missing(self, method_name, *args, **kwargs):
try:
self.__pickle_send((method_name, (args, kwargs)))
break
except:
except Exception:
# re-connect to the PED-RPC server if the sock died.
self.__connect()

Expand All @@ -131,7 +133,7 @@ def __pickle_recv(self):
# it gets worse. you would think that simply returning here would break things, but it doesn't.
# gotta track this down at some point.
length = struct.unpack("<L", self.__server_sock.recv(4))[0]
except:
except Exception:
return

try:
Expand All @@ -141,9 +143,9 @@ def __pickle_recv(self):
chunk = self.__server_sock.recv(length)
received += chunk
length -= len(chunk)
except:
except Exception:
sys.stderr.write("PED-RPC> connection to server severed during recv()\n")
raise Exception
raise

return cPickle.loads(received)

Expand All @@ -165,9 +167,9 @@ def __pickle_send(self, data):
try:
self.__server_sock.send(struct.pack("<L", len(data)))
self.__server_sock.send(data)
except:
except Exception:
sys.stderr.write("PED-RPC> connection to server severed during send()\n")
raise Exception
raise


class Server:
Expand All @@ -184,7 +186,7 @@ def __init__(self, host, port):
self.__server.settimeout(None)
self.__server.bind((host, port))
self.__server.listen(1)
except:
except Exception:
sys.stderr.write("unable to bind to %s:%d\n" % (host, port))
sys.exit(1)

Expand Down Expand Up @@ -221,7 +223,7 @@ def __pickle_recv(self):
chunk = self.__client_sock.recv(length)
received += chunk
length -= len(chunk)
except:
except Exception:
sys.stderr.write("PED-RPC> connection client severed during recv()\n")
raise Exception

Expand All @@ -245,7 +247,7 @@ def __pickle_send(self, data):
try:
self.__client_sock.send(struct.pack("<L", len(data)))
self.__client_sock.send(data)
except:
except Exception:
sys.stderr.write("PED-RPC> connection to client severed during send()\n")
raise Exception

Expand All @@ -257,30 +259,32 @@ def serve_forever(self):
self.__disconnect()

# accept a client connection.
(self.__client_sock, self.__client_address) = self.__server.accept()
while True:
readable, writeable, errored = select.select([self.__server], [], [], .1)
if len(readable) > 0:
assert readable[0] == self.__server
(self.__client_sock, self.__client_address) = self.__server.accept()
break

self.__debug("accepted connection from %s:%d" % (self.__client_address[0], self.__client_address[1]))

# recieve the method name and arguments, continue on socket disconnect.
try:
(method_name, (args, kwargs)) = self.__pickle_recv()
self.__debug("%s(args=%s, kwargs=%s)" % (method_name, args, kwargs))
except:
except Exception:
continue

try:
# resolve a pointer to the requested method and call it.
# Wat.
exec("method_pointer = self.%s" % method_name)
# noinspection PyUnresolvedReferences
ret = method_pointer(*args, **kwargs)
method = getattr(self, method_name)
except AttributeError:
# if the method can't be found notify the user and raise an error
sys.stderr.write("PED-RPC> remote method %s cannot be found\n" % method_name)
continue
sys.stderr.write('PED-RPC> remote method "{0}" of {1} cannot be found\n'.format(method_name, self))
raise
ret = method(*args, **kwargs)

# transmit the return value to the client, continue on socket disconnect.
try:
self.__pickle_send(ret)
except:
except Exception:
continue
34 changes: 17 additions & 17 deletions boofuzz/sessions.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,21 +36,23 @@ class Target(object):
tcp_target = Target(SocketConnection(host='127.0.0.1', port=17971))
"""

def __init__(self, connection):
def __init__(self, connection, procmon=None, procmon_options=None):
"""
@type connection: itarget_connection.ITargetConnection
@param connection: Connection to system under test.
"""
self._fuzz_data_logger = None

self._target_connection = connection
self.procmon = procmon

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

def close(self):
Expand Down Expand Up @@ -82,8 +84,8 @@ def pedrpc_connect(self):
time.sleep(1)

# connection established.
for key in self.procmon_options.keys():
eval('self.procmon.set_%s(self.procmon_options["%s"])' % (key, key))
for key, value in self.procmon_options.items():
getattr(self.procmon, 'set_{0}'.format(key))(value)

# If the network monitor is alive, set it's options
if self.netmon:
Expand Down Expand Up @@ -599,7 +601,7 @@ def _process_failures(self, target):
self.total_mutant_index += skipped
self.fuzz_node.mutant_index += skipped

self.restart_target(target, stop_first=False)
self.restart_target(target)

# noinspection PyUnusedLocal
def post_send(self, target, fuzz_data_logger, session, sock, *args, **kwargs):
Expand Down Expand Up @@ -654,17 +656,14 @@ def pre_send(self, sock):
# default to doing nothing.
pass

def restart_target(self, target, stop_first=True):
def restart_target(self, target):
"""
Restart the fuzz target. If a VMControl is available revert the snapshot, if a process monitor is available
restart the target process. Otherwise, do nothing.
@type target: session.target
@param target: Target we are restarting
@type stop_first: bool
@param stop_first: Set to True to stop the target before starting.
@raise sex.BoofuzzRestartFailedError if restart fails.
"""

Expand All @@ -681,13 +680,11 @@ def restart_target(self, target, stop_first=True):
# if we have a connected process monitor, restart the target process.
elif target.procmon:
self._fuzz_data_logger.log_info("restarting target process")
if stop_first:
target.procmon.stop_target()

if not target.procmon.start_target():
if not target.procmon.restart_target():
raise sex.BoofuzzRestartFailedError()

# give the process a few seconds to settle in.
self._fuzz_data_logger.log_info("giving the process 3 seconds to settle in ")
time.sleep(3)

# otherwise all we can do is wait a while for the target to recover on its own.
Expand Down Expand Up @@ -750,9 +747,12 @@ def transmit(self, sock, node, edge):
self._fuzz_data_logger.log_pass("Some data received from target.")
except sex.BoofuzzTargetConnectionReset:
self._fuzz_data_logger.log_fail("Target connection reset.")
except sex.BoofuzzTargetConnectionAborted:
self._fuzz_data_logger.log_fail("Target connection lost: Software caused connection abort. You may have a"
" network issue, or an issue with firewalls or anti-virus.")
except sex.BoofuzzTargetConnectionAborted as e:
self._fuzz_data_logger.log_fail("Target connection lost (socket error: {0} {1}): You may have a network "
"issue, or an issue with firewalls or anti-virus. Try disabling your"
"firewall."
.format(e.socket_errno, e.socket_errmsg))
pass

def build_webapp_thread(self, port=26000):
app.session = self
Expand Down
8 changes: 7 additions & 1 deletion boofuzz/sex.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import attr
# Sulley EXception Class


Expand All @@ -17,8 +18,13 @@ class BoofuzzTargetConnectionReset(BoofuzzError):
pass


@attr.s
class BoofuzzTargetConnectionAborted(BoofuzzError):
pass
"""
Raised on `errno.ECONNABORTED`.
"""
socket_errno = attr.ib()
socket_errmsg = attr.ib()


class SullyRuntimeError(Exception):
Expand Down
5 changes: 3 additions & 2 deletions boofuzz/socket_connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ def recv(self, max_bytes):
data = bytes('')
except socket.error as e:
if e.errno == errno.ECONNABORTED:
raise_(sex.BoofuzzTargetConnectionAborted, None, sys.exc_info()[2])
raise_(sex.BoofuzzTargetConnectionAborted(socket_errno=e.errno, socket_errmsg=e.strerror), None, sys.exc_info()[2])
elif (e.errno == errno.ECONNRESET) or \
(e.errno == errno.ENETRESET) or \
(e.errno == errno.ETIMEDOUT):
Expand Down Expand Up @@ -214,7 +214,8 @@ def send(self, data):
raise sex.SullyRuntimeError("INVALID PROTOCOL SPECIFIED: %s" % self.proto)
except socket.error as e:
if e.errno == errno.ECONNABORTED:
raise_(sex.BoofuzzTargetConnectionAborted, None, sys.exc_info()[2])
raise_(sex.BoofuzzTargetConnectionAborted(socket_errno=e.errno, socket_errmsg=e.strerror),
None, sys.exc_info()[2])
elif (e.errno == errno.ECONNRESET) or \
(e.errno == errno.ENETRESET) or \
(e.errno == errno.ETIMEDOUT):
Expand Down
2 changes: 1 addition & 1 deletion boofuzz/utils/crash_binning.py
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ def last_crash_synopsis(self):
for (addr, handler, handler_str) in self.last_crash.seh_unwind:
try:
disasm = self.pydbg.disasm(handler)
except:
except Exception:
disasm = "[INVALID]"

synopsis += "\t%08x -> %s %s\n" % (addr, handler_str, disasm)
Expand Down
6 changes: 3 additions & 3 deletions network_monitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,11 @@ def create_usage(ifs):
# if there is a DHCP address snag that, otherwise fall back to the IP address.
try:
ip = _winreg.QueryValueEx(key, "DhcpIPAddress")[0]
except:
except Exception:
ip = _winreg.QueryValueEx(key, "IPAddress")[0][0]

pcapy_device = pcapy_device + "\t" + ip
except:
except Exception:
pass

message += " [%d] %s\n" % (index, pcapy_device)
Expand Down Expand Up @@ -282,7 +282,7 @@ def main():
# Now wait in a way that will not block signals like SIGINT
helpers.pause_for_signal()

except:
except Exception:
pass

if __name__ == "__main__":
Expand Down
Loading

0 comments on commit 40ef710

Please sign in to comment.