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 __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()
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()
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 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()
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()
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()
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)
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!'
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_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()
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 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 = 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()
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)
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)
encoder=ENC_INT_DEC), Static('\r\n\r\n', name='eom') ]) #define target target = TcpTarget(name='test_target', host=target_ip, port=target_port, timeout=2) target.set_expect_response(True) #define controller controller = WinAppDbgController(name='test_controller', process_path='C:\\ProgramData\\SOFTCMS\\AspWebServer.exe') target.set_controller(controller) #define model model = GraphModel() model.connect(data) #define fuzzer fuzzer = ServerFuzzer() fuzzer.set_interface(WebInterface(host='0.0.0.0', port=web_port)) fuzzer.set_model(model) fuzzer.set_target(target) fuzzer.set_delay_between_tests(0.5) fuzzer.start()