def testMaxFailures(self): target_config = { '1': { 'send': { "raise exception": True } }, '2': { 'send': { "raise exception": True } }, '3': { 'send': { "raise exception": True } }, } self.target = ServerTargetMock(target_config, logger=self.logger) cmd_line = '--test-list=0-10' self.fuzzer = ServerFuzzer(name='TestServerFuzzer', logger=self.logger, option_line=cmd_line) self.fuzzer.set_interface(self.interface) self.fuzzer.set_model(self.model) self.fuzzer.set_target(self.target) self.fuzzer.set_max_failures(3) self.fuzzer.start() # check what tests were started by the fuzzer pre_test_list = self.target.instrument.list_get('pre_test') self.assertListEqual(pre_test_list, [-1, 0, 1, 2, 3])
def testSessionResume(self): session_file_name = 'testSessionResume.session' try: os.remove(session_file_name) except: pass self.logger.info('Make the fuzzer stop after 2 tests by reaching max failures') target_config = { '1': {'send': {"raise exception": True}}, } self.target = ServerTargetMock(target_config, logger=self.logger) cmd_line = '--test-list=0-10 --session=%s' % (session_file_name) self.fuzzer = ServerFuzzer(name='TestServerFuzzer', logger=self.logger, option_line=cmd_line) self.fuzzer.set_interface(self.interface) self.fuzzer.set_model(self.new_model()) self.fuzzer.set_target(self.target) self.fuzzer.set_max_failures(1) self.fuzzer.start() pre_test_list = self.target.instrument.list_get('pre_test') self.assertListEqual(pre_test_list, [-1, 0, 1]) self.fuzzer.stop() self.logger.info('Now use the same session file to run from where we have stopped') cmd_line = '--session=%s --no-env-test' % (session_file_name) self.target = ServerTargetMock({}, logger=self.logger) self.fuzzer = ServerFuzzer(name='TestServerFuzzer', logger=self.logger, option_line=cmd_line) self.fuzzer.set_interface(self.interface) self.fuzzer.set_model(self.new_model()) self.fuzzer.set_target(self.target) self.fuzzer.start() pre_test_list = self.target.instrument.list_get('pre_test') self.assertListEqual(pre_test_list, range(2, 11)) os.remove(session_file_name)
def prepare(self): self.start_index = 0 self.end_index = 20 self.delay_duration = 0 self.fuzzer = ServerFuzzer(name="TestServerFuzzer", logger=self.logger) self.model = GraphModel() self.model.logger = self.logger self.model.connect(self.t_str) self.fuzzer.set_model(self.model)
def testCommandLineArgumentSession(self): self.session_file_name = 'mysession.sqlite' cmd_line = '--session=%s' % self.session_file_name self.fuzzer = ServerFuzzer(name="TestServerFuzzer", logger=self.logger, option_line=cmd_line) self.fuzzer.set_interface(self.interface) self.fuzzer.set_model(self.model) self.fuzzer.set_target(self.target) self.fuzzer.set_delay_between_tests(self.delay_duration) self.fuzzer.set_range(self.start_index, self.end_index) self.assertEqual(self.session_file_name, self.fuzzer.config.session_file_name) self.fuzzer.start()
def testCommandLineArgumentTestList(self): cmd_line = '--test-list=%s' % (','.join(str(i) for i in [1, 3, 5, 7])) self.fuzzer = ServerFuzzer(name='TestServerFuzzer', logger=self.logger, option_line=cmd_line) self.fuzzer.set_interface(self.interface) self.fuzzer.set_model(self.model) self.fuzzer.set_target(self.target) self.fuzzer.start() # check what tests were started by the fuzzer pre_test_list = self.target.instrument.list_get('pre_test') self.assertListEqual(pre_test_list, [-1, 1, 3, 5, 7])
def testRetest(self): session_file_name = 'testSessionResume.session' try: os.remove(session_file_name) except: pass self.logger.info( 'Make the fuzzer stop after 2 tests by reaching max failures') target_config = { '1': { 'send': { "raise exception": True } }, '3': { 'send': { "raise exception": True } }, '5': { 'send': { "raise exception": True } }, } self.target = ServerTargetMock(target_config, logger=self.logger) cmd_line = '--test-list=0-10 --session=%s' % (session_file_name) self.fuzzer = ServerFuzzer(name='TestServerFuzzer', logger=self.logger, option_line=cmd_line) self.fuzzer.set_interface(self.interface) self.fuzzer.set_model(self.new_model()) self.fuzzer.set_target(self.target) self.fuzzer.start() pre_test_list = self.target.instrument.list_get('pre_test') self.assertListEqual(pre_test_list, list(range(-1, 11))) self.fuzzer.stop() self.logger.info('Now use the same session file to rerun failed tests') cmd_line = '--retest=%s --no-env-test' % (session_file_name) self.target = ServerTargetMock({}, logger=self.logger) self.fuzzer = ServerFuzzer(name='TestServerFuzzer', logger=self.logger, option_line=cmd_line) self.fuzzer.set_interface(self.interface) self.fuzzer.set_model(self.new_model()) self.fuzzer.set_target(self.target) self.fuzzer.start() pre_test_list = self.target.instrument.list_get('pre_test') self.assertListEqual(pre_test_list, [1, 3, 5]) os.remove(session_file_name)
def testCommandLineArgumentsStart(self): self.start_index = 10 cmd_line = '--start=%d' % self.start_index self.fuzzer = ServerFuzzer(name="TestServerFuzzer", logger=self.logger, option_line=cmd_line) self.fuzzer.set_interface(self.interface) self.fuzzer.set_model(self.model) self.fuzzer.set_target(self.target) self.fuzzer.set_delay_between_tests(self.delay_duration) self.fuzzer.start() info = self.fuzzer._get_session_info() self.assertEqual(info.current_index, self.model.last_index()) self.assertEqual(info.start_index, self.start_index)
def testCommandLineArgumentDelay(self): self.delay_duration = 0.1 cmd_line = '--delay=%s' % self.delay_duration self.fuzzer = ServerFuzzer(name="TestServerFuzzer", logger=self.logger, option_line=cmd_line) self.fuzzer.set_interface(self.interface) self.fuzzer.set_model(self.model) self.fuzzer.set_target(self.target) self.fuzzer.set_range(self.start_index, self.end_index) self.assertEqual(self.delay_duration, self.fuzzer.config.delay_secs) start_time = time.time() self.fuzzer.start() end_time = time.time() expected_runtime = self.delay_duration * (self.end_index - self.start_index + 1) actual_runtime = end_time - start_time self.assertAlmostEqual(int(actual_runtime), int(expected_runtime))
def prepare(self): self.start_index = 10 self.end_index = 20 self.delay_duration = 0 self.session_file_name = None self.interface = EmptyInterface() self.model = self.new_model() self.target = ServerTargetMock({}, logger=self.logger) self.fuzzer = ServerFuzzer(name="TestServerFuzzer", logger=self.logger) self.fuzzer.set_interface(self.interface) self.fuzzer.set_model(self.model) self.fuzzer.set_target(self.target) self.fuzzer.set_range(self.start_index, self.end_index) self.fuzzer.set_delay_between_tests(self.delay_duration)
def testMaxFailures(self): target_config = { '1': {'send': {"raise exception": True}}, '2': {'send': {"raise exception": True}}, '3': {'send': {"raise exception": True}}, } self.target = ServerTargetMock(target_config, logger=self.logger) cmd_line = '--test-list=0-10' self.fuzzer = ServerFuzzer(name='TestServerFuzzer', logger=self.logger, option_line=cmd_line) self.fuzzer.set_interface(self.interface) self.fuzzer.set_model(self.model) self.fuzzer.set_target(self.target) self.fuzzer.set_max_failures(3) self.fuzzer.start() # check what tests were started by the fuzzer pre_test_list = self.target.instrument.list_get('pre_test') self.assertListEqual(pre_test_list, [-1, 0, 1, 2, 3])
def prepare(self): self.start_index = 10 self.end_index = 20 self.delay_duration = 0 self.fuzzer = ServerFuzzer(name="TestServerFuzzer", logger=self.logger) self.interface = EmptyInterface() self.fuzzer.set_interface(self.interface) self.model = GraphModel() self.model.connect(self.t_str) self.fuzzer.set_model(self.model) self.target = TargetMock({}) self.fuzzer.set_target(self.target) self.fuzzer.set_range(self.start_index, self.end_index) self.fuzzer.set_delay_between_tests(self.delay_duration)
from kitty.remote.actor import RemoteActor t1 = Template(name='T1', fields=[ String('The default string', name='S1_1'), ]) # Writes content to files target = FileTarget('FileTarget', 'tmp/', 'fuzzed') # # connects to actual actor (controller) over RPC # controller = RemoteActor('127.0.0.1', 25002) target.set_controller(controller) model = GraphModel() model.connect(t1) fuzzer = ServerFuzzer() fuzzer.set_interface(WebInterface(port=26001)) fuzzer.set_model(model) fuzzer.set_target(target) # No need for delay, we only create files # fuzzer.set_delay_between_tests(0.02) # No need for range, generate all # fuzzer.set_range(50) fuzzer.start() print('-------------- done with fuzzing -----------------') raw_input('press any key to exit') fuzzer.stop()
class WebInterfaceTest(BaseTestCase): def setUp(self): super(WebInterfaceTest, self).setUp(None) self.t_str = Template(name='simple_str_template', fields=[String(name='str1', value='kitty')]) self.t_int = Template(name='simple_int_template', fields=[UInt32(name='int1', value=0x1234)]) self.fuzzer = None self.host = '127.0.0.1' self.port = 11223 self.url = 'http://%(host)s:%(port)s' % { 'host': self.host, 'port': self.port } self.prepare() def tearDown(self): if self.fuzzer: self.logger.info('still have fuzzer, stop it') self.fuzzer.stop() def prepare(self): self.start_index = 0 self.end_index = 20 self.delay_duration = 0 self.fuzzer = ServerFuzzer(name="TestServerFuzzer", logger=self.logger) self.model = GraphModel() self.model.logger = self.logger self.model.connect(self.t_str) self.fuzzer.set_model(self.model) def _webValidRequest(self, request): resp = requests.get(request) self.assertIsNotNone(resp) self.assertEqual(resp.status_code, 200) as_json = resp.json() self.assertIsNotNone(as_json) return as_json def _webGetStats(self): return self._webValidRequest('%s/api/stats.json' % self.url) def _webGetReport(self, report_id): return self._webValidRequest('%s/api/report?report_id=%s' % (self.url, report_id)) def _webGetReportList(self): resp = self._webGetStats() self.assertIn('reports', resp) reports = resp['reports'] return reports def _runFuzzerWithReportList(self, uut, report_list): config = {} for report_id in report_list: config[str(report_id)] = {'report': {'failed': True}} self.fuzzer.set_interface(uut) target = ServerTargetMock(config, logger=self.logger) self.fuzzer.set_target(target) self.fuzzer.start() def _testStatsApiReportList(self, report_list): uut = WebInterface(host=self.host, port=self.port) report_list.sort() self._runFuzzerWithReportList(uut, report_list) actual_report_list = self._webGetReportList() self.assertListEqual(actual_report_list, report_list) def testStatsApiReportListEmpty(self): self._testStatsApiReportList([]) def testStatsApiReportListSingle(self): self._testStatsApiReportList([5]) def testStatsApiReportListMultiple(self): self._testStatsApiReportList([1, 2, 3, 4, 5]) def testStatsApiReportListAll(self): self._testStatsApiReportList([x for x in range(self.end_index)]) def _testStatsApi(self): ''' .. todo:: other stats API tests ''' pass def _testReportApiReportExists(self, report_list): for report_id in report_list: response = self._webGetReport(report_id) self.assertIn('report', response) self.assertIn('encoding', response) def _testReportApiValid(self, report_list): self._testStatsApiReportList(report_list) self._testReportApiReportExists(report_list) def testReportApiSingle(self): self._testReportApiValid([1]) def testReportApiMultiple(self): self._testReportApiValid([1, 2, 3]) def testReportApiAll(self): self._testReportApiValid([x for x in range(self.end_index)]) def _testReportApiError(self, request): self._testReportApiValid([x for x in range(self.end_index)]) resp = self._webValidRequest(request) self.assertIn('error', resp) self.assertNotIn('report', resp) def testReportApiErrorWhenNoReportId(self): self._testReportApiError('%s/api/report' % (self.url)) def testReportApiErrorWhenReportIdNotInt(self): self._testReportApiError('%s/api/report?report_id=%s' % (self.url, '%%')) def testReportApiErrorWhenNoSuchReport(self): self._testReportApiError('%s/api/report?report_id=%s' % (self.url, self.end_index + 1)) def _testPauseApi(self): ''' .. todo:: pause/resume api tests ''' pass
from kitty.controllers import EmptyController from katnip.targets.file import FileTarget from kitty.model import GraphModel from kitty.model import String from kitty.model import Template opts = docopt.docopt(__doc__) t1 = Template(name='T1', fields=[ String('The default string', name='S1_1'), String('Another string', name='S1_2'), ]) # Writes content to files target = FileTarget('FileTarget', 'tmp/', 'fuzzed') controller = EmptyController('EmptyController') target.set_controller(controller) model = GraphModel() model.connect(t1) fuzzer = ServerFuzzer(name="Example 1 - File Generator", option_line=opts['--kitty-options']) fuzzer.set_interface(WebInterface(port=26001)) fuzzer.set_model(model) fuzzer.set_target(target) fuzzer.start() print('-------------- done with fuzzing -----------------') raw_input('press enter to exit') fuzzer.stop()
fuzzer.logger.info('session is: %s' % resp[1:3].encode('hex')) fuzzer.target.session_data['session_id'] = resp[1:3] # Define session target target = TcpTarget(name='session_test_target', host=target_ip, port=target_port, timeout=2) # Make target expect response target.set_expect_response(True) # Define controller controller = SessionServerController(name='ServerController', host=target_ip, port=target_port) target.set_controller(controller) # Define model model = GraphModel() model.connect(get_session) model.connect(get_session, send_data, new_session_callback) # Define fuzzer fuzzer = ServerFuzzer() fuzzer.set_interface(WebInterface(port=web_port)) fuzzer.set_model(model) fuzzer.set_target(target) fuzzer.set_delay_between_tests(0.2) fuzzer.start()
def fuzzing(host, port, template): # Define target target = TcpTarget('HTTP', host, int(port), timeout=1) target.set_expect_response(True) # target.add_monitor(monitor) # Define model model = GraphModel() model.connect(template) # Define fuzzer fuzzer = ServerFuzzer() fuzzer.set_interface(WebInterface(port=4445)) fuzzer.set_delay_between_tests(0.2) # Run fuzzer session_name = '%s.sqlite' % time.ctime().replace(' ', '_') sessions_dbs = os.path.join('/tmp', 'sessions', session_name) fuzzer.set_session_file(sessions_dbs) fuzzer.set_store_all_reports('reports') fuzzer.set_target(target) fuzzer.set_model(model) fuzzer.start() fuzzer.stop()
def fuzzing(host, port, template): # Define target monitor = GdbServerMonitor( name='GdbServerMonitor', gdb_path='gdb-multiarch', host=host, port=2222, signals=[signal.SIGSEGV, signal.SIGILL, signal.SIGKILL, signal.SIGTERM] ) target = TcpTarget('upnp', host, int(port), timeout=1) target.set_expect_response(True) target.add_monitor(monitor) # Define model model = GraphModel() model.connect(template) # Define fuzzer fuzzer = ServerFuzzer() fuzzer.set_interface(WebInterface(port=4445)) fuzzer.set_delay_between_tests(0.2) # Run fuzzer fuzzer.set_session_file('sessions/%s.sqlite' % time.ctime().replace(' ', '_')) fuzzer.set_store_all_reports('reports') fuzzer.set_target(target) fuzzer.set_model(model) fuzzer.start() fuzzer.stop()
def __generate_fuzz_data(index, kitty_modal): controller = EmptyController() if os.path.exists(fuzz_Input_data_location): shutil.rmtree(fuzz_Input_data_location) if not os.path.exists(fuzz_Input_data_location): os.makedirs(fuzz_Input_data_location) target = FileTarget('FileTarget', fuzz_Input_data_location, 'fuzzed'+str(index)) target.set_controller(controller) fuzzer = ServerFuzzer() fuzzer.set_interface(WebInterface(port=26001)) fuzzer.set_model(kitty_modal) fuzzer.set_target(target) fuzzer.start() fuzzer.stop()
class TestServerFuzzer(unittest.TestCase): def setUp(self): self.logger = get_test_logger() self.logger.debug('TESTING METHOD: %s', self._testMethodName) self.t_str = Template(name='simple_str_template', fields=[String(name='str1', value='kitty')]) self.t_int = Template(name='simple_int_template', fields=[UInt32(name='int1', value=0x1234)]) self.fuzzer = None self.prepare() def tearDown(self): if self.fuzzer: self.fuzzer.stop() if self.session_file_name: if os.path.exists(self.session_file_name): os.remove(self.session_file_name) def new_model(self): model = GraphModel() model.logger = self.logger model.connect( Template(name='simple_str_template', fields=[String(name='str1', value='kitty')]) ) return model def prepare(self): self.start_index = 10 self.end_index = 20 self.delay_duration = 0 self.session_file_name = None self.interface = EmptyInterface() self.model = self.new_model() self.target = ServerTargetMock({}, logger=self.logger) self.fuzzer = ServerFuzzer(name="TestServerFuzzer", logger=self.logger) self.fuzzer.set_interface(self.interface) self.fuzzer.set_model(self.model) self.fuzzer.set_target(self.target) self.fuzzer.set_range(self.start_index, self.end_index) self.fuzzer.set_delay_between_tests(self.delay_duration) def testRaisesExceptionWhenStartedWithoutModel(self): self.fuzzer.set_model(None) self.assertRaises(AssertionError, self.fuzzer.start) self.fuzzer = None def testRaisesExceptionWhenStartedWithoutTarget(self): self.fuzzer.set_target(None) self.assertRaises(AssertionError, self.fuzzer.start) self.fuzzer = None def testRaisesExceptionWhenStartedWithoutInterface(self): self.fuzzer.set_interface(None) self.assertRaises(AssertionError, self.fuzzer.start) self.fuzzer = None def testCommandLineArgumentDelay(self): self.delay_duration = 0.1 cmd_line = '--delay=%s' % self.delay_duration self.fuzzer = ServerFuzzer(name="TestServerFuzzer", logger=self.logger, option_line=cmd_line) self.fuzzer.set_interface(self.interface) self.fuzzer.set_model(self.model) self.fuzzer.set_target(self.target) self.fuzzer.set_range(self.start_index, self.end_index) self.assertEqual(self.delay_duration, self.fuzzer.config.delay_secs) start_time = time.time() self.fuzzer.start() end_time = time.time() expected_runtime = self.delay_duration * (self.end_index - self.start_index + 1) actual_runtime = end_time - start_time self.assertAlmostEqual(int(actual_runtime), int(expected_runtime)) def testCommandLineArgumentSession(self): self.session_file_name = 'mysession.sqlite' cmd_line = '--session=%s' % self.session_file_name self.fuzzer = ServerFuzzer(name="TestServerFuzzer", logger=self.logger, option_line=cmd_line) self.fuzzer.set_interface(self.interface) self.fuzzer.set_model(self.model) self.fuzzer.set_target(self.target) self.fuzzer.set_delay_between_tests(self.delay_duration) self.fuzzer.set_range(self.start_index, self.end_index) self.assertEqual(self.session_file_name, self.fuzzer.config.session_file_name) self.fuzzer.start() def testCommandLineArgumentTestList(self): cmd_line = '--test-list=%s' % (','.join(str(i) for i in [1, 3, 5, 7])) self.fuzzer = ServerFuzzer(name='TestServerFuzzer', logger=self.logger, option_line=cmd_line) self.fuzzer.set_interface(self.interface) self.fuzzer.set_model(self.model) self.fuzzer.set_target(self.target) self.fuzzer.start() # check what tests were started by the fuzzer pre_test_list = self.target.instrument.list_get('pre_test') self.assertListEqual(pre_test_list, [-1, 1, 3, 5, 7]) def testCommandLineArgumentNoEnvTest(self): cmd_line = '--test-list=%s' % (','.join(str(i) for i in [1, 3, 5, 7])) cmd_line += ' --no-env-test' self.fuzzer = ServerFuzzer(name='TestServerFuzzer', logger=self.logger, option_line=cmd_line) self.fuzzer.set_interface(self.interface) self.fuzzer.set_model(self.model) self.fuzzer.set_target(self.target) self.fuzzer.start() # check what tests were started by the fuzzer pre_test_list = self.target.instrument.list_get('pre_test') self.assertListEqual(pre_test_list, [1, 3, 5, 7]) def testMaxFailures(self): target_config = { '1': {'send': {"raise exception": True}}, '2': {'send': {"raise exception": True}}, '3': {'send': {"raise exception": True}}, } self.target = ServerTargetMock(target_config, logger=self.logger) cmd_line = '--test-list=0-10' self.fuzzer = ServerFuzzer(name='TestServerFuzzer', logger=self.logger, option_line=cmd_line) self.fuzzer.set_interface(self.interface) self.fuzzer.set_model(self.model) self.fuzzer.set_target(self.target) self.fuzzer.set_max_failures(3) self.fuzzer.start() # check what tests were started by the fuzzer pre_test_list = self.target.instrument.list_get('pre_test') self.assertListEqual(pre_test_list, [-1, 0, 1, 2, 3]) def testSessionResume(self): session_file_name = 'testSessionResume.session' try: os.remove(session_file_name) except: pass self.logger.info('Make the fuzzer stop after 2 tests by reaching max failures') target_config = { '1': {'send': {"raise exception": True}}, } self.target = ServerTargetMock(target_config, logger=self.logger) cmd_line = '--test-list=0-10 --session=%s' % (session_file_name) self.fuzzer = ServerFuzzer(name='TestServerFuzzer', logger=self.logger, option_line=cmd_line) self.fuzzer.set_interface(self.interface) self.fuzzer.set_model(self.new_model()) self.fuzzer.set_target(self.target) self.fuzzer.set_max_failures(1) self.fuzzer.start() pre_test_list = self.target.instrument.list_get('pre_test') self.assertListEqual(pre_test_list, [-1, 0, 1]) self.fuzzer.stop() self.logger.info('Now use the same session file to run from where we have stopped') cmd_line = '--session=%s --no-env-test' % (session_file_name) self.target = ServerTargetMock({}, logger=self.logger) self.fuzzer = ServerFuzzer(name='TestServerFuzzer', logger=self.logger, option_line=cmd_line) self.fuzzer.set_interface(self.interface) self.fuzzer.set_model(self.new_model()) self.fuzzer.set_target(self.target) self.fuzzer.start() pre_test_list = self.target.instrument.list_get('pre_test') self.assertListEqual(pre_test_list, range(2, 11)) os.remove(session_file_name) def testRetest(self): session_file_name = 'testSessionResume.session' try: os.remove(session_file_name) except: pass self.logger.info('Make the fuzzer stop after 2 tests by reaching max failures') target_config = { '1': {'send': {"raise exception": True}}, '3': {'send': {"raise exception": True}}, '5': {'send': {"raise exception": True}}, } self.target = ServerTargetMock(target_config, logger=self.logger) cmd_line = '--test-list=0-10 --session=%s' % (session_file_name) self.fuzzer = ServerFuzzer(name='TestServerFuzzer', logger=self.logger, option_line=cmd_line) self.fuzzer.set_interface(self.interface) self.fuzzer.set_model(self.new_model()) self.fuzzer.set_target(self.target) self.fuzzer.start() pre_test_list = self.target.instrument.list_get('pre_test') self.assertListEqual(pre_test_list, range(-1, 11)) self.fuzzer.stop() self.logger.info('Now use the same session file to rerun failed tests') cmd_line = '--retest=%s --no-env-test' % (session_file_name) self.target = ServerTargetMock({}, logger=self.logger) self.fuzzer = ServerFuzzer(name='TestServerFuzzer', logger=self.logger, option_line=cmd_line) self.fuzzer.set_interface(self.interface) self.fuzzer.set_model(self.new_model()) self.fuzzer.set_target(self.target) self.fuzzer.start() pre_test_list = self.target.instrument.list_get('pre_test') self.assertListEqual(pre_test_list, [1, 3, 5]) os.remove(session_file_name) def testVanilla(self): self.fuzzer.start() info = self.fuzzer._get_session_info() # reports = self.fuzzer._get_reports_manager() # self.assertEqual(len(reports), 0) self.assertEqual(info.failure_count, 0) self.assertEqual(info.current_index, None) # self.assertEqual(info.original_start_index, 10) self.assertEqual(info.start_index, self.start_index) self.assertEqual(info.end_index, self.end_index) def testStartingFromStartIndex(self): start_index = self.model.num_mutations() - 2 self.fuzzer.set_range(start_index) self.fuzzer.start() info = self.fuzzer._get_session_info() self.assertEqual(info.current_index, None) self.assertEqual(info.end_index, self.model.last_index()) def testEndingAtEndIndex(self): start_index = 0 end_index = 3 self.fuzzer.set_range(start_index, end_index) self.fuzzer.start() info = self.fuzzer._get_session_info() self.assertEqual(info.start_index, 0) self.assertEqual(info.end_index, 3) self.assertEqual(info.current_index, None) def testFullMutationRange(self): self.fuzzer.set_range() self.fuzzer.start() info = self.fuzzer._get_session_info() self.assertEqual(info.start_index, 0) self.assertEqual(info.end_index, self.model.last_index()) self.assertEqual(info.current_index, None) def _MOVE_TO_TARGET_TESTS_test_send_failure(self): config = { '12': { 'send': {"raise exception": True} } } send_error_target = ServerTargetMock(config, logger=self.logger) self.fuzzer.set_target(send_error_target) self.fuzzer.start() info = self.fuzzer._get_session_info() reports = self.fuzzer._get_reports_manager() self.assertEqual(len(reports), 1) self.assertTrue(12 in reports) self.assertEqual(info.failure_count, 1) def testTestFailedWhenReportIsFailed(self): config = { '13': { 'report': { 'status': 'failed', 'reason': 'failure reason' } } } target = ServerTargetMock(config, logger=self.logger) self.fuzzer.set_target(target) self.fuzzer.start() info = self.fuzzer._get_session_info() reports = self.fuzzer.dataman.get_report_test_ids() self.assertEqual(reports, [int(x) for x in config.keys()]) self.assertEqual(info.failure_count, len(config)) def testAllFailedTestsHaveReports(self): config = { '10': {'report': {'status': 'failed', 'reason': 'failure reason'}}, '11': {'report': {'status': 'failed', 'reason': 'failure reason'}}, '12': {'report': {'status': 'failed', 'reason': 'failure reason'}}, '13': {'report': {'status': 'failed', 'reason': 'failure reason'}} } target = ServerTargetMock(config, logger=self.logger) self.fuzzer.set_target(target) self.fuzzer.start() info = self.fuzzer._get_session_info() reports = self.fuzzer.dataman.get_report_test_ids() self.assertEqual(reports, sorted([int(x) for x in config.keys()])) self.assertEqual(info.failure_count, len(config)) def testStoringAllReportsWhenStoreAllReportsIsSetToTrue(self): config = {} target = ServerTargetMock(config, logger=self.logger) self.fuzzer.set_store_all_reports(True) self.fuzzer.set_target(target) self.fuzzer.start() info = self.fuzzer._get_session_info() reports = self.fuzzer.dataman.get_report_test_ids() expected_mutation_count = self.end_index - self.start_index + 1 expected_failure_count = 0 self.assertEqual(len(reports), expected_mutation_count) self.assertEqual(info.failure_count, expected_failure_count) def testOnlyTestsInSetRangeAreExecuted(self): start_index = self.model.num_mutations() - 5 self.model.connect(self.t_str, self.t_int) expected_end_index = self.model.last_index() expected_num_mutations = expected_end_index - start_index self.fuzzer.set_range(start_index) self.fuzzer.start() info = self.fuzzer._get_session_info() self.assertEqual(info.failure_count, 0) self.assertEqual(info.current_index, None) self.assertEqual(info.start_index, start_index) self.assertEqual(info.end_index, expected_end_index) def testCallbackIsCalledBetweenTwoNodes(self): template1 = Template(name='template1', fields=String('str1')) template2 = Template(name='template2', fields=String('str2')) self.cb_call_count = 0 def t1_t2_cb(fuzzer, edge, response): self.assertEqual(fuzzer, self.fuzzer) self.assertEqual(edge.src, template1) self.assertEqual(edge.dst, template2) self.cb_call_count += 1 model = GraphModel() model.logger = self.logger model.connect(template1) model.connect(template1, template2, t1_t2_cb) self.model = model self.fuzzer.set_model(model) self.fuzzer.set_range() self.fuzzer.start() self.assertEqual(template2.num_mutations(), self.cb_call_count) def testCorrectCallbackIsCalledForEachEdge(self): template1 = Template(name='template1', fields=String('str1')) template2 = Template(name='template2', fields=String('str2')) template3 = Template(name='template3', fields=String('str3')) self.cb2_call_count = 0 self.cb3_call_count = 0 def t1_t2_cb(fuzzer, edge, response): self.assertEqual(fuzzer, self.fuzzer) self.assertEqual(edge.src, template1) self.assertEqual(edge.dst, template2) self.cb2_call_count += 1 def t1_t3_cb(fuzzer, edge, response): self.assertEqual(fuzzer, self.fuzzer) self.assertEqual(edge.src, template1) self.assertEqual(edge.dst, template3) self.cb3_call_count += 1 model = GraphModel() model.logger = self.logger model.connect(template1) model.connect(template1, template2, t1_t2_cb) model.connect(template1, template3, t1_t3_cb) self.model = model self.fuzzer.set_model(model) self.fuzzer.set_range() self.fuzzer.start() self.assertEqual(template2.num_mutations(), self.cb2_call_count) self.assertEqual(template3.num_mutations(), self.cb3_call_count) def testCorrectCallbackIsCalledForAllEdgesInPath(self): template1 = Template(name='template1', fields=String('str1')) template2 = Template(name='template2', fields=String('str2')) template3 = Template(name='template3', fields=String('str3')) self.cb2_call_count = 0 self.cb3_call_count = 0 def t1_t2_cb(fuzzer, edge, response): self.assertEqual(fuzzer, self.fuzzer) self.assertEqual(edge.src, template1) self.assertEqual(edge.dst, template2) self.cb2_call_count += 1 def t2_t3_cb(fuzzer, edge, response): self.assertEqual(fuzzer, self.fuzzer) self.assertEqual(edge.src, template2) self.assertEqual(edge.dst, template3) self.cb3_call_count += 1 model = GraphModel() model.logger = self.logger model.connect(template1) model.connect(template1, template2, t1_t2_cb) model.connect(template2, template3, t2_t3_cb) self.model = model self.fuzzer.set_model(model) self.fuzzer.set_range() self.fuzzer.start() self.assertEqual(template2.num_mutations() + template3.num_mutations(), self.cb2_call_count) self.assertEqual(template3.num_mutations(), self.cb3_call_count)
class WebInterfaceTest(BaseTestCase): def setUp(self): super(WebInterfaceTest, self).setUp(None) self.t_str = Template(name='simple_str_template', fields=[String(name='str1', value='kitty')]) self.t_int = Template(name='simple_int_template', fields=[UInt32(name='int1', value=0x1234)]) self.fuzzer = None self.host = '127.0.0.1' self.port = 11223 self.url = 'http://%(host)s:%(port)s' % {'host': self.host, 'port': self.port} self.prepare() def tearDown(self): if self.fuzzer: self.logger.info('still have fuzzer, stop it') self.fuzzer.stop() def prepare(self): self.start_index = 0 self.end_index = 20 self.delay_duration = 0 self.fuzzer = ServerFuzzer(name="TestServerFuzzer", logger=self.logger) self.model = GraphModel() self.model.logger = self.logger self.model.connect(self.t_str) self.fuzzer.set_model(self.model) def _webValidRequest(self, request): resp = requests.get(request) self.assertIsNotNone(resp) self.assertEqual(resp.status_code, 200) as_json = resp.json() self.assertIsNotNone(as_json) return as_json def _webGetStats(self): return self._webValidRequest('%s/api/stats.json' % self.url) def _webGetReport(self, report_id): return self._webValidRequest('%s/api/report?report_id=%s' % (self.url, report_id)) def _webGetReportList(self): resp = self._webGetStats() self.assertIn('reports_extended', resp) reports = resp['reports_extended'] return reports def _runFuzzerWithReportList(self, uut, report_list): config = {} for report_id in report_list: config[str(report_id)] = {'report': {'status': 'failed', 'reason': 'failure reason'}} self.fuzzer.set_interface(uut) target = ServerTargetMock(config, logger=self.logger) self.fuzzer.set_target(target) self.fuzzer.start() def _testStatsApiReportList(self, report_list): uut = WebInterface(host=self.host, port=self.port) report_list.sort() self._runFuzzerWithReportList(uut, report_list) actual_report_list = [x[0] for x in self._webGetReportList()] self.assertListEqual(actual_report_list, report_list) def testStatsApiReportListEmpty(self): self._testStatsApiReportList([]) def testStatsApiReportListSingle(self): self._testStatsApiReportList([5]) def testStatsApiReportListMultiple(self): self._testStatsApiReportList([1, 2, 3, 4, 5]) def testStatsApiReportListAll(self): self._testStatsApiReportList([x for x in range(self.end_index)]) def _testStatsApi(self): ''' .. todo:: other stats API tests ''' pass def _testReportApiReportExists(self, report_list): for report_id in report_list: response = self._webGetReport(report_id) self.assertIn('report', response) self.assertIn('encoding', response) def _testReportApiValid(self, report_list): self._testStatsApiReportList(report_list) self._testReportApiReportExists(report_list) def testReportApiSingle(self): self._testReportApiValid([1]) def testReportApiMultiple(self): self._testReportApiValid([1, 2, 3]) def testReportApiAll(self): self._testReportApiValid([x for x in range(self.end_index)]) def _testReportApiError(self, request): self._testReportApiValid([x for x in range(self.end_index)]) resp = self._webValidRequest(request) self.assertIn('error', resp) self.assertNotIn('report', resp) def testReportApiErrorWhenNoReportId(self): self._testReportApiError('%s/api/report' % (self.url)) def testReportApiErrorWhenReportIdNotInt(self): self._testReportApiError('%s/api/report?report_id=%s' % (self.url, '%%')) def testReportApiErrorWhenNoSuchReport(self): self._testReportApiError('%s/api/report?report_id=%s' % (self.url, self.end_index + 1)) def _testPauseApi(self): ''' .. todo:: pause/resume api tests ''' pass def get_static_content(self, filename): (dir_path, _) = os.path.split(__file__) index_path = os.path.join(dir_path, '..', 'kitty', 'interfaces', 'web', 'static', filename) data = None with open(index_path, 'rb') as f: data = f.read() return data def testGetIndexHtml(self): url = self.url + '/index.html' uut = WebInterface(host=self.host, port=self.port) self._runFuzzerWithReportList(uut, []) resp = requests.get(url) self.assertEqual(resp.status_code, 200) self.assertEqual(resp.headers['content-type'], 'text/html') index_content = self.get_static_content('index.html') self.assertEqual(resp.text, index_content) def testReturnIndexForRoot(self): root_url = self.url + '/' index_url = self.url + '/index.html' uut = WebInterface(host=self.host, port=self.port) self._runFuzzerWithReportList(uut, []) root_resp = requests.get(root_url) index_url = requests.get(index_url) self.assertEqual(root_resp.status_code, 200) self.assertEqual(root_resp.headers['content-type'], 'text/html') self.assertEqual(root_resp.text, index_url.text) def testGetOtherFilesReturns401(self): url = self.url + '/../../../../../../../etc/passwd' uut = WebInterface(host=self.host, port=self.port) self._runFuzzerWithReportList(uut, []) resp = requests.get(url) self.assertEqual(resp.status_code, 401) def testPost(self): url = self.url + '/index.html' uut = WebInterface(host=self.host, port=self.port) self._runFuzzerWithReportList(uut, []) resp = requests.post(url) self.assertEqual(resp.status_code, 200) self.assertEqual(resp.headers['content-type'], 'text/html') index_content = self.get_static_content('index.html') self.assertEqual(resp.text, index_content)
from kitty.remote.actor import RemoteActor t1 = Template(name='T1', fields=[ String('The default string', name='S1_1'), ]) # Writes content to files target = FileTarget('FileTarget', 'tmp/', 'fuzzed') # # connects to actual actor (controller) over RPC # controller = RemoteActor('127.0.0.1', 25002) target.set_controller(controller) model = GraphModel() model.connect(t1) fuzzer = ServerFuzzer(name='Example 4 - File Generator(Remote Controller)') fuzzer.set_interface(WebInterface(port=26001)) fuzzer.set_model(model) fuzzer.set_target(target) # No need for delay, we only create files # fuzzer.set_delay_between_tests(0.02) # No need for range, generate all # fuzzer.set_range(50) fuzzer.start() print('-------------- done with fuzzing -----------------') raw_input('press enter to exit') fuzzer.stop()
edge.src is the get_session template edge.dst is the send_data template :param resp: the response from the target """ fuzzer.logger.info("session is: %s" % resp[1:3].encode("hex")) fuzzer.target.session_data["session_id"] = resp[1:3] # Define session target target = TcpTarget(name="session_test_target", host=target_ip, port=target_port, timeout=2) # Make target expect response target.set_expect_response(True) # Define controller controller = SessionServerController(name="ServerController", host=target_ip, port=target_port) target.set_controller(controller) # Define model model = GraphModel() model.connect(get_session) model.connect(get_session, send_data, new_session_callback) # Define fuzzer fuzzer = ServerFuzzer() fuzzer.set_interface(WebInterface(port=web_port)) fuzzer.set_model(model) fuzzer.set_target(target) fuzzer.set_delay_between_tests(0.2) fuzzer.start()
def __generate_fuzz_file_for_fuzzinternalfilereads(input_files = None, sample_input = None): controller = EmptyController() __my_modal = sample_model __tmp_folder = tmp_folder if os.path.exists(__tmp_folder): shutil.rmtree(__tmp_folder) if not os.path.exists(__tmp_folder): os.makedirs(__tmp_folder) if sample_input is not None: __parent_tokens = [] for __si in sample_input: __tokens = str(__si).split() if len(__tokens)>2: __parent_tokens.extend(__tokens[2:]) elif len(__tokens) == 2: __parent_tokens.extend(__tokens[1:]) else: __parent_tokens.extend(__tokens) __my_modal = InputParser.get_kitty_models_from_sample_input(__parent_tokens, False) target = FileTarget('FileTarget', __tmp_folder, 'fuzzed') target.set_controller(controller) fuzzer = ServerFuzzer() fuzzer.set_interface(WebInterface(port=26001)) fuzzer.set_model(__my_modal) fuzzer.set_target(target) fuzzer.start() fuzzer.stop()
def run_proto(self) -> None: """ kitty low level field model https://kitty.readthedocs.io/en/latest/kitty.model.low_level.field.html """ js = ext_json.dict_to_JsonObject(dict(self.pb2_api[0]['Messages']), 'api') template_a = Template(name='Api', fields=js) self.logger.info(f"[{time.strftime('%H:%M:%S')}] Prepare ProtobufTarget ") target = ProtobufTarget('ProtobufTarget', host=self.target_host, port=self.target_port, max_retries=10, timeout=None, pb2_module=self.pb2_api[1]) self.logger.info(f"[{time.strftime('%H:%M:%S')}] Prepare ProtobufController ") controller = ProtobufController('ProtobufController', host=self.target_host, port=self.target_port) target.set_controller(controller) #target.set_expect_response('true') self.logger.info(f"[{time.strftime('%H:%M:%S')}] Defining GraphModel") model = GraphModel() model.connect(template_a) self.logger.info(f"[{time.strftime('%H:%M:%S')}] Prepare Server Fuzzer ") fuzzer = ServerFuzzer() fuzzer.set_interface(WebInterface(port=26001)) fuzzer.set_model(model) fuzzer.set_target(target) fuzzer.start() self.logger.info(f"[{time.strftime('%H:%M:%S')}] Start Fuzzer") self.logger.info(f"[Further info are in the related Kitty log output!]") six.moves.input('press enter to exit') self.logger.info(f"[{time.strftime('%H:%M:%S')}] End Fuzzer Session") fuzzer.stop()
http_get_v1 = Template(name='HTTP_GET_V1', fields=[ String('GET', name='method', fuzzable=False), Delimiter(' ', name='space1', fuzzable=False), Delimiter('/', name='backslash'), String('somewhere', name='path', max_size=5), Delimiter(' ', name='space2'), String('HTTP', name='protocol name'), Delimiter('/', name='fws1'), Dword(1, name='major version', encoder=ENC_INT_DEC), Delimiter('.', name='dot1'), Dword(1, name='minor version', encoder=ENC_INT_DEC), Static('\r\n'), Static('Host: 127.0.0.1:5000'), Static('\r\n'), Static('Connection: close'), Static('\r\n\r\n', name='eom') ]) model.connect(http_get_v1) fuzzer = ServerFuzzer() fuzzer.set_model(model) fuzzer.set_target(target) fuzzer.set_store_all_reports(True) os.remove("fuzz_session.sqlite") fuzzer.set_session_file("fuzz_session.sqlite") fuzzer.set_interface(WebInterface()) fuzzer.start() print 'finished!'
class TestServerFuzzer(unittest.TestCase): def setUp(self): self.logger = get_test_logger() self.logger.debug('TESTING METHOD: %s', self._testMethodName) self.t_str = Template(name='simple_str_template', fields=[String(name='str1', value='kitty')]) self.t_int = Template(name='simple_int_template', fields=[UInt32(name='int1', value=0x1234)]) self.fuzzer = None self.prepare() def tearDown(self): if self.fuzzer: self.fuzzer.stop() if self.session_file_name: if os.path.exists(self.session_file_name): os.remove(self.session_file_name) def new_model(self): model = GraphModel() model.logger = self.logger model.connect( Template(name='simple_str_template', fields=[String(name='str1', value='kitty')])) return model def prepare(self): self.start_index = 10 self.end_index = 20 self.delay_duration = 0 self.session_file_name = None self.interface = EmptyInterface() self.model = self.new_model() self.target = ServerTargetMock({}, logger=self.logger) self.fuzzer = ServerFuzzer(name="TestServerFuzzer", logger=self.logger) self.fuzzer.set_interface(self.interface) self.fuzzer.set_model(self.model) self.fuzzer.set_target(self.target) self.fuzzer.set_range(self.start_index, self.end_index) self.fuzzer.set_delay_between_tests(self.delay_duration) def testRaisesExceptionWhenStartedWithoutModel(self): self.fuzzer.set_model(None) self.assertRaises(AssertionError, self.fuzzer.start) self.fuzzer = None def testRaisesExceptionWhenStartedWithoutTarget(self): self.fuzzer.set_target(None) self.assertRaises(AssertionError, self.fuzzer.start) self.fuzzer = None def testRaisesExceptionWhenStartedWithoutInterface(self): self.fuzzer.set_interface(None) self.assertRaises(AssertionError, self.fuzzer.start) self.fuzzer = None def testCommandLineArgumentDelay(self): self.delay_duration = 0.1 cmd_line = '--delay=%s' % self.delay_duration self.fuzzer = ServerFuzzer(name="TestServerFuzzer", logger=self.logger, option_line=cmd_line) self.fuzzer.set_interface(self.interface) self.fuzzer.set_model(self.model) self.fuzzer.set_target(self.target) self.fuzzer.set_range(self.start_index, self.end_index) self.assertEqual(self.delay_duration, self.fuzzer.config.delay_secs) start_time = time.time() self.fuzzer.start() end_time = time.time() expected_runtime = self.delay_duration * (self.end_index - self.start_index + 1) actual_runtime = end_time - start_time self.assertAlmostEqual(int(actual_runtime), int(expected_runtime)) def testCommandLineArgumentSession(self): self.session_file_name = 'mysession.sqlite' cmd_line = '--session=%s' % self.session_file_name self.fuzzer = ServerFuzzer(name="TestServerFuzzer", logger=self.logger, option_line=cmd_line) self.fuzzer.set_interface(self.interface) self.fuzzer.set_model(self.model) self.fuzzer.set_target(self.target) self.fuzzer.set_delay_between_tests(self.delay_duration) self.fuzzer.set_range(self.start_index, self.end_index) self.assertEqual(self.session_file_name, self.fuzzer.config.session_file_name) self.fuzzer.start() def testCommandLineArgumentTestList(self): cmd_line = '--test-list=%s' % (','.join(str(i) for i in [1, 3, 5, 7])) self.fuzzer = ServerFuzzer(name='TestServerFuzzer', logger=self.logger, option_line=cmd_line) self.fuzzer.set_interface(self.interface) self.fuzzer.set_model(self.model) self.fuzzer.set_target(self.target) self.fuzzer.start() # check what tests were started by the fuzzer pre_test_list = self.target.instrument.list_get('pre_test') self.assertListEqual(pre_test_list, [-1, 1, 3, 5, 7]) def testCommandLineArgumentNoEnvTest(self): cmd_line = '--test-list=%s' % (','.join(str(i) for i in [1, 3, 5, 7])) cmd_line += ' --no-env-test' self.fuzzer = ServerFuzzer(name='TestServerFuzzer', logger=self.logger, option_line=cmd_line) self.fuzzer.set_interface(self.interface) self.fuzzer.set_model(self.model) self.fuzzer.set_target(self.target) self.fuzzer.start() # check what tests were started by the fuzzer pre_test_list = self.target.instrument.list_get('pre_test') self.assertListEqual(pre_test_list, [1, 3, 5, 7]) def testMaxFailures(self): target_config = { '1': { 'send': { "raise exception": True } }, '2': { 'send': { "raise exception": True } }, '3': { 'send': { "raise exception": True } }, } self.target = ServerTargetMock(target_config, logger=self.logger) cmd_line = '--test-list=0-10' self.fuzzer = ServerFuzzer(name='TestServerFuzzer', logger=self.logger, option_line=cmd_line) self.fuzzer.set_interface(self.interface) self.fuzzer.set_model(self.model) self.fuzzer.set_target(self.target) self.fuzzer.set_max_failures(3) self.fuzzer.start() # check what tests were started by the fuzzer pre_test_list = self.target.instrument.list_get('pre_test') self.assertListEqual(pre_test_list, [-1, 0, 1, 2, 3]) def testSessionResume(self): session_file_name = 'testSessionResume.session' try: os.remove(session_file_name) except: pass self.logger.info( 'Make the fuzzer stop after 2 tests by reaching max failures') target_config = { '1': { 'send': { "raise exception": True } }, } self.target = ServerTargetMock(target_config, logger=self.logger) cmd_line = '--test-list=0-10 --session=%s' % (session_file_name) self.fuzzer = ServerFuzzer(name='TestServerFuzzer', logger=self.logger, option_line=cmd_line) self.fuzzer.set_interface(self.interface) self.fuzzer.set_model(self.new_model()) self.fuzzer.set_target(self.target) self.fuzzer.set_max_failures(1) self.fuzzer.start() pre_test_list = self.target.instrument.list_get('pre_test') self.assertListEqual(pre_test_list, [-1, 0, 1]) self.fuzzer.stop() self.logger.info( 'Now use the same session file to run from where we have stopped') cmd_line = '--session=%s --no-env-test' % (session_file_name) self.target = ServerTargetMock({}, logger=self.logger) self.fuzzer = ServerFuzzer(name='TestServerFuzzer', logger=self.logger, option_line=cmd_line) self.fuzzer.set_interface(self.interface) self.fuzzer.set_model(self.new_model()) self.fuzzer.set_target(self.target) self.fuzzer.start() pre_test_list = self.target.instrument.list_get('pre_test') self.assertListEqual(pre_test_list, list(range(2, 11))) os.remove(session_file_name) def testRetest(self): session_file_name = 'testSessionResume.session' try: os.remove(session_file_name) except: pass self.logger.info( 'Make the fuzzer stop after 2 tests by reaching max failures') target_config = { '1': { 'send': { "raise exception": True } }, '3': { 'send': { "raise exception": True } }, '5': { 'send': { "raise exception": True } }, } self.target = ServerTargetMock(target_config, logger=self.logger) cmd_line = '--test-list=0-10 --session=%s' % (session_file_name) self.fuzzer = ServerFuzzer(name='TestServerFuzzer', logger=self.logger, option_line=cmd_line) self.fuzzer.set_interface(self.interface) self.fuzzer.set_model(self.new_model()) self.fuzzer.set_target(self.target) self.fuzzer.start() pre_test_list = self.target.instrument.list_get('pre_test') self.assertListEqual(pre_test_list, list(range(-1, 11))) self.fuzzer.stop() self.logger.info('Now use the same session file to rerun failed tests') cmd_line = '--retest=%s --no-env-test' % (session_file_name) self.target = ServerTargetMock({}, logger=self.logger) self.fuzzer = ServerFuzzer(name='TestServerFuzzer', logger=self.logger, option_line=cmd_line) self.fuzzer.set_interface(self.interface) self.fuzzer.set_model(self.new_model()) self.fuzzer.set_target(self.target) self.fuzzer.start() pre_test_list = self.target.instrument.list_get('pre_test') self.assertListEqual(pre_test_list, [1, 3, 5]) os.remove(session_file_name) def testVanilla(self): self.fuzzer.start() info = self.fuzzer._get_session_info() # reports = self.fuzzer._get_reports_manager() # self.assertEqual(len(reports), 0) self.assertEqual(info.failure_count, 0) self.assertEqual(info.current_index, None) # self.assertEqual(info.original_start_index, 10) self.assertEqual(info.start_index, self.start_index) self.assertEqual(info.end_index, self.end_index) def testStartingFromStartIndex(self): start_index = self.model.num_mutations() - 2 self.fuzzer.set_range(start_index) self.fuzzer.start() info = self.fuzzer._get_session_info() self.assertEqual(info.current_index, None) self.assertEqual(info.end_index, self.model.last_index()) def testEndingAtEndIndex(self): start_index = 0 end_index = 3 self.fuzzer.set_range(start_index, end_index) self.fuzzer.start() info = self.fuzzer._get_session_info() self.assertEqual(info.start_index, 0) self.assertEqual(info.end_index, 3) self.assertEqual(info.current_index, None) def testFullMutationRange(self): self.fuzzer.set_range() self.fuzzer.start() info = self.fuzzer._get_session_info() self.assertEqual(info.start_index, 0) self.assertEqual(info.end_index, self.model.last_index()) self.assertEqual(info.current_index, None) def _MOVE_TO_TARGET_TESTS_test_send_failure(self): config = {'12': {'send': {"raise exception": True}}} send_error_target = ServerTargetMock(config, logger=self.logger) self.fuzzer.set_target(send_error_target) self.fuzzer.start() info = self.fuzzer._get_session_info() reports = self.fuzzer._get_reports_manager() self.assertEqual(len(reports), 1) self.assertTrue(12 in reports) self.assertEqual(info.failure_count, 1) def testTestFailedWhenReportIsFailed(self): config = { '13': { 'report': { 'status': 'failed', 'reason': 'failure reason' } } } target = ServerTargetMock(config, logger=self.logger) self.fuzzer.set_target(target) self.fuzzer.start() info = self.fuzzer._get_session_info() reports = self.fuzzer.dataman.get_report_test_ids() self.assertEqual(reports, [int(x) for x in config.keys()]) self.assertEqual(info.failure_count, len(config)) def testAllFailedTestsHaveReports(self): config = { '10': { 'report': { 'status': 'failed', 'reason': 'failure reason' } }, '11': { 'report': { 'status': 'failed', 'reason': 'failure reason' } }, '12': { 'report': { 'status': 'failed', 'reason': 'failure reason' } }, '13': { 'report': { 'status': 'failed', 'reason': 'failure reason' } } } target = ServerTargetMock(config, logger=self.logger) self.fuzzer.set_target(target) self.fuzzer.start() info = self.fuzzer._get_session_info() reports = self.fuzzer.dataman.get_report_test_ids() self.assertEqual(reports, sorted([int(x) for x in config.keys()])) self.assertEqual(info.failure_count, len(config)) def testStoringAllReportsWhenStoreAllReportsIsSetToTrue(self): config = {} target = ServerTargetMock(config, logger=self.logger) self.fuzzer.set_store_all_reports(True) self.fuzzer.set_target(target) self.fuzzer.start() info = self.fuzzer._get_session_info() reports = self.fuzzer.dataman.get_report_test_ids() expected_mutation_count = self.end_index - self.start_index + 1 expected_failure_count = 0 self.assertEqual(len(reports), expected_mutation_count) self.assertEqual(info.failure_count, expected_failure_count) def testOnlyTestsInSetRangeAreExecuted(self): start_index = self.model.num_mutations() - 5 self.model.connect(self.t_str, self.t_int) expected_end_index = self.model.last_index() # expected_num_mutations = expected_end_index - start_index self.fuzzer.set_range(start_index) self.fuzzer.start() info = self.fuzzer._get_session_info() self.assertEqual(info.failure_count, 0) self.assertEqual(info.current_index, None) self.assertEqual(info.start_index, start_index) self.assertEqual(info.end_index, expected_end_index) def testCallbackIsCalledBetweenTwoNodes(self): template1 = Template(name='template1', fields=String('str1')) template2 = Template(name='template2', fields=String('str2')) self.cb_call_count = 0 def t1_t2_cb(fuzzer, edge, response): self.assertEqual(fuzzer, self.fuzzer) self.assertEqual(edge.src, template1) self.assertEqual(edge.dst, template2) self.cb_call_count += 1 model = GraphModel() model.logger = self.logger model.connect(template1) model.connect(template1, template2, t1_t2_cb) self.model = model self.fuzzer.set_model(model) self.fuzzer.set_range() self.fuzzer.start() self.assertEqual(template2.num_mutations(), self.cb_call_count) def testCorrectCallbackIsCalledForEachEdge(self): template1 = Template(name='template1', fields=String('str1')) template2 = Template(name='template2', fields=String('str2')) template3 = Template(name='template3', fields=String('str3')) self.cb2_call_count = 0 self.cb3_call_count = 0 def t1_t2_cb(fuzzer, edge, response): self.assertEqual(fuzzer, self.fuzzer) self.assertEqual(edge.src, template1) self.assertEqual(edge.dst, template2) self.cb2_call_count += 1 def t1_t3_cb(fuzzer, edge, response): self.assertEqual(fuzzer, self.fuzzer) self.assertEqual(edge.src, template1) self.assertEqual(edge.dst, template3) self.cb3_call_count += 1 model = GraphModel() model.logger = self.logger model.connect(template1) model.connect(template1, template2, t1_t2_cb) model.connect(template1, template3, t1_t3_cb) self.model = model self.fuzzer.set_model(model) self.fuzzer.set_range() self.fuzzer.start() self.assertEqual(template2.num_mutations(), self.cb2_call_count) self.assertEqual(template3.num_mutations(), self.cb3_call_count) def testCorrectCallbackIsCalledForAllEdgesInPath(self): template1 = Template(name='template1', fields=String('str1')) template2 = Template(name='template2', fields=String('str2')) template3 = Template(name='template3', fields=String('str3')) self.cb2_call_count = 0 self.cb3_call_count = 0 def t1_t2_cb(fuzzer, edge, response): self.assertEqual(fuzzer, self.fuzzer) self.assertEqual(edge.src, template1) self.assertEqual(edge.dst, template2) self.cb2_call_count += 1 def t2_t3_cb(fuzzer, edge, response): self.assertEqual(fuzzer, self.fuzzer) self.assertEqual(edge.src, template2) self.assertEqual(edge.dst, template3) self.cb3_call_count += 1 model = GraphModel() model.logger = self.logger model.connect(template1) model.connect(template1, template2, t1_t2_cb) model.connect(template2, template3, t2_t3_cb) self.model = model self.fuzzer.set_model(model) self.fuzzer.set_range() self.fuzzer.start() self.assertEqual(template2.num_mutations() + template3.num_mutations(), self.cb2_call_count) self.assertEqual(template3.num_mutations(), self.cb3_call_count)
def main(cls): """ Main fuzzing routine. :return: """ args = cls.parse_args() conf = cls.parse_config() logger = cls.logger(levels[args.log_level], "tPortmapd.fuzz", "./session.log") victim = args.target_addr port = args.target_port version = args.target_version vmrun = conf.get("VMWARE", "vmrun") vmx = conf.get("VMWARE", "vm_path") snapshot_name = conf.get("VMWARE", "snapshot") web_port = conf.getint("KITTY", "web_port") to_log = "Started VxWorks {}.x fuzzing session\n".format(version) to_log += "Target:\n\tip address: {}\n\tport: {}\n".format( victim, port) to_log += "VM: {}\nsnapshot: {}\n".format(vmx, snapshot_name) logger.info(to_log) # Define target target = TcpTarget("tPortmapd", logger=logger, host=victim, port=port, timeout=2) # Define the controller controller = VmWareController(name="VMWare Controller", logger=logger, vmrun_path=vmrun, vmx_path=vmx, snap_name=snapshot_name, target_addr=victim, target_port=port) target.set_controller(controller) # Define the monitor monitor = VxWorksProcessMonitor(name="VxWorks Process Monitor", logger=logger, target_addr=victim, target_version=version) target.add_monitor(monitor) # Define the model model = GraphModel() model.connect(portmap_proc_null) # Define the fuzzing session fuzzer = ServerFuzzer(name="PortmapFuzzer", logger=logger) fuzzer.set_interface(WebInterface(port=web_port)) fuzzer.set_model(model) fuzzer.set_target(target) fuzzer.set_delay_between_tests(0) # Start! try: fuzzer.start() except KeyboardInterrupt: logger.info("Session interrupted by user...") fuzzer.stop() return 1 except Exception as exc: logger.error(exc) fuzzer.stop() return -1
def main(cls): """ Main fuzzing routine. :return: """ args = cls.parse_args() conf = cls.parse_config() logger = cls.logger(levels[args.log_level], "tPortmapd.fuzz", "./session.log") victim = args.target_addr port = args.target_port version = args.target_version vmrun = conf.get("VMWARE", "vmrun") vmx = conf.get("VMWARE", "vm_path") snapshot_name = conf.get("VMWARE", "snapshot") web_port = conf.getint("KITTY", "web_port") to_log = "Started VxWorks {}.x fuzzing session\n".format(version) to_log += "Target:\n\tip address: {}\n\tport: {}\n".format(victim, port) to_log += "VM: {}\nsnapshot: {}\n".format(vmx, snapshot_name) logger.info(to_log) # Define target target = TcpTarget("tPortmapd", logger=logger, host=victim, port=port, timeout=2) # Define the controller controller = VmWareController(name="VMWare Controller", logger=logger, vmrun_path=vmrun, vmx_path=vmx, snap_name=snapshot_name, target_addr=victim, target_port=port) target.set_controller(controller) # Define the monitor monitor = VxWorksProcessMonitor(name="VxWorks Process Monitor", logger=logger, target_addr=victim, target_version=version) target.add_monitor(monitor) # Define the model model = GraphModel() model.connect(portmap_proc_null) # Define the fuzzing session fuzzer = ServerFuzzer(name="PortmapFuzzer", logger=logger) fuzzer.set_interface(WebInterface(port=web_port)) fuzzer.set_model(model) fuzzer.set_target(target) fuzzer.set_delay_between_tests(0) # Start! try: fuzzer.start() except KeyboardInterrupt: logger.info("Session interrupted by user...") fuzzer.stop() return 1 except Exception as exc: logger.error(exc) fuzzer.stop() return -1
class TestServerFuzzer(unittest.TestCase): def setUp(self): self.logger = get_test_logger() self.logger.debug('TESTING METHOD: %s', self._testMethodName) self.t_str = Template(name='simple_str_template', fields=[String(name='str1', value='kitty')]) self.t_int = Template(name='simple_int_template', fields=[UInt32(name='int1', value=0x1234)]) self.fuzzer = None self.prepare() def tearDown(self): if self.fuzzer: self.fuzzer.stop() if self.session_file_name: if os.path.exists(self.session_file_name): os.remove(self.session_file_name) def prepare(self): self.start_index = 10 self.end_index = 20 self.delay_duration = 0 self.session_file_name = None self.interface = EmptyInterface() self.model = GraphModel() self.model.logger = self.logger self.model.connect(self.t_str) self.target = ServerTargetMock({}, logger=self.logger) self.fuzzer = ServerFuzzer(name="TestServerFuzzer", logger=self.logger) self.fuzzer.set_interface(self.interface) self.fuzzer.set_model(self.model) self.fuzzer.set_target(self.target) self.fuzzer.set_range(self.start_index, self.end_index) self.fuzzer.set_delay_between_tests(self.delay_duration) def testRaisesExceptionWhenStartedWithoutModel(self): self.fuzzer.set_model(None) self.assertRaises(AssertionError, self.fuzzer.start) self.fuzzer = None def testRaisesExceptionWhenStartedWithoutTarget(self): self.fuzzer.set_target(None) self.assertRaises(AssertionError, self.fuzzer.start) self.fuzzer = None def testRaisesExceptionWhenStartedWithoutInterface(self): self.fuzzer.set_interface(None) self.assertRaises(AssertionError, self.fuzzer.start) self.fuzzer = None def testCommandLineArgumentsStart(self): self.start_index = 10 cmd_line = '--start=%d' % self.start_index self.fuzzer = ServerFuzzer(name="TestServerFuzzer", logger=self.logger, option_line=cmd_line) self.fuzzer.set_interface(self.interface) self.fuzzer.set_model(self.model) self.fuzzer.set_target(self.target) self.fuzzer.set_delay_between_tests(self.delay_duration) self.fuzzer.start() info = self.fuzzer._get_session_info() self.assertEqual(info.current_index, self.model.last_index()) self.assertEqual(info.start_index, self.start_index) def testCommandLineArgumentsEnd(self): self.end_index = 10 cmd_line = '--end=%d' % self.end_index self.fuzzer = ServerFuzzer(name="TestServerFuzzer", logger=self.logger, option_line=cmd_line) self.fuzzer.set_interface(self.interface) self.fuzzer.set_model(self.model) self.fuzzer.set_target(self.target) self.fuzzer.set_delay_between_tests(self.delay_duration) self.fuzzer.start() info = self.fuzzer._get_session_info() self.assertEqual(info.start_index, 0) self.assertEqual(info.end_index, self.end_index) self.assertEqual(info.current_index, self.end_index) def testCommandLineArgumentDelay(self): self.delay_duration = 0.1 cmd_line = '--delay=%s' % self.delay_duration self.fuzzer = ServerFuzzer(name="TestServerFuzzer", logger=self.logger, option_line=cmd_line) self.fuzzer.set_interface(self.interface) self.fuzzer.set_model(self.model) self.fuzzer.set_target(self.target) self.fuzzer.set_range(self.start_index, self.end_index) self.assertEqual(self.delay_duration, self.fuzzer.config.delay_secs) start_time = time.time() self.fuzzer.start() end_time = time.time() expected_runtime = self.delay_duration * (self.end_index - self.start_index + 1) actual_runtime = end_time - start_time self.assertAlmostEqual(int(actual_runtime), int(expected_runtime)) def testCommandLineArgumentSession(self): self.session_file_name = 'mysession.sqlite' cmd_line = '--session=%s' % self.session_file_name self.fuzzer = ServerFuzzer(name="TestServerFuzzer", logger=self.logger, option_line=cmd_line) self.fuzzer.set_interface(self.interface) self.fuzzer.set_model(self.model) self.fuzzer.set_target(self.target) self.fuzzer.set_delay_between_tests(self.delay_duration) self.fuzzer.set_range(self.start_index, self.end_index) self.assertEqual(self.session_file_name, self.fuzzer.config.session_file_name) self.fuzzer.start() def testVanilla(self): self.fuzzer.start() info = self.fuzzer._get_session_info() # reports = self.fuzzer._get_reports_manager() # self.assertEqual(len(reports), 0) self.assertEqual(info.failure_count, 0) self.assertEqual(info.current_index, self.end_index) # self.assertEqual(info.original_start_index, 10) self.assertEqual(info.start_index, self.start_index) self.assertEqual(info.end_index, self.end_index) mutations_tested = info.current_index - info.start_index self.assertEqual(mutations_tested, self.end_index - self.start_index) def testStartingFromStartIndex(self): start_index = self.model.num_mutations() - 2 self.fuzzer.set_range(start_index) self.fuzzer.start() info = self.fuzzer._get_session_info() self.assertEqual(info.current_index, self.model.last_index()) self.assertEqual(info.end_index, self.model.last_index()) def testEndingAtEndIndex(self): start_index = 0 end_index = 3 self.fuzzer.set_range(start_index, end_index) self.fuzzer.start() info = self.fuzzer._get_session_info() self.assertEqual(info.start_index, 0) self.assertEqual(info.end_index, 3) self.assertEqual(info.current_index, 3) def testFullMutationRange(self): self.fuzzer.set_range() self.fuzzer.start() info = self.fuzzer._get_session_info() self.assertEqual(info.start_index, 0) self.assertEqual(info.end_index, self.model.last_index()) self.assertEqual(info.current_index, self.model.last_index()) def _MOVE_TO_TARGET_TESTS_test_send_failure(self): config = { '12': { 'send': {"raise exception": True} } } send_error_target = ServerTargetMock(config, logger=self.logger) self.fuzzer.set_target(send_error_target) self.fuzzer.start() info = self.fuzzer._get_session_info() reports = self.fuzzer._get_reports_manager() self.assertEqual(len(reports), 1) self.assertTrue(12 in reports) self.assertEqual(info.failure_count, 1) def testTestFailedWhenReportIsFailed(self): config = { '13': { 'report': { 'status': 'failed', 'reason': 'failure reason' } } } target = ServerTargetMock(config, logger=self.logger) self.fuzzer.set_target(target) self.fuzzer.start() info = self.fuzzer._get_session_info() reports = self.fuzzer.dataman.get_report_test_ids() self.assertEqual(reports, [int(x) for x in config.keys()]) self.assertEqual(info.failure_count, len(config)) def testAllFailedTestsHaveReports(self): config = { '10': {'report': {'status': 'failed', 'reason': 'failure reason'}}, '11': {'report': {'status': 'failed', 'reason': 'failure reason'}}, '12': {'report': {'status': 'failed', 'reason': 'failure reason'}}, '13': {'report': {'status': 'failed', 'reason': 'failure reason'}} } target = ServerTargetMock(config, logger=self.logger) self.fuzzer.set_target(target) self.fuzzer.start() info = self.fuzzer._get_session_info() reports = self.fuzzer.dataman.get_report_test_ids() self.assertEqual(reports, sorted([int(x) for x in config.keys()])) self.assertEqual(info.failure_count, len(config)) def testStoringAllReportsWhenStoreAllReportsIsSetToTrue(self): config = {} target = ServerTargetMock(config, logger=self.logger) self.fuzzer.set_store_all_reports(True) self.fuzzer.set_target(target) self.fuzzer.start() info = self.fuzzer._get_session_info() reports = self.fuzzer.dataman.get_report_test_ids() expected_mutation_count = self.end_index - self.start_index + 1 expected_failure_count = 0 self.assertEqual(len(reports), expected_mutation_count) self.assertEqual(info.failure_count, expected_failure_count) def testOnlyTestsInSetRangeAreExecuted(self): start_index = self.model.num_mutations() - 5 self.model.connect(self.t_str, self.t_int) expected_end_index = self.model.last_index() expected_num_mutations = expected_end_index - start_index self.fuzzer.set_range(start_index) self.fuzzer.start() info = self.fuzzer._get_session_info() self.assertEqual(info.failure_count, 0) self.assertEqual(info.current_index, expected_end_index) mutations_tested = info.current_index - info.start_index self.assertEqual(mutations_tested, expected_num_mutations) self.assertEqual(info.start_index, start_index) self.assertEqual(info.end_index, expected_end_index) def testCallbackIsCalledBetweenTwoNodes(self): template1 = Template(name='template1', fields=String('str1')) template2 = Template(name='template2', fields=String('str2')) self.cb_call_count = 0 def t1_t2_cb(fuzzer, edge, response): self.assertEqual(fuzzer, self.fuzzer) self.assertEqual(edge.src, template1) self.assertEqual(edge.dst, template2) self.cb_call_count += 1 model = GraphModel() model.logger = self.logger model.connect(template1) model.connect(template1, template2, t1_t2_cb) self.model = model self.fuzzer.set_model(model) self.fuzzer.set_range() self.fuzzer.start() self.assertEqual(template2.num_mutations(), self.cb_call_count) def testCorrectCallbackIsCalledForEachEdge(self): template1 = Template(name='template1', fields=String('str1')) template2 = Template(name='template2', fields=String('str2')) template3 = Template(name='template3', fields=String('str3')) self.cb2_call_count = 0 self.cb3_call_count = 0 def t1_t2_cb(fuzzer, edge, response): self.assertEqual(fuzzer, self.fuzzer) self.assertEqual(edge.src, template1) self.assertEqual(edge.dst, template2) self.cb2_call_count += 1 def t1_t3_cb(fuzzer, edge, response): self.assertEqual(fuzzer, self.fuzzer) self.assertEqual(edge.src, template1) self.assertEqual(edge.dst, template3) self.cb3_call_count += 1 model = GraphModel() model.logger = self.logger model.connect(template1) model.connect(template1, template2, t1_t2_cb) model.connect(template1, template3, t1_t3_cb) self.model = model self.fuzzer.set_model(model) self.fuzzer.set_range() self.fuzzer.start() self.assertEqual(template2.num_mutations(), self.cb2_call_count) self.assertEqual(template3.num_mutations(), self.cb3_call_count) def testCorrectCallbackIsCalledForAllEdgesInPath(self): template1 = Template(name='template1', fields=String('str1')) template2 = Template(name='template2', fields=String('str2')) template3 = Template(name='template3', fields=String('str3')) self.cb2_call_count = 0 self.cb3_call_count = 0 def t1_t2_cb(fuzzer, edge, response): self.assertEqual(fuzzer, self.fuzzer) self.assertEqual(edge.src, template1) self.assertEqual(edge.dst, template2) self.cb2_call_count += 1 def t2_t3_cb(fuzzer, edge, response): self.assertEqual(fuzzer, self.fuzzer) self.assertEqual(edge.src, template2) self.assertEqual(edge.dst, template3) self.cb3_call_count += 1 model = GraphModel() model.logger = self.logger model.connect(template1) model.connect(template1, template2, t1_t2_cb) model.connect(template2, template3, t2_t3_cb) self.model = model self.fuzzer.set_model(model) self.fuzzer.set_range() self.fuzzer.start() self.assertEqual(template2.num_mutations() + template3.num_mutations(), self.cb2_call_count) self.assertEqual(template3.num_mutations(), self.cb3_call_count)
class TestServerFuzzer(unittest.TestCase): def setUp(self): self.logger = get_test_logger() self.logger.debug('TESTING METHOD: %s', self._testMethodName) self.t_str = Template(name='simple_str_template', fields=[String(name='str1', value='kitty')]) self.t_int = Template(name='simple_int_template', fields=[UInt32(name='int1', value=0x1234)]) self.fuzzer = None self.prepare() def tearDown(self): if self.fuzzer: self.fuzzer.stop() def prepare(self): self.start_index = 10 self.end_index = 20 self.delay_duration = 0 self.fuzzer = ServerFuzzer(name="TestServerFuzzer", logger=self.logger) self.interface = EmptyInterface() self.fuzzer.set_interface(self.interface) self.model = GraphModel() self.model.connect(self.t_str) self.fuzzer.set_model(self.model) self.target = TargetMock({}) self.fuzzer.set_target(self.target) self.fuzzer.set_range(self.start_index, self.end_index) self.fuzzer.set_delay_between_tests(self.delay_duration) def test_start_without_session(self): self.fuzzer.set_model(None) self.assertRaises(AssertionError, self.fuzzer.start) self.fuzzer = None def test_start_without_target(self): self.fuzzer.set_target(None) self.assertRaises(AssertionError, self.fuzzer.start) self.fuzzer = None def test_start_without_interface(self): self.fuzzer.set_interface(None) self.assertRaises(AssertionError, self.fuzzer.start) self.fuzzer = None def test_vanilla(self): self.fuzzer.start() info = self.fuzzer._get_session_info() # reports = self.fuzzer._get_reports_manager() # self.assertEqual(len(reports), 0) self.assertEqual(info.failure_count, 0) self.assertEqual(info.current_index, self.end_index) # self.assertEqual(info.original_start_index, 10) self.assertEqual(info.start_index, self.start_index) self.assertEqual(info.end_index, self.end_index) mutations_tested = info.current_index - info.start_index self.assertEqual(mutations_tested, self.end_index - self.start_index) def test_start_index(self): start_index = self.model.num_mutations() - 2 self.fuzzer.set_range(start_index) self.fuzzer.start() info = self.fuzzer._get_session_info() self.assertEqual(info.current_index, self.model.last_index()) self.assertEqual(info.end_index, self.model.last_index()) def test_end_index(self): start_index = 0 end_index = 3 self.fuzzer.set_range(start_index, end_index) self.fuzzer.start() info = self.fuzzer._get_session_info() self.assertEqual(info.start_index, 0) self.assertEqual(info.end_index, 3) self.assertEqual(info.current_index, 3) def test_full_range(self): self.fuzzer.set_range() self.fuzzer.start() info = self.fuzzer._get_session_info() self.assertEqual(info.start_index, 0) self.assertEqual(info.end_index, self.model.last_index()) self.assertEqual(info.current_index, self.model.last_index()) def _MOVE_TO_TARGET_TESTS_test_send_failure(self): config = { '12': { 'send': ["raise exception"] } } send_error_target = TargetMock(config) self.fuzzer.set_target(send_error_target) self.fuzzer.start() info = self.fuzzer._get_session_info() reports = self.fuzzer._get_reports_manager() self.assertEqual(len(reports), 1) self.assertTrue(12 in reports) self.assertEqual(info.failure_count, 1) def ___test_target_failed_is_true(self): config = { '12': { 'report': { 'failed': False } }, '13': { 'report': { 'failed': True } } } target = TargetMock(config) self.fuzzer.set_target(target) self.fuzzer.start() info = self.fuzzer._get_session_info() reports = self.fuzzer._get_reports_manager() self.assertEqual(len(reports), 1) self.assertTrue(13 in reports) self.assertEqual(info.failure_count, 1) def test_set_range(self): start_index = self.model.num_mutations() - 5 self.model.connect(self.t_str, self.t_int) expected_end_index = self.model.last_index() expected_num_mutations = expected_end_index - start_index self.fuzzer.set_range(start_index) self.fuzzer.start() info = self.fuzzer._get_session_info() self.assertEqual(info.failure_count, 0) self.assertEqual(info.current_index, expected_end_index) mutations_tested = info.current_index - info.start_index self.assertEqual(mutations_tested, expected_num_mutations) self.assertEqual(info.start_index, start_index) self.assertEqual(info.end_index, expected_end_index)
from kitty.fuzzers import ServerFuzzer from kitty.interfaces import WebInterface from kitty.controllers import EmptyController from katnip.targets.file import FileTarget from kitty.model import GraphModel from kitty.model import String from kitty.model import Template opts = docopt.docopt(__doc__) t1 = Template(name='T1', fields=[ String('The default string', name='S1_1'), String('Another string', name='S1_2'), ]) # Writes content to files target = FileTarget('FileTarget', 'tmp/', 'fuzzed') controller = EmptyController('EmptyController') target.set_controller(controller) model = GraphModel() model.connect(t1) fuzzer = ServerFuzzer(name="Example 1 - File Generator", option_line=opts['--kitty-options']) fuzzer.set_interface(WebInterface(port=26001)) fuzzer.set_model(model) fuzzer.set_target(target) fuzzer.start() print('-------------- done with fuzzing -----------------') raw_input('press any key to exit') fuzzer.stop()
def s7(ics_ip): print ">>>>> ICS FUZZING MODULE <<<<<\n" # snap7 server 配置信息 TARGET_IP = ics_ip TARGET_PORT = 102 RANDSEED = int(RandShort()) SRC_TSAP = "0100".encode('hex') DST_TSAP = "0103".encode('hex') # 定义COTP CR建立连接数据包 COTP_CR_PACKET = TPKT() / COTPCR() COTP_CR_PACKET.Parameters = [COTPOption() for i in range(3)] COTP_CR_PACKET.PDUType = "CR" COTP_CR_PACKET.Parameters[0].ParameterCode = "tpdu-size" COTP_CR_PACKET.Parameters[0].Parameter = "\x0a" COTP_CR_PACKET.Parameters[1].ParameterCode = "src-tsap" COTP_CR_PACKET.Parameters[2].ParameterCode = "dst-tsap" COTP_CR_PACKET.Parameters[1].Parameter = SRC_TSAP COTP_CR_PACKET.Parameters[2].Parameter = DST_TSAP # 因为是建立连接使用,因此fuzzable参数需要设置为False避免数据包被变异破坏 COTP_CR_TEMPLATE = Template(name='cotp cr template', fields=[ ScapyField(COTP_CR_PACKET, name='cotp cr', fuzzable=False), ]) # 定义通讯参数配置数据结构 SETUP_COMM_PARAMETER_PACKET = TPKT() / COTPDT(EOT=1) / S7Header( ROSCTR="Job", Parameters=S7SetConParameter()) SETUP_COMM_PARAMETER_TEMPLATE = Template( name='setup comm template', fields=[ ScapyField(SETUP_COMM_PARAMETER_PACKET, name='setup comm', fuzzable=False), ]) # 定义需要Fuzzing的数据包结构, 下面例子中将使用RandShort对请求的SZLId及SZLIndex值进行变异测试 READ_SZL_PACKET = TPKT() / COTPDT(EOT=1) / S7Header( ROSCTR="UserData", Parameters=S7ReadSZLParameterReq(), Data=S7ReadSZLDataReq(SZLId=RandShort(), SZLIndex=RandShort())) # 定义READ_SZL_TEMPLATE为可以进行变异的结构,fuzzing的次数为1000次 READ_SZL_TEMPLATE = Template(name='read szl template', fields=[ ScapyField(READ_SZL_PACKET, name='read szl', fuzzable=True, fuzz_count=1000), ]) # 使用GraphModel进行Fuzz model = GraphModel() # 在使用GraphModel中注册第一个节点, 首先发送COTP_CR请求。 model.connect(COTP_CR_TEMPLATE) # 在使用GraphModel中注册第二个节点, 在发送完COTP_CR后发送SETUP_COMM_PARAMETER请求 model.connect(COTP_CR_TEMPLATE, SETUP_COMM_PARAMETER_TEMPLATE) # 在使用GraphModel中注册第三个节点, 在发送完SETUP_COMM_PARAMETER后发送READ_SZL请求 model.connect(SETUP_COMM_PARAMETER_TEMPLATE, READ_SZL_TEMPLATE) # define target s7comm_target = TcpTarget(name='s7comm target', host=TARGET_IP, port=TARGET_PORT, timeout=2) # 定义是需要等待Target返回响应,如果设置为True Target不返回数据包则会被识别成异常进行记录 s7comm_target.set_expect_response(True) # 定义使用基础的ServerFuzzer进行Fuzz测试 fuzzer = ServerFuzzer() # 定义fuzzer使用的交互界面为web界面 fuzzer.set_interface(WebInterface(port=26001)) # 在fuzzer中定义使用GraphModel fuzzer.set_model(model) # 在fuzzer中定义target为s7comm_target fuzzer.set_target(s7comm_target) # 定义每个测试用例发送之间的延迟 fuzzer.set_delay_between_tests(0.1) # 开始执行Fuzz fuzzer.start()
def run_dns(self): """ kitty low level field model https://kitty.readthedocs.io/en/latest/kitty.model.low_level.field.html """ fields = [] counter = 0 dns_label_length = len(self.default_labels.split('.')) dns_label_list = self.default_labels.split('.') self.logger.info( f"[{time.strftime('%H:%M:%S')}] Initiate template for DNS ...") while counter < dns_label_length: fields.append( String(dns_label_list[counter], name='sub_domain_' + str(counter), max_size=10)) fields.append(Delimiter('.', name='delimiter_' + str(counter))) counter += 1 fields.append(String(self.tld, name='tld', fuzzable=False)) dns_query = Template(name='DNS_QUERY', fields=fields) """ dns_query = Template(name='DNS_QUERY', fields=[ String('r', name='sub_domain', max_size=10), Delimiter('.', name='space1"), String('rf', name='sub_domain2', max_size=10), Delimiter('.', name='space2"), String(self.tld, name='tld', fuzzable=False), ]) """ # define target, in this case this is SslTarget because of HTTPS self.logger.info( f"[{time.strftime('%H:%M:%S')}] Prepare DnsTarget ...") target = DnsTarget(name='DnsTarget', host=self.target_host, port=self.target_port, timeout=self.timeout) target.set_expect_response('true') self.logger.info( f"[{time.strftime('%H:%M:%S')}] Prepare DnsController ...") controller = DnsController('DnsController', host=self.target_host, port=self.target_port) target.set_controller(controller) # Define model self.logger.info( f"[{time.strftime('%H:%M:%S')}] Defining GraphModel...") model = GraphModel() model.connect(dns_query) self.logger.info( f"[{time.strftime('%H:%M:%S')}] Prepare Server Fuzzer ...") fuzzer = ServerFuzzer() fuzzer.set_interface(WebInterface(port=26001)) fuzzer.set_model(model) fuzzer.set_target(target) fuzzer.set_delay_between_tests(1) self.logger.info(f"[{time.strftime('%H:%M:%S')}] Start Fuzzer...") self.logger.info( f"[Further info are in the related Kitty log output!]") fuzzer.start() self.logger.info(f"[{time.strftime('%H:%M:%S')}] End Fuzzer Session") fuzzer.stop()
class WebInterfaceTest(BaseTestCase): def setUp(self): super(WebInterfaceTest, self).setUp(None) self.t_str = Template(name='simple_str_template', fields=[String(name='str1', value='kitty')]) self.t_int = Template(name='simple_int_template', fields=[UInt32(name='int1', value=0x1234)]) self.fuzzer = None self.host = '127.0.0.1' self.port = 11223 self.url = 'http://%(host)s:%(port)s' % {'host': self.host, 'port': self.port} self.prepare() def tearDown(self): if self.fuzzer: self.logger.info('still have fuzzer, stop it') self.fuzzer.stop() def prepare(self): self.start_index = 0 self.end_index = 20 self.delay_duration = 0 self.fuzzer = ServerFuzzer(name="TestServerFuzzer", logger=self.logger) self.model = GraphModel() self.model.logger = self.logger self.model.connect(self.t_str) self.fuzzer.set_model(self.model) def _webValidRequest(self, request): resp = requests.get(request) self.assertIsNotNone(resp) self.assertEqual(resp.status_code, 200) as_json = resp.json() self.assertIsNotNone(as_json) return as_json def _webGetStats(self): return self._webValidRequest('%s/api/stats.json' % self.url) def _webGetReport(self, report_id): return self._webValidRequest('%s/api/report?report_id=%s' % (self.url, report_id)) def _webGetReportList(self): resp = self._webGetStats() self.assertIn('reports', resp) reports = resp['reports'] return reports def _runFuzzerWithReportList(self, uut, report_list): config = {} for report_id in report_list: config[str(report_id)] = {'report': {'failed': True}} self.fuzzer.set_interface(uut) target = TargetMock(config, logger=self.logger) self.fuzzer.set_target(target) self.fuzzer.start() def _testStatsApiReportList(self, report_list): uut = WebInterface(host=self.host, port=self.port) report_list.sort() self._runFuzzerWithReportList(uut, report_list) actual_report_list = self._webGetReportList() self.assertListEqual(actual_report_list, report_list) def testStatsApiReportListEmpty(self): self._testStatsApiReportList([]) def testStatsApiReportListSingle(self): self._testStatsApiReportList([5]) def testStatsApiReportListMultiple(self): self._testStatsApiReportList([1, 2, 3, 4, 5]) def testStatsApiReportListAll(self): self._testStatsApiReportList([x for x in range(self.end_index)]) def _testStatsApi(self): ''' .. todo:: other stats API tests ''' pass def _testReportApiReportExists(self, report_list): for report_id in report_list: response = self._webGetReport(report_id) self.assertIn('report', response) self.assertIn('encoding', response) def _testReportApiValid(self, report_list): self._testStatsApiReportList(report_list) self._testReportApiReportExists(report_list) def testReportApiSingle(self): self._testReportApiValid([1]) def testReportApiMultiple(self): self._testReportApiValid([1, 2, 3]) def testReportApiAll(self): self._testReportApiValid([x for x in range(self.end_index)]) def _testReportApiError(self, request): self._testReportApiValid([x for x in range(self.end_index)]) resp = self._webValidRequest(request) self.assertIn('error', resp) self.assertNotIn('report', resp) def testReportApiErrorWhenNoReportId(self): self._testReportApiError('%s/api/report' % (self.url)) def testReportApiErrorWhenReportIdNotInt(self): self._testReportApiError('%s/api/report?report_id=%s' % (self.url, '%%')) def testReportApiErrorWhenNoSuchReport(self): self._testReportApiError('%s/api/report?report_id=%s' % (self.url, self.end_index + 1)) def _testPauseApi(self): ''' .. todo:: pause/resume api tests ''' pass
import docopt from kitty.fuzzers import ServerFuzzer from kitty.interfaces import WebInterface from kitty.controllers import EmptyController from katnip.targets.file import FileTarget from kitty.model import GraphModel from kitty.model import String from kitty.model import Template opts = docopt.docopt(__doc__) t1 = Template(name='T1', fields=[ String('The default string', name='S1_1'), ]) # Writes content to files target = FileTarget('FileTarget', 'tmp/', 'fuzzed') controller = EmptyController('EmptyController') target.set_controller(controller) model = GraphModel() model.connect(t1) fuzzer = ServerFuzzer(option_line=opts['--kitty-options']) fuzzer.set_interface(WebInterface(port=26001)) fuzzer.set_model(model) fuzzer.set_target(target) fuzzer.start() print('-------------- done with fuzzing -----------------') raw_input('press any key to exit') fuzzer.stop()
def run_http(self) -> None: """ This method provides the HTTP GET, POST, ... , templating for the HTTP header as fields, data provided by the config, explained in the User Documentation. kitty low level field model https://kitty.readthedocs.io/en/latest/kitty.model.low_level.field.html :returns: None :rtype: None """ http_template = None # HTTP GET TEMPLATE self.logger.info( f"[{time.strftime('%H:%M:%S')}] Initiate template for HTTP GET ..." ) if self.http_get: http_template = Template( name='HTTP_GET', fields=[ # GET / HTTP/1.1 String('GET', name='method', fuzzable=False), Delimiter(' ', name='delimiter-1', fuzzable=False), String(self.http_path, name='path'), Delimiter(' ', name='delimiter-2', fuzzable=self.http_fuzz_protocol), String('HTTP', name='protocol name', fuzzable=self.http_fuzz_protocol), Delimiter('/', name='fws-1', fuzzable=self.http_fuzz_protocol), Dword(1, name='major version', encoder=ENC_INT_DEC, fuzzable=self.http_fuzz_protocol), Delimiter('.', name='dot-1', fuzzable=self.http_fuzz_protocol), Dword(1, name='minor version', encoder=ENC_INT_DEC, fuzzable=self.http_fuzz_protocol), Static('\r\n', name='EOL-1'), # User agent String('User-Agent:', name='user_agent_field', fuzzable=self.http_fuzz_protocol), Delimiter(' ', name='delimiter-3', fuzzable=self.http_fuzz_protocol), String('Fuzzer', name='user-agent_name', fuzzable=self.http_fuzz_protocol), Static('\r\n', name='EOL-2'), # Token generated by framework to support following the session if necessary. String('Fuzzer-Token:', name='fuzzer_token', fuzzable=self.http_fuzz_protocol), Delimiter(' ', name='delimiter-4', fuzzable=self.http_fuzz_protocol), String(str(self.gen_uuid), name='fuzzer_token_type', fuzzable=False), # do not fuzz token Static('\r\n', name='EOL-3'), # Accept String('Accept:', name='accept', fuzzable=self.http_fuzz_protocol), Delimiter(' ', name='delimiter-5', fuzzable=self.http_fuzz_protocol), String('*/*', name='accept_type_', fuzzable=self.http_fuzz_protocol), Static('\r\n', name='EOL-4'), # Cache-control no-cache by default String('Cache-Control:', name='cache-control', fuzzable=self.http_fuzz_protocol), Delimiter(' ', name='delimiter-6', fuzzable=self.http_fuzz_protocol), String('no-cache', name='cache_control_type', fuzzable=self.http_fuzz_protocol), Static('\r\n', name='EOL-5'), # Host, the target host String('Host:', name='host_name', fuzzable=self.http_fuzz_protocol), Delimiter(' ', name='delimiter-7', fuzzable=self.http_fuzz_protocol), String(self.target_host, name='target_host', fuzzable=False), # do not fuzz target host address! Static('\r\n', name='EOL-6'), # Connection close, do not use keep-alive it results only one mutation, than the # fuzzer will hang. String('Connection:', name='accept_encoding', fuzzable=self.http_fuzz_protocol), Delimiter(' ', name='delimiter-8', fuzzable=self.http_fuzz_protocol), String('close', name='accept_encoding_types', fuzzable=False), # do not fuzz this field! Static('\r\n', name='EOM-7'), # Content-type from config. String('Content-Type:', name='Content-Type', fuzzable=self.http_fuzz_protocol), Delimiter(' ', name='delimiter-9', fuzzable=self.http_fuzz_protocol), String(self.http_content_type, name='content_type_', fuzzable=self.http_fuzz_protocol), Static('\r\n\r\n', name='EOM-8') ]) if self.http_post_put: self.logger.info( f"[{time.strftime('%H:%M:%S')}] Initiate template for HTTP POST ..." ) http_template = Template( name='HTTP_POST', fields=[ # POST / HTTP/1.1 String('POST', name='method', fuzzable=False), Delimiter(' ', name='delimiter-1', fuzzable=False), String(self.http_path, name='path'), Delimiter(' ', name='delimiter-2', fuzzable=self.http_fuzz_protocol), String('HTTP', name='protocol name', fuzzable=self.http_fuzz_protocol), Delimiter('/', name='fws-1', fuzzable=self.http_fuzz_protocol), Dword(1, name='major version', encoder=ENC_INT_DEC, fuzzable=self.http_fuzz_protocol), Delimiter('.', name='dot-1', fuzzable=self.http_fuzz_protocol), Dword(1, name='minor version', encoder=ENC_INT_DEC, fuzzable=self.http_fuzz_protocol), Static('\r\n', name='EOL-1'), # User agent String('User-Agent:', name='user_agent_field', fuzzable=self.http_fuzz_protocol), Delimiter(' ', name='delimiter-3', fuzzable=self.http_fuzz_protocol), String('Fuzzer', name='user-agent_name', fuzzable=self.http_fuzz_protocol), Static('\r\n', name='EOL-2'), # Token generated by framework to support following the session if necessary. String('Fuzzer-Token:', name='fuzzer_token', fuzzable=self.http_fuzz_protocol), Delimiter(' ', name='delimiter-4', fuzzable=self.http_fuzz_protocol), String(str(self.gen_uuid), name='fuzzer_token_type', fuzzable=self.http_fuzz_protocol), Static('\r\n', name='EOL-3'), # Accept String('Accept:', name='accept', fuzzable=self.http_fuzz_protocol), Delimiter(' ', name='delimiter-5', fuzzable=self.http_fuzz_protocol), String('*/*', name='accept_type_', fuzzable=self.http_fuzz_protocol), Static('\r\n', name='EOL-4'), # Cache-control no-cache by default String('Cache-Control:', name='cache-control', fuzzable=self.http_fuzz_protocol), Delimiter(' ', name='delimiter-6', fuzzable=self.http_fuzz_protocol), String('no-cache', name='cache_control_type', fuzzable=self.http_fuzz_protocol), Static('\r\n', name='EOL-5'), # Host, the target host String('Host:', name='host_name', fuzzable=self.http_fuzz_protocol), Delimiter(' ', name='delimiter-7', fuzzable=self.http_fuzz_protocol), String(self.target_host, name='target_host', fuzzable=False), # do not fuzz target host address! Static('\r\n', name='EOL-6'), # Content length: obvious payload lenght. String('Content-Length:', name='content_length', fuzzable=self.http_fuzz_protocol), Delimiter(' ', name='delimiter-9', fuzzable=self.http_fuzz_protocol), String(str(len(self.http_payload)), name='content_length_len', fuzzable=False), Static('\r\n', name='EOM-8'), # Connection close, do not use keep-alive it results only one mutation, than the # fuzzer will hang. String('Connection:', name='accept_encoding', fuzzable=self.http_fuzz_protocol), Delimiter(' ', name='delimiter-8', fuzzable=self.http_fuzz_protocol), String('close', name='accept_encoding_types', fuzzable=False), # do not fuzz this field! Static('\r\n', name='EOM-7'), # Content type String('Content-Type:', name='Content-Type', fuzzable=self.http_fuzz_protocol), Delimiter(' ', name='delimiter-10', fuzzable=self.http_fuzz_protocol), String(self.http_content_type, name='content_type_', fuzzable=self.http_fuzz_protocol), Static('\n\r\n', name='EOM-9'), # Payload String(self.http_payload, name='payload'), Static('\r\n\r\n', name='EOM-10') ]) self.logger.info( f"[{time.strftime('%H:%M:%S')}] Prepare HttpTarget ...") target = HttpTarget(name='HttpTarget', host=self.target_host, port=self.target_port, max_retries=10, timeout=None) target.set_expect_response('true') self.logger.info( f"[{time.strftime('%H:%M:%S')}] Prepare HttpController ...") controller = HttpGetController('HttpGetController', host=self.target_host, port=self.target_port) target.set_controller(controller) self.logger.info( f"[{time.strftime('%H:%M:%S')}] Defining GraphModel...") model = GraphModel() model.connect(http_template) fuzzer = ServerFuzzer() fuzzer.set_interface(WebInterface(port=26001)) fuzzer.set_model(model) fuzzer.set_target(target) fuzzer.set_delay_between_tests(1) self.logger.info(f"[{time.strftime('%H:%M:%S')}] Start Fuzzer...") self.logger.info( f"[Further info are in the related Kitty log output!]") fuzzer.start() self.logger.info(f"[{time.strftime('%H:%M:%S')}] End Fuzzer Session") fuzzer.stop()
class WebInterfaceTest(BaseTestCase): def setUp(self): super(WebInterfaceTest, self).setUp(None) self.t_str = Template(name='simple_str_template', fields=[String(name='str1', value='kitty')]) self.t_int = Template(name='simple_int_template', fields=[UInt32(name='int1', value=0x1234)]) self.fuzzer = None self.host = '127.0.0.1' self.port = 11223 self.url = 'http://%(host)s:%(port)s' % {'host': self.host, 'port': self.port} self.prepare() def tearDown(self): if self.fuzzer: self.logger.info('still have fuzzer, stop it') self.fuzzer.stop() def prepare(self): self.start_index = 0 self.end_index = 20 self.delay_duration = 0 self.fuzzer = ServerFuzzer(name="TestServerFuzzer", logger=self.logger) self.model = GraphModel() self.model.logger = self.logger self.model.connect(self.t_str) self.fuzzer.set_model(self.model) def _webValidRequest(self, request): resp = requests.get(request) self.assertIsNotNone(resp) self.assertEqual(resp.status_code, 200) as_json = resp.json() self.assertIsNotNone(as_json) return as_json def _webGetStats(self): return self._webValidRequest('%s/api/stats.json' % self.url) def _webGetReport(self, report_id): return self._webValidRequest('%s/api/report?report_id=%s' % (self.url, report_id)) def _webGetTemplateInfo(self): return self._webValidRequest('%s/api/template_info.json' % self.url) def _webGetStages(self): return self._webValidRequest('%s/api/stages.json' % self.url) def _webGetFavicon(self): resp = requests.get('%s/favicon.ico' % self.url) self.assertIsNotNone(resp) self.assertEqual(resp.status_code, 200) return resp def _webGetReportList(self): resp = self._webGetStats() self.assertIn('reports_extended', resp) reports = resp['reports_extended'] return reports def _runFuzzerWithReportList(self, uut, report_list): config = {} for report_id in report_list: config[str(report_id)] = {'report': {'status': 'failed', 'reason': 'failure reason'}} self.fuzzer.set_interface(uut) target = ServerTargetMock(config, logger=self.logger) self.fuzzer.set_target(target) self.fuzzer.start() def _testStatsApiReportList(self, report_list): uut = WebInterface(host=self.host, port=self.port) report_list.sort() self._runFuzzerWithReportList(uut, report_list) actual_report_list = [x[0] for x in self._webGetReportList()] self.assertListEqual(actual_report_list, report_list) def testStatsApiReportListEmpty(self): self._testStatsApiReportList([]) def testStatsApiReportListSingle(self): self._testStatsApiReportList([5]) def testStatsApiReportListMultiple(self): self._testStatsApiReportList([1, 2, 3, 4, 5]) def testStatsApiReportListAll(self): self._testStatsApiReportList([x for x in range(self.end_index)]) def testTemplateInfoApi(self): # # This is based on the usage in index.html # uut = WebInterface(host=self.host, port=self.port) self._runFuzzerWithReportList(uut, []) template_info = self._webGetTemplateInfo() self.assertIn('name', template_info) self.assertIn('field_type', template_info) self.assertIn('fields', template_info) self.assertIn('mutation', template_info) self.assertIn('total_number', template_info['mutation']) self.assertIn('current_index', template_info['mutation']) def testGetStagesApi(self): uut = WebInterface(host=self.host, port=self.port) self._runFuzzerWithReportList(uut, []) resp = self._webGetStages() self.assertIn('current', resp) self.assertIn('stages', resp) def _testReportApiReportExists(self, report_list): for report_id in report_list: response = self._webGetReport(report_id) self.assertIn('report', response) self.assertIn('encoding', response) def _testReportApiValid(self, report_list): self._testStatsApiReportList(report_list) self._testReportApiReportExists(report_list) def testReportApiSingle(self): self._testReportApiValid([1]) def testReportApiMultiple(self): self._testReportApiValid([1, 2, 3]) def testReportApiAll(self): self._testReportApiValid([x for x in range(self.end_index)]) def _testReportApiError(self, request): self._testReportApiValid([x for x in range(self.end_index)]) resp = self._webValidRequest(request) self.assertIn('error', resp) self.assertNotIn('report', resp) def testReportApiErrorWhenNoReportId(self): self._testReportApiError('%s/api/report' % (self.url)) def testReportApiErrorWhenReportIdNotInt(self): self._testReportApiError('%s/api/report?report_id=%s' % (self.url, '%%')) def testReportApiErrorWhenNoSuchReport(self): self._testReportApiError('%s/api/report?report_id=%s' % (self.url, self.end_index + 1)) def _testPauseApi(self): ''' .. todo:: pause/resume api tests ''' pass def get_static_content(self, filename): (dir_path, _) = os.path.split(__file__) index_path = os.path.join(dir_path, '..', 'kitty', 'interfaces', 'web', 'static', filename) data = None with open(index_path, 'rb') as f: data = f.read() return data def testGetIndexHtml(self): url = self.url + '/index.html' uut = WebInterface(host=self.host, port=self.port) self._runFuzzerWithReportList(uut, []) resp = requests.get(url) self.assertEqual(resp.status_code, 200) self.assertEqual(resp.headers['content-type'], 'text/html') index_content = self.get_static_content('index.html') self.assertEqual(resp.text, index_content) def testReturnIndexForRoot(self): root_url = self.url + '/' index_url = self.url + '/index.html' uut = WebInterface(host=self.host, port=self.port) self._runFuzzerWithReportList(uut, []) root_resp = requests.get(root_url) index_url = requests.get(index_url) self.assertEqual(root_resp.status_code, 200) self.assertEqual(root_resp.headers['content-type'], 'text/html') self.assertEqual(root_resp.text, index_url.text) def testGetOtherFilesReturns401(self): url = self.url + '/../../../../../../../etc/passwd' uut = WebInterface(host=self.host, port=self.port) self._runFuzzerWithReportList(uut, []) resp = requests.get(url) self.assertEqual(resp.status_code, 401) def testPost(self): url = self.url + '/index.html' uut = WebInterface(host=self.host, port=self.port) self._runFuzzerWithReportList(uut, []) resp = requests.post(url) self.assertEqual(resp.status_code, 200) self.assertEqual(resp.headers['content-type'], 'text/html') index_content = self.get_static_content('index.html') self.assertEqual(resp.text, index_content)
def mod(ics_ip): print ">>>>> ICS FUZZING MODULE <<<<<\n" # 定义目标Fuzz对象的IP地址 TARGET_IP = ics_ip # 定义目标Fuzz对象的通讯端口 TARGET_PORT = 502 # 定义随机数种子 RANDSEED = int(RandShort()) # 根据ISF中Modbus-tcp协议的数据结构构造测试数据包,下面例子中将使用RandShort对请求的地址及bit位长度进行测试 write_coils_request_packet = ModbusHeaderRequest( func_code=0x05) / WriteSingleCoilRequest(ReferenceNumber=RandShort(), Value=RandShort()) # 使用ScapyField直接将Scapy的数据包结构应用于Kitty框架中 write_coils_request_packet_template = Template( name='Write Coils Request', fields=[ ScapyField( write_coils_request_packet, name='wrire_coils_request_packet', # 定义这个Field的名字,用于在报告中显示 fuzzable=True, # 定义这个Field是否需要Fuzz seed=RANDSEED, # 定义用于变异的随机数 fuzz_count=2000 # 这个数据结构的fuzz次数 ), ]) # 使用GraphModel进行Fuzz model = GraphModel() # 在使用GraphModel中注册第一个节点,由于Modbus的Read Coils请求是单次的请求/回答形式,因此这里只要注册简单的一个节点即可 model.connect(write_coils_request_packet_template) # 定义一个目标Target, 设置IP、端口及连接超时时间 modbus_target = TcpTarget(name='modbus target', host=TARGET_IP, port=TARGET_PORT, timeout=2) # 定义是需要等待Target返回响应,如果设置为True Target不返回数据包则会被识别成异常进行记录。 modbus_target.set_expect_response(True) # 定义使用ServerFuzzer的方式进行Fuzz测试 fuzzer = ServerFuzzer() # 定义fuzzer使用的交互界面为web界面 fuzzer.set_interface(WebInterface(port=26001)) # 在fuzzer中定义使用GraphModel fuzzer.set_model(model) # 在fuzzer中定义target为modbus_target fuzzer.set_target(modbus_target) # 定义每个测试用例发送之间的延迟 fuzzer.set_delay_between_tests(0.1) # 开始执行Fuzz fuzzer.start()