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

Sulley refactor #99

Open
wants to merge 23 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
34969dc
Just an insane amount of refactoring. Mostly just getting things gree…
Fitblip Jun 12, 2014
c6a0c28
Oops, forgot to include the actual changes!
Fitblip Jun 12, 2014
d90779e
Another massive refactor (sessions.py)
Fitblip Jun 13, 2014
756257c
Add helpers
Fitblip Jun 13, 2014
2ab686a
Refactor pgraph stuff
Fitblip Jun 15, 2014
b297f26
Refactor legos
Fitblip Jun 15, 2014
b5fee52
Refactor a bunch of utilities/helpers
Fitblip Jun 15, 2014
aa7f641
Refactor of a bunch of other stuff. No more inspection warnings!
Fitblip Jul 22, 2014
f3c7a83
Replace BaseHTTPServer with flask app.
Fitblip Jul 23, 2014
23362d6
Refactor into templates with actual CSS files.
Fitblip Jul 26, 2014
b762c7d
Fix some OCD crap.
Fitblip Jul 26, 2014
6da9f31
Add some assert fixes and a better repr() method.
Fitblip Jul 26, 2014
5a0ec2c
Missed these in the node -> Node class refactor.
Fitblip Jul 26, 2014
93ed66f
First run at the "new" sulley fuzz definition file.
Fitblip Jul 26, 2014
348968e
Stubs for breaking the fuzzing engine into it's own abstraction
Fitblip Jul 26, 2014
10976e6
Lots of syntactical changes to vmcontrol.
Fitblip Aug 14, 2014
f7f47d0
Only 19 more inspection errors to go! woo hoo!
Fitblip Aug 15, 2014
1d3431c
Add a MustImplementException for people sub-classing a base Fuzzer class
Fitblip Aug 17, 2014
3749f7e
Bug fixes
amoshkina Nov 26, 2014
f567d2a
Fixed assertion if sulley/primitives.py, removed mutable default
amoshkina Nov 26, 2014
5e3355c
Added setup.py
amoshkina Nov 26, 2014
256c21d
Changed type check to isinstance check
amoshkina Nov 27, 2014
0911500
Merge pull request #72 from amoshkina/sulley_refactor
Fitblip Jun 16, 2015
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
Prev Previous commit
Next Next commit
Replace BaseHTTPServer with flask app.
Another night, another massive refactor :-P
  • Loading branch information
Fitblip committed Jul 23, 2014
commit f3c7a83bd0ae10f37fcf6e0b4dbe5642f6867706
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
*.pyc
archived_fuzzies/*.session
.idea/
.idea/
testing/
313 changes: 17 additions & 296 deletions sulley/sessions.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import re
import sys
import zlib
import time
Expand All @@ -7,7 +6,6 @@
import signal
import cPickle
import threading
import BaseHTTPServer
import httplib
import logging
import blocks
Expand All @@ -17,6 +15,11 @@

from helpers import get_max_udp_size

from tornado.wsgi import WSGIContainer
from tornado.httpserver import HTTPServer
from tornado.ioloop import IOLoop
from web.app import app

class Target(object):
"""
Target descriptor container.
Expand Down Expand Up @@ -147,7 +150,7 @@ def __init__(self, session_filename=None, skip=0, sleep_time=1.0, log_level=logg
except:
self.signal_module = False

self.web_interface_thread = WebInterfaceThread(self)
self.web_interface_thread = self.build_webapp_thread(port=26000)
self.session_filename = session_filename
self.skip = skip
self.sleep_time = sleep_time
Expand Down Expand Up @@ -184,7 +187,7 @@ def __init__(self, session_filename=None, skip=0, sleep_time=1.0, log_level=logg
self.netmon_results = {}
self.procmon_results = {}
self.protmon_results = {}
self.pause_flag = False
self.is_paused = False
self.crashing_primitives = {}

if self.proto == "tcp":
Expand Down Expand Up @@ -331,7 +334,7 @@ def export_file(self):
"netmon_results" : self.netmon_results,
"procmon_results" : self.procmon_results,
"protmon_results" : self.protmon_results,
"pause_flag" : self.pause_flag
"is_paused" : self.is_paused
}

fh = open(self.session_filename, "wb+")
Expand Down Expand Up @@ -564,7 +567,7 @@ def import_file(self):
self.netmon_results = data["netmon_results"]
self.procmon_results = data["procmon_results"]
self.protmon_results = data["protmon_results"]
self.pause_flag = data["pause_flag"]
self.is_paused = data["is_paused"]

def log(self, msg, level=1):
raise Exception("Depreciated!")
Expand Down Expand Up @@ -607,7 +610,7 @@ def pause(self):
If that pause flag is raised, enter an endless loop until it is lowered.
"""
while 1:
if self.pause_flag:
if self.is_paused:
time.sleep(1)
else:
break
Expand Down Expand Up @@ -662,10 +665,6 @@ def poll_pedrpc(self, target):
if not self.restart_target(target, stop_first=False):
self.logger.critical("Restarting the target failed, exiting.")
self.export_file()
try:
self.web_interface_thread.join()
except:
self.logger.debug("No server launched")
sys.exit(0)

def post_send(self, sock):
Expand Down Expand Up @@ -762,11 +761,6 @@ def exit_abruptly(signal_recv, frame_recv):
"""
self.export_file()
self.logger.critical("SIGINT received ... exiting")
try:
self.web_interface_thread.join()
except:
self.logger.debug("No server launched")

sys.exit(0)
signal.signal(signal.SIGINT, exit_abruptly)

Expand Down Expand Up @@ -832,283 +826,10 @@ def transmit(self, sock, node, edge):
# Note crash information
self.protmon_results[self.total_mutant_index] = data


# TODO: Refactor all this crap into a full-fledged flask app
# noinspection PyPep8Naming,PyOldStyleClasses
class WebInterfaceHandler(BaseHTTPServer.BaseHTTPRequestHandler):
def __init__(self, *args, **kwargs):

super(WebInterfaceHandler, self).__init__(*args, **kwargs)

self.session = None

# TODO: What the fuck?!
def commify(self, number):
number = str(number)
processing = 1
regex = re.compile(r"^(-?\d+)(\d{3})")
while processing:
(number, processing) = regex.subn(r"\1,\2", number)
return number

def do_GET(self):
self.do_everything()

def do_HEAD(self):
self.do_everything()

def do_POST(self):
self.do_everything()

def do_everything(self):
if "pause" in self.path:
self.session.pause_flag = True

if "resume" in self.path:
self.session.pause_flag = False

self.send_response(200)
self.send_header('Content-type', 'text/html')
self.end_headers()

if "view_crash" in self.path:
response = self.view_crash(self.path)
elif "view_pcap" in self.path:
response = self.view_pcap(self.path)
else:
response = self.view_index()

self.wfile.write(response)

def log_error(self, *args, **kwargs):
pass

def log_message(self, *args, **kwargs):
pass

def version_string(self):
return "Sulley Fuzz Session"

def view_crash(self, path):
test_number = int(path.split("/")[-1])
return "<html><pre>%s</pre></html>" % self.session.procmon_results[test_number]

def view_pcap(self, path):
return path

def view_index(self):
response = """
<html>
<head>
<meta http-equiv="refresh" content="5">
<title>Sulley Fuzz Control</title>
<style>
a:link {color: #FF8200; text-decoration: none;}
a:visited {color: #FF8200; text-decoration: none;}
a:hover {color: #C5C5C5; text-decoration: none;}

body
{
background-color: #000000;
font-family: Arial, Helvetica, sans-serif;
font-size: 12px;
color: #FFFFFF;
}

td
{
font-family: Arial, Helvetica, sans-serif;
font-size: 12px;
color: #A0B0B0;
}

.fixed
{
font-family: Courier New;
font-size: 12px;
color: #A0B0B0;
}

.input
{
font-family: Arial, Helvetica, sans-serif;
font-size: 11px;
color: #FFFFFF;
background-color: #333333;
border: thin none;
height: 20px;
}
</style>
</head>
<body>
<center>
<table border=0 cellpadding=5 cellspacing=0 width=750><tr><td>
<!-- begin bounding table -->

<table border=0 cellpadding=5 cellspacing=0 width="100%%">
<tr bgcolor="#333333">
<td><div style="font-size: 20px;">Sulley Fuzz Control</div></td>
<td align=right><div style="font-weight: bold; font-size: 20px;">%(status)s</div></td>
</tr>
<tr bgcolor="#111111">
<td colspan=2 align="center">
<table border=0 cellpadding=0 cellspacing=5>
<tr bgcolor="#111111">
<td><b>Total:</b></td>
<td>%(total_mutant_index)s</td>
<td>of</td>
<td>%(total_num_mutations)s</td>
<td class="fixed">%(progress_total_bar)s</td>
<td>%(progress_total)s</td>
</tr>
<tr bgcolor="#111111">
<td><b>%(current_name)s:</b></td>
<td>%(current_mutant_index)s</td>
<td>of</td>
<td>%(current_num_mutations)s</td>
<td class="fixed">%(progress_current_bar)s</td>
<td>%(progress_current)s</td>
</tr>
</table>
</td>
</tr>
<tr>
<td>
<form method=get action="/pause">
<input class="input" type="submit" value="Pause">
</form>
</td>
<td align=right>
<form method=get action="/resume">
<input class="input" type="submit" value="Resume">
</form>
</td>
</tr>
</table>

<!-- begin procmon results -->
<table border=0 cellpadding=5 cellspacing=0 width="100%%">
<tr bgcolor="#333333">
<td nowrap>Test Case #</td>
<td>Crash Synopsis</td>
<td nowrap>Captured Bytes</td>
</tr>
"""

procmon_result_keys = self.session.procmon_results.keys()
procmon_result_keys.sort()
for key in procmon_result_keys:
val = self.session.procmon_results[key]
status_bytes = "&nbsp;"

if key in self.session.netmon_results:
status_bytes = self.commify(self.session.netmon_results[key])

response += '''<tr><td class="fixed"><a href="/view_crash/%(key)d">%(key)06d</a></td><td>%(value)s</td>
<td align=right>%(status_bytes)s</td></tr>''' % \
{
"key": key,
"value": val.split("\n")[0],
"status_bytes" : status_bytes
}

response += """
<!-- end procmon results -->
</table>

<!-- end bounding table -->
</td></tr></table>
</center>
</body>
</html>
"""

# what is the fuzzing status.
if self.session.pause_flag:
status = "<font color=red>PAUSED</font>"
else:
status = "<font color=green>RUNNING</font>"

# if there is a current fuzz node.
if self.session.fuzz_node:
# which node (request) are we currently fuzzing.
if self.session.fuzz_node.name:
current_name = self.session.fuzz_node.name
else:
current_name = "[N/A]"

# render sweet progress bars.
mutant_index = float(self.session.fuzz_node.mutant_index)
num_mutations = float(self.session.fuzz_node.num_mutations())

progress_current = mutant_index / num_mutations
num_bars = int(progress_current * 50)
progress_current_bar = "[" + "=" * num_bars + "&nbsp;" * (50 - num_bars) + "]"
progress_current = "%.3f%%" % (progress_current * 100)

total_mutant_index = float(self.session.total_mutant_index)
total_num_mutations = float(self.session.total_num_mutations)

progress_total = total_mutant_index / total_num_mutations
num_bars = int(progress_total * 50)
progress_total_bar = "[" + "=" * num_bars + "&nbsp;" * (50 - num_bars) + "]"
progress_total = "%.3f%%" % (progress_total * 100)

response %= \
{
"current_mutant_index" : self.commify(self.session.fuzz_node.mutant_index),
"current_name" : current_name,
"current_num_mutations" : self.commify(self.session.fuzz_node.num_mutations()),
"progress_current" : progress_current,
"progress_current_bar" : progress_current_bar,
"progress_total" : progress_total,
"progress_total_bar" : progress_total_bar,
"status" : status,
"total_mutant_index" : self.commify(self.session.total_mutant_index),
"total_num_mutations" : self.commify(self.session.total_num_mutations),
}
else:
response %= \
{
"current_mutant_index" : "",
"current_name" : "",
"current_num_mutations" : "",
"progress_current" : "",
"progress_current_bar" : "",
"progress_total" : "",
"progress_total_bar" : "",
"status" : "<font color=yellow>UNAVAILABLE</font>",
"total_mutant_index" : "",
"total_num_mutations" : "",
}

return response


# noinspection PyOldStyleClasses
class WebInterfaceServer(BaseHTTPServer.HTTPServer):

def __init__(self, server_address, request_handler_class, session):
super(WebInterfaceServer, self).__init__(server_address, request_handler_class)
self.RequestHandlerClass.session = session


class WebInterfaceThread (threading.Thread):
def __init__(self, session):
threading.Thread.__init__(self, name="SulleyWebServer")

self._stopevent = threading.Event()
self.session = session
self.server = None

def run(self):
self.server = WebInterfaceServer(('', self.session.web_port), WebInterfaceHandler, self.session)
while not self._stopevent.isSet():
self.server.handle_request()

def join(self, timeout=None):
# A little dirty but no other solution afaik
self._stopevent.set()
conn = httplib.HTTPConnection("localhost:%d" % self.session.web_port)
conn.request("GET", "/")
conn.getresponse()
def build_webapp_thread(self, port=26000):
app.session = self
http_server = HTTPServer(WSGIContainer(app))
http_server.listen(port)
flask_thread = threading.Thread(target=IOLoop.instance().start)
flask_thread.daemon = True
return flask_thread
Empty file added web/__init__.py
Empty file.
Loading