def main(cls): """ Main NmFuzzer function :return: 0 if successful, -1 otherwise """ args = cls.parse_args() logger = cls.logger(levels[args.log_level], "NetworkMiner.fuzz", "./session.log") prog = os.path.abspath(args.target_prog) start_tc = int(args.start) # define target target = WinAppDbgTarget("NetworkMiner", process_path=prog, process_args=[], logger=logger) # Template t1 = Template(name="PCAPs", fields=[ FsNames(args.test_corpus, name_filter="*.pcap", name="paths"), ]) model = GraphModel() model.connect(t1) # define the fuzzing session fuzzer = ServerFuzzer( name="NetworkMiner fuzzer", logger=logger, ) fuzzer.set_interface(WebInterface()) fuzzer.set_model(model) fuzzer.set_target(target) fuzzer.set_delay_between_tests(2) # Start try: logger.info("Starting fuzz session...") fuzzer.set_range(start_tc) start_time = time.time() fuzzer.start() end_time = time.time() logger.info("Done with fuzzing in {} seconds".format(end_time - start_time)) raw_input("Press enter to exit...") fuzzer.stop() except KeyboardInterrupt: logger.info("Session interrupted by user...") fuzzer.stop() return 1 except Exception as exc: logger.error(exc) fuzzer.stop() return -1 return 0
def prepare(self): self.start_index = 10 self.end_index = 20 self.delay_duration = 0 self.fuzzer = ClientFuzzer(name="TestServerFuzzer", logger=self.logger) self.interface = EmptyInterface() self.fuzzer.set_interface(self.interface) self.model = GraphModel() self.model.logger = self.logger self.model.connect(self.t_str) self.fuzzer.set_model(self.model) self.default_config = { 'always': { 'trigger': { 'fuzzer': self.fuzzer, 'stages': [(self._default_stage, {})] } } } self.target = ClientTargetMock(self.default_config, self.default_callback, logger=self.logger) 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 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 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 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(): test_name = 'GET fuzzed' get_template = Template( name=test_name, fields=[ XmlElement( name='html', element_name='html', content=[ XmlElement( name='head', element_name='head', content='<meta http-equiv="refresh" content="5; url=/">' ), XmlElement(name='body', element_name='body', content='123', fuzz_content=True), ]) ]) fuzzer = ClientFuzzer(name='Example 3 - Browser Fuzzer') fuzzer.set_interface(WebInterface(host='0.0.0.0', port=26000)) target = ClientTarget(name='BrowserTarget') # # Note: to avoid opening the process on our X server, we use another display for it # display ':2' that is specified below was started this way: # >> sudo apt-get install xvfb # >> Xvfb :2 -screen 2 1280x1024x8 # env = os.environ.copy() env['DISPLAY'] = ':2' controller = ClientProcessController('BrowserController', '/usr/bin/opera', ['http://localhost:8082/fuzzed'], process_env=env) target.set_controller(controller) target.set_mutation_server_timeout(20) model = GraphModel() model.connect(get_template) fuzzer.set_model(model) fuzzer.set_target(target) fuzzer.set_delay_between_tests(0.1) server = MyHttpServer(('localhost', 8082), MyHttpHandler, fuzzer) fuzzer.start() while True: server.handle_request()
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 run(self): target = FuzzerTarget(name='target', base_url=self.base_url, report_dir=self.report_dir) interface = WebInterface() model = GraphModel() for template in self.templates: model.connect(template.compile_template()) fuzzer = OpenApiServerFuzzer() fuzzer.set_model(model) fuzzer.set_target(target) fuzzer.set_interface(interface) fuzzer.start()
def prepare(self): self.start_index = 10 self.end_index = 20 self.delay_duration = 0 self.fuzzer = ClientFuzzer(name="TestServerFuzzer", logger=self.logger) self.interface = EmptyInterface() self.fuzzer.set_interface(self.interface) self.model = GraphModel() self.model.logger = self.logger self.model.connect(self.t_str) self.fuzzer.set_model(self.model) self.default_config = { 'always': { 'trigger': { 'fuzzer': self.fuzzer, 'stages': [ (self._default_stage, {}) ] } } } self.target = ClientTargetMock(self.default_config, self.default_callback, logger=self.logger) 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 get_model(options): ''' Get the data model :param options: options :return: session model ''' stage_file = options['--stage-file'] stages = get_stages(stage_file) templates = {} templates.update(enumerate_templates(audio)) templates.update(enumerate_templates(cdc)) templates.update(enumerate_templates(enum)) templates.update(enumerate_templates(generic)) templates.update(enumerate_templates(hid)) templates.update(enumerate_templates(hub)) templates.update(enumerate_templates(mass_storage)) templates.update(enumerate_templates(smart_card)) g = GraphModel('usb model (%s)' % (stage_file)) for stage in stages: if stage in templates: stage_template = templates[stage] stage_count = min(stages[stage], int(options['--count'])) add_stage(g, stage, stage_template, stage_count) return g
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 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(): test_name = 'GET /fuzzed' get_template = Template(name=test_name, fields=[ XmlElement(name='html', element_name='html', content=[ XmlElement(name='head', element_name='head', content='<meta http-equiv="refresh" content="5; url=/">'), XmlElement(name='body', element_name='body', content='123', fuzz_content=True), ]) ]) fuzzer = ClientFuzzer(name='BrowserFuzzer') fuzzer.set_interface(WebInterface(host='0.0.0.0', port=26000)) target = ClientTarget(name='BrowserTarget') # # Note: to avoid opening the process on our X server, we use another display for it # display ':2' that is specified below was started this way: # >> sudo apt-get install xvfb # >> Xvfb :2 -screen 2 1280x1024x8 # env = os.environ.copy() env['DISPLAY'] = ':2' controller = ClientProcessController( 'BrowserController', '/usr/bin/opera', ['http://localhost:8082/fuzzed'], process_env=env ) target.set_controller(controller) target.set_mutation_server_timeout(20) model = GraphModel() model.connect(get_template) fuzzer.set_model(model) fuzzer.set_target(target) fuzzer.set_delay_between_tests(0.1) server = MyHttpServer(('localhost', 8082), MyHttpHandler, fuzzer) fuzzer.start() while True: server.handle_request()
def main(): test_name = 'GET fuzzed' get_template = Template(name=test_name, fields=[ XmlElement(name='html', element_name='html', content=[ XmlElement(name='head', element_name='head', content='<meta http-equiv="refresh" content="5; url=/">'), XmlElement(name='body', element_name='body', content='123', fuzz_content=True), ]) ]) fuzzer = ClientFuzzer(name='Example 2 - Browser Fuzzer (Remote)') fuzzer.set_interface(WebInterface(host='0.0.0.0', port=26000)) target = ClientTarget(name='BrowserTarget') # # Note: to avoid opening the process on our X server, we use another display for it # display ':2' that is specified below was started this way: # >> sudo apt-get install xvfb # >> Xvfb :2 -screen 2 1280x1024x8 # env = os.environ.copy() env['DISPLAY'] = ':2' controller = ClientProcessController( 'BrowserController', '/usr/bin/opera', ['http://localhost:8082/fuzzed'], process_env=env ) target.set_controller(controller) target.set_mutation_server_timeout(20) model = GraphModel() model.connect(get_template) fuzzer.set_model(model) fuzzer.set_target(target) # # only fuzz the half of the mutations, just as an example fuzzer.set_range(end_index=model.num_mutations() / 2) fuzzer.set_delay_between_tests(0.1) remote = RpcServer(host='localhost', port=26007, impl=fuzzer) remote.start()
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 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()
def get_model(options): ''' Get the data model :param options: options :return: session model ''' stage_file = options['--stage-file'] stages = get_stages(stage_file) templates = enumerate_templates(usb_templates) g = GraphModel('usb model (%s)' % (stage_file)) for stage in stages: if stage in templates: stage_template = templates[stage] stage_count = min(stages[stage], int(options['--count'])) add_stage(g, stage, stage_template, stage_count) return g
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 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)
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 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 TestClientFuzzer(unittest.TestCase): def setUp(self): self.logger = get_test_logger() self.logger.debug('TESTING METHOD: %s', self._testMethodName) self._default_stage = 'simple_str_template' self.t_str = Template(name=self._default_stage, fields=[String(name='str1', value='kitty')]) self.t_int = Template(name='simple_int_template', fields=[UInt32(name='int1', value=0x1234)]) self.fuzzer = None self.mutations = {} self.prepare() def tearDown(self): if self.fuzzer: self.fuzzer.stop() def default_callback(self, test, stage, resp): if test not in self.mutations: self.mutations[test] = [] self.mutations[test].append((stage, resp)) def prepare(self): self.start_index = 10 self.end_index = 20 self.delay_duration = 0 self.fuzzer = ClientFuzzer(name="TestServerFuzzer", logger=self.logger) self.interface = EmptyInterface() self.fuzzer.set_interface(self.interface) self.model = GraphModel() self.model.logger = self.logger self.model.connect(self.t_str) self.fuzzer.set_model(self.model) self.default_config = { 'always': { 'trigger': { 'fuzzer': self.fuzzer, 'stages': [(self._default_stage, {})] } } } self.target = ClientTargetMock(self.default_config, self.default_callback, logger=self.logger) 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 testVanilla(self): self.fuzzer.start() self.fuzzer.wait_until_done() 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() self.fuzzer.wait_until_done() 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() self.fuzzer.wait_until_done() 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() self.fuzzer.wait_until_done() 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 testTestFailedWhenReportIsFailed(self): config = { '13': { 'report': { 'status': 'failed', 'reason': 'failure reason' } } } config.update(self.default_config) target = ClientTargetMock(config, self.default_callback, logger=self.logger) self.fuzzer.set_target(target) self.fuzzer.start() self.fuzzer.wait_until_done() info = self.fuzzer._get_session_info() reports = self.fuzzer.dataman.get_report_test_ids() self.assertEqual( sorted(reports), sorted([int(x) for x in config.keys() if x != 'always'])) self.assertEqual(info.failure_count, len(config) - 1) 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' } } } config.update(self.default_config) target = ClientTargetMock(config, self.default_callback, logger=self.logger) self.fuzzer.set_target(target) self.fuzzer.start() self.fuzzer.wait_until_done() info = self.fuzzer._get_session_info() reports = self.fuzzer.dataman.get_report_test_ids() self.assertEqual( sorted(reports), sorted([int(x) for x in config.keys() if x != 'always'])) self.assertEqual(info.failure_count, len(config) - 1) def testStoringAllReportsWhenStoreAllReportsIsSetToTrue(self): config = {} config.update(self.default_config) target = ClientTargetMock(config, self.default_callback, logger=self.logger) self.fuzzer.set_store_all_reports(True) self.fuzzer.set_target(target) self.fuzzer.start() self.fuzzer.wait_until_done() 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() self.fuzzer.set_range(start_index) self.fuzzer.start() self.fuzzer.wait_until_done() 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 testGetMutationForStage(self): self.fuzzer.set_range(0, 1) config = { 'always': { 'trigger': { 'fuzzer': self.fuzzer, 'stages': [(self._default_stage, {})] } } } target = ClientTargetMock(config, self.default_callback, logger=self.logger) self.fuzzer.set_target(target) self.fuzzer.start() self.fuzzer.wait_until_done() self.assertIn(0, self.mutations) self.assertEqual(self.mutations[0][0][0], self._default_stage) self.assertIsNotNone(self.mutations[0][0][1]) def testGetMutationForStageTwice(self): self.fuzzer.set_range(0, 1) config = { 'always': { 'trigger': { 'fuzzer': self.fuzzer, 'stages': [(self._default_stage, {}), (self._default_stage, {})] } } } target = ClientTargetMock(config, self.default_callback, logger=self.logger) self.fuzzer.set_target(target) self.fuzzer.start() self.fuzzer.wait_until_done() self.assertIn(0, self.mutations) self.assertEqual(self.mutations[0][0][0], self._default_stage) self.assertIsNotNone(self.mutations[0][0][1]) self.assertEqual(self.mutations[0][1][0], self._default_stage) self.assertIsNotNone(self.mutations[0][1][1]) def testGetMutationWrongStage(self): self.fuzzer.set_range(0, 1) wrong_stage = 'simple_str_template1' config = { 'always': { 'trigger': { 'fuzzer': self.fuzzer, 'stages': [ (wrong_stage, {}), ] } } } target = ClientTargetMock(config, self.default_callback, logger=self.logger) self.fuzzer.set_target(target) self.fuzzer.start() self.fuzzer.wait_until_done() self.assertIn(0, self.mutations) self.assertEqual(self.mutations[0][0][0], wrong_stage) self.assertIsNone(self.mutations[0][0][1]) def testGetMutationWrongAfterCorrectStage(self): self.fuzzer.set_range(0, 1) wrong_stage = 'simple_str_template1' config = { 'always': { 'trigger': { 'fuzzer': self.fuzzer, 'stages': [ (self._default_stage, {}), (wrong_stage, {}), ] } } } target = ClientTargetMock(config, self.default_callback, logger=self.logger) self.fuzzer.set_target(target) self.fuzzer.start() self.fuzzer.wait_until_done() self.assertIn(0, self.mutations) self.assertEqual(self.mutations[0][0][0], self._default_stage) self.assertIsNotNone(self.mutations[0][0][1]) self.assertEqual(self.mutations[0][1][0], wrong_stage) self.assertIsNone(self.mutations[0][1][1]) def testGetMutationCorrectAfterWrongStage(self): self.fuzzer.set_range(0, 1) wrong_stage = 'simple_str_template1' config = { 'always': { 'trigger': { 'fuzzer': self.fuzzer, 'stages': [ (wrong_stage, {}), (self._default_stage, {}), ] } } } target = ClientTargetMock(config, self.default_callback, logger=self.logger) self.fuzzer.set_target(target) self.fuzzer.start() self.fuzzer.wait_until_done() self.assertIn(0, self.mutations) self.assertEqual(self.mutations[0][0][0], wrong_stage) self.assertIsNone(self.mutations[0][0][1]) self.assertEqual(self.mutations[0][1][0], self._default_stage) self.assertIsNotNone(self.mutations[0][1][1]) def testGetMutationWithWildcard(self): self.fuzzer.set_range(0, 1) config = { 'always': { 'trigger': { 'fuzzer': self.fuzzer, 'stages': [(ClientFuzzer.STAGE_ANY, {})] } } } target = ClientTargetMock(config, self.default_callback, logger=self.logger) self.fuzzer.set_target(target) self.fuzzer.start() self.fuzzer.wait_until_done() self.assertIn(0, self.mutations) self.assertEqual(self.mutations[0][0][0], ClientFuzzer.STAGE_ANY) self.assertIsNotNone(self.mutations[0][0][1])
class GraphModelTests(unittest.TestCase): def setUp(self): self.logger = get_test_logger() self.logger.debug('TESTING METHOD: %s', self._testMethodName) self.model = GraphModel() self.templates = self.get_templates() self.todo = [] def get_templates(self): res = [] res.append(Template(name='t1', fields=[String('data1')])) res.append(Template(name='t2', fields=[String('data2'), UInt32(300)])) res.append(Template(name='t3', fields=[UInt32(400)])) return res def _check_sequences(self, expected_sequences): self.logger.debug('check num_mutations()') t_num_mutations = sum(s[-1].num_mutations() for s in expected_sequences) m_num_mutations = self.model.num_mutations() self.assertEqual(t_num_mutations, m_num_mutations) sequences = {} while self.model.mutate(): sequence = tuple(self.model.get_sequence()) if sequence not in sequences: sequences[sequence] = 1 else: sequences[sequence] += 1 self.assertEqual(len(sequences), len(expected_sequences)) self.logger.debug( 'check that each sequence appears the appropriate number of times') for sequence, count in sequences.items(): seq_templates = [e.dst for e in sequence] self.assertIn(seq_templates, expected_sequences) last = seq_templates[-1] last_num_mutations = last.num_mutations() self.assertEqual(count, last_num_mutations) def testSequenceSingleTemplate(self): t = self.templates[0] self.model.connect(t) expected_sequences = [[t]] self._check_sequences(expected_sequences) def testSequenceDirectPath(self): ''' root -> t1 ''' self.model.connect(self.templates[0]) for i in range(len(self.templates) - 1): self.model.connect(self.templates[i], self.templates[i + 1]) expected_sequences = list(self.templates[:i + 1] for i in range(len(self.templates))) self._check_sequences(expected_sequences) def testSequenceComplexPath(self): ''' root -> t1 root -> t1 -> t2 root -> t1 -> t3 root -> t1 -> t2 -> t3 ''' self.model.connect(self.templates[0]) self.model.connect(self.templates[0], self.templates[1]) self.model.connect(self.templates[0], self.templates[2]) self.model.connect(self.templates[1], self.templates[2]) expected_sequences = [[self.templates[0]], [self.templates[0], self.templates[1]], [self.templates[0], self.templates[2]], [ self.templates[0], self.templates[1], self.templates[2] ]] self._check_sequences(expected_sequences) def testMultiHeadPath(self): ''' root -> t1 root -> t2 root -> t3 ''' expected_sequences = [] for t in self.templates: expected_sequences.append([t]) self.model.connect(t) self._check_sequences(expected_sequences) def _check_skip(self, to_skip, expected_skipped, expected_mutated): skipped = self.model.skip(to_skip) self.assertEqual(expected_skipped, skipped) mutated = 0 while self.model.mutate(): mutated += 1 self.assertEqual(expected_mutated, mutated) def testSkipZeroSingleTemplate(self): self.model.connect(self.templates[0]) m_num_mutations = self.model.num_mutations() to_skip = 0 expected_skipped = to_skip expected_mutated = m_num_mutations self._check_skip(to_skip, expected_skipped, expected_mutated) def testSkipHalfSingleTemplate(self): self.model.connect(self.templates[0]) m_num_mutations = self.model.num_mutations() to_skip = m_num_mutations // 2 expected_skipped = to_skip expected_mutated = m_num_mutations - expected_skipped self._check_skip(to_skip, expected_skipped, expected_mutated) def testSkipExactSingleTemplate(self): self.model.connect(self.templates[0]) m_num_mutations = self.model.num_mutations() to_skip = m_num_mutations expected_skipped = to_skip expected_mutated = m_num_mutations - expected_skipped self._check_skip(to_skip, expected_skipped, expected_mutated) def testSkipTooMuchSingleTemplate(self): self.model.connect(self.templates[0]) m_num_mutations = self.model.num_mutations() to_skip = m_num_mutations + 10 expected_skipped = m_num_mutations expected_mutated = m_num_mutations - expected_skipped self._check_skip(to_skip, expected_skipped, expected_mutated) def testSkipZeroMultiTemplate(self): self.model.connect(self.templates[0]) self.model.connect(self.templates[0], self.templates[1]) m_num_mutations = self.model.num_mutations() to_skip = 0 expected_skipped = to_skip expected_mutated = m_num_mutations self._check_skip(to_skip, expected_skipped, expected_mutated) def testSkipHalfMultiTemplate(self): self.model.connect(self.templates[0]) self.model.connect(self.templates[0], self.templates[1]) m_num_mutations = self.model.num_mutations() to_skip = m_num_mutations // 2 expected_skipped = to_skip expected_mutated = m_num_mutations - expected_skipped self._check_skip(to_skip, expected_skipped, expected_mutated) def testSkipExactMultiTemplate(self): self.model.connect(self.templates[0]) self.model.connect(self.templates[0], self.templates[1]) m_num_mutations = self.model.num_mutations() to_skip = m_num_mutations expected_skipped = to_skip expected_mutated = m_num_mutations - expected_skipped self._check_skip(to_skip, expected_skipped, expected_mutated) def testSkipTooMuchMultiTemplate(self): self.model.connect(self.templates[0]) self.model.connect(self.templates[0], self.templates[1]) m_num_mutations = self.model.num_mutations() to_skip = m_num_mutations + 10 expected_skipped = m_num_mutations expected_mutated = m_num_mutations - expected_skipped self._check_skip(to_skip, expected_skipped, expected_mutated) def testFailureToTo(self): self.assertEqual(len(self.todo), 0) def testExceptionIfLoop(self): self.model.connect(self.templates[0]) self.model.connect(self.templates[0], self.templates[1]) self.model.connect(self.templates[1], self.templates[0]) with self.assertRaises(KittyException): self.model.num_mutations()
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()
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()
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()
from kitty.data.data_manager import DataManager, DataManagerTask from kitty.fuzzers import ServerFuzzer from kitty.interfaces import WebInterface from kitty.model import GraphModel from rest.target import TcpTarget from rest.controller import MyController from katnip.legos import url from katnip.legos.json import dict_to_JsonObject target = TcpTarget("tcp target", "0.0.0.0", 5000) controller = BaseController("my controlller") target.set_controller(controller) model = GraphModel() from kitty.model import * #GET /somewhere HTTP/1.1 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'),
from kitty.controllers import EmptyController from kitty.fuzzers import ServerFuzzer from kitty.interfaces import WebInterface from katnip.targets.file import FileTarget from kitty.model import String from kitty.model import Template from kitty.model import GraphModel from chaostoolkitfuzzdiscover.experimentfilewriter.writegeneratedfuzz import InputFuzzExperimentGenerator, InputFileFuzzExperimentGenerator, InternalFileFuzzExperimentGenerator import os, shutil, pickle sample_template = Template(name='T1', fields=[ String('The default string', name='S1_1'), String('Another string', name='S1_2'), ]) sample_model = GraphModel() sample_model.connect(sample_template) #TODO : Add input validations & fix input 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:
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()
class TestClientFuzzer(unittest.TestCase): def setUp(self): self.logger = get_test_logger() self.logger.debug('TESTING METHOD: %s', self._testMethodName) self._default_stage = 'simple_str_template' self.t_str = Template(name=self._default_stage, fields=[String(name='str1', value='kitty')]) self.t_int = Template(name='simple_int_template', fields=[UInt32(name='int1', value=0x1234)]) self.fuzzer = None self.mutations = {} self.prepare() def tearDown(self): if self.fuzzer: self.fuzzer.stop() def default_callback(self, test, stage, resp): if test not in self.mutations: self.mutations[test] = [] self.mutations[test].append((stage, resp)) def prepare(self): self.start_index = 10 self.end_index = 20 self.delay_duration = 0 self.fuzzer = ClientFuzzer(name="TestServerFuzzer", logger=self.logger) self.interface = EmptyInterface() self.fuzzer.set_interface(self.interface) self.model = GraphModel() self.model.logger = self.logger self.model.connect(self.t_str) self.fuzzer.set_model(self.model) self.default_config = { 'always': { 'trigger': { 'fuzzer': self.fuzzer, 'stages': [ (self._default_stage, {}) ] } } } self.target = ClientTargetMock(self.default_config, self.default_callback, logger=self.logger) 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 testVanilla(self): self.fuzzer.start() self.fuzzer.wait_until_done() 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() self.fuzzer.wait_until_done() 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() self.fuzzer.wait_until_done() 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() self.fuzzer.wait_until_done() 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 testTestFailedWhenReportIsFailed(self): config = { '13': { 'report': { 'status': 'failed', 'reason': 'failure reason' } } } config.update(self.default_config) target = ClientTargetMock(config, self.default_callback, logger=self.logger) self.fuzzer.set_target(target) self.fuzzer.start() self.fuzzer.wait_until_done() info = self.fuzzer._get_session_info() reports = self.fuzzer.dataman.get_report_test_ids() self.assertEqual(sorted(reports), sorted([int(x) for x in config.keys() if x != 'always'])) self.assertEqual(info.failure_count, len(config) - 1) 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'}} } config.update(self.default_config) target = ClientTargetMock(config, self.default_callback, logger=self.logger) self.fuzzer.set_target(target) self.fuzzer.start() self.fuzzer.wait_until_done() info = self.fuzzer._get_session_info() reports = self.fuzzer.dataman.get_report_test_ids() self.assertEqual(sorted(reports), sorted([int(x) for x in config.keys() if x != 'always'])) self.assertEqual(info.failure_count, len(config) - 1) def testStoringAllReportsWhenStoreAllReportsIsSetToTrue(self): config = {} config.update(self.default_config) target = ClientTargetMock(config, self.default_callback, logger=self.logger) self.fuzzer.set_store_all_reports(True) self.fuzzer.set_target(target) self.fuzzer.start() self.fuzzer.wait_until_done() 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() self.fuzzer.set_range(start_index) self.fuzzer.start() self.fuzzer.wait_until_done() 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 testGetMutationForStage(self): self.fuzzer.set_range(0, 1) config = { 'always': { 'trigger': { 'fuzzer': self.fuzzer, 'stages': [ (self._default_stage, {}) ] } } } target = ClientTargetMock(config, self.default_callback, logger=self.logger) self.fuzzer.set_target(target) self.fuzzer.start() self.fuzzer.wait_until_done() self.assertIn(0, self.mutations) self.assertEquals(self.mutations[0][0][0], self._default_stage) self.assertIsNotNone(self.mutations[0][0][1]) def testGetMutationForStageTwice(self): self.fuzzer.set_range(0, 1) config = { 'always': { 'trigger': { 'fuzzer': self.fuzzer, 'stages': [ (self._default_stage, {}), (self._default_stage, {}) ] } } } target = ClientTargetMock(config, self.default_callback, logger=self.logger) self.fuzzer.set_target(target) self.fuzzer.start() self.fuzzer.wait_until_done() self.assertIn(0, self.mutations) self.assertEquals(self.mutations[0][0][0], self._default_stage) self.assertIsNotNone(self.mutations[0][0][1]) self.assertEquals(self.mutations[0][1][0], self._default_stage) self.assertIsNotNone(self.mutations[0][1][1]) def testGetMutationWrongStage(self): self.fuzzer.set_range(0, 1) wrong_stage = 'simple_str_template1' config = { 'always': { 'trigger': { 'fuzzer': self.fuzzer, 'stages': [ (wrong_stage, {}), ] } } } target = ClientTargetMock(config, self.default_callback, logger=self.logger) self.fuzzer.set_target(target) self.fuzzer.start() self.fuzzer.wait_until_done() self.assertIn(0, self.mutations) self.assertEquals(self.mutations[0][0][0], wrong_stage) self.assertIsNone(self.mutations[0][0][1]) def testGetMutationWrongAfterCorrectStage(self): self.fuzzer.set_range(0, 1) wrong_stage = 'simple_str_template1' config = { 'always': { 'trigger': { 'fuzzer': self.fuzzer, 'stages': [ (self._default_stage, {}), (wrong_stage, {}), ] } } } target = ClientTargetMock(config, self.default_callback, logger=self.logger) self.fuzzer.set_target(target) self.fuzzer.start() self.fuzzer.wait_until_done() self.assertIn(0, self.mutations) self.assertEquals(self.mutations[0][0][0], self._default_stage) self.assertIsNotNone(self.mutations[0][0][1]) self.assertEquals(self.mutations[0][1][0], wrong_stage) self.assertIsNone(self.mutations[0][1][1]) def testGetMutationCorrectAfterWrongStage(self): self.fuzzer.set_range(0, 1) wrong_stage = 'simple_str_template1' config = { 'always': { 'trigger': { 'fuzzer': self.fuzzer, 'stages': [ (wrong_stage, {}), (self._default_stage, {}), ] } } } target = ClientTargetMock(config, self.default_callback, logger=self.logger) self.fuzzer.set_target(target) self.fuzzer.start() self.fuzzer.wait_until_done() self.assertIn(0, self.mutations) self.assertEquals(self.mutations[0][0][0], wrong_stage) self.assertIsNone(self.mutations[0][0][1]) self.assertEquals(self.mutations[0][1][0], self._default_stage) self.assertIsNotNone(self.mutations[0][1][1]) def testGetMutationWithWildcard(self): self.fuzzer.set_range(0, 1) config = { 'always': { 'trigger': { 'fuzzer': self.fuzzer, 'stages': [ (ClientFuzzer.STAGE_ANY, {}) ] } } } target = ClientTargetMock(config, self.default_callback, logger=self.logger) self.fuzzer.set_target(target) self.fuzzer.start() self.fuzzer.wait_until_done() self.assertIn(0, self.mutations) self.assertEquals(self.mutations[0][0][0], ClientFuzzer.STAGE_ANY) self.assertIsNotNone(self.mutations[0][0][1])
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
from kitty.fuzzers import ServerFuzzer from kitty.interfaces import WebInterface from kitty.model import GraphModel from rest.target import TcpTarget from rest.controller import MyController from katnip.legos import url from katnip.legos.json import dict_to_JsonObject target = TcpTarget("tcp target", "0.0.0.0", 5000) controller = BaseController("my controlller") target.set_controller(controller) model = GraphModel() from kitty.model import * class Method(String): _encoder_type_ = StrEncoder lib = None def __init__(self, value, max_size=None, encoder=ENC_STR_DEFAULT, fuzzable=True, name=None): super(Method, self).__init__(value=value,
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)
class GraphModelTests(unittest.TestCase): def setUp(self): self.logger = get_test_logger() self.logger.debug('TESTING METHOD: %s', self._testMethodName) self.model = GraphModel() self.templates = self.get_templates() self.todo = [] def get_templates(self): res = [] res.append(Template(name='t1', fields=[String('data1')])) res.append(Template(name='t2', fields=[String('data2'), UInt32(300)])) res.append(Template(name='t3', fields=[UInt32(400)])) return res def _check_sequences(self, expected_sequences): self.logger.debug('check num_mutations()') t_num_mutations = sum(s[-1].num_mutations() for s in expected_sequences) m_num_mutations = self.model.num_mutations() self.assertEqual(t_num_mutations, m_num_mutations) sequences = {} while self.model.mutate(): sequence = tuple(self.model.get_sequence()) if sequence not in sequences: sequences[sequence] = 1 else: sequences[sequence] += 1 self.assertEqual(len(sequences), len(expected_sequences)) self.logger.debug('check that each sequence appears the appropriate number of times') for sequence, count in sequences.items(): seq_templates = [e.dst for e in sequence] self.assertIn(seq_templates, expected_sequences) last = seq_templates[-1] last_num_mutations = last.num_mutations() self.assertEqual(count, last_num_mutations) def test_sequence_single_template(self): t = self.templates[0] self.model.connect(t) expected_sequences = [[t]] self._check_sequences(expected_sequences) def test_sequence_direct_path(self): ''' root -> t1 ''' self.model.connect(self.templates[0]) for i in range(len(self.templates) - 1): self.model.connect(self.templates[i], self.templates[i + 1]) expected_sequences = list(self.templates[:i + 1] for i in range(len(self.templates))) self._check_sequences(expected_sequences) def test_sequence_complex_path(self): ''' root -> t1 root -> t1 -> t2 root -> t1 -> t3 root -> t1 -> t2 -> t3 ''' self.model.connect(self.templates[0]) self.model.connect(self.templates[0], self.templates[1]) self.model.connect(self.templates[0], self.templates[2]) self.model.connect(self.templates[1], self.templates[2]) expected_sequences = [ [self.templates[0]], [self.templates[0], self.templates[1]], [self.templates[0], self.templates[2]], [self.templates[0], self.templates[1], self.templates[2]] ] self._check_sequences(expected_sequences) def test_multi_head_path(self): ''' root -> t1 root -> t2 root -> t3 ''' expected_sequences = [] for t in self.templates: expected_sequences.append([t]) self.model.connect(t) self._check_sequences(expected_sequences) def _check_skip(self, to_skip, expected_skipped, expected_mutated): skipped = self.model.skip(to_skip) self.assertEqual(expected_skipped, skipped) mutated = 0 while self.model.mutate(): mutated += 1 self.assertEqual(expected_mutated, mutated) def test_skip_zero_single_template(self): self.model.connect(self.templates[0]) m_num_mutations = self.model.num_mutations() to_skip = 0 expected_skipped = to_skip expected_mutated = m_num_mutations self._check_skip(to_skip, expected_skipped, expected_mutated) def test_skip_half_single_template(self): self.model.connect(self.templates[0]) m_num_mutations = self.model.num_mutations() to_skip = m_num_mutations / 2 expected_skipped = to_skip expected_mutated = m_num_mutations - expected_skipped self._check_skip(to_skip, expected_skipped, expected_mutated) def test_skip_exact_single_template(self): self.model.connect(self.templates[0]) m_num_mutations = self.model.num_mutations() to_skip = m_num_mutations expected_skipped = to_skip expected_mutated = m_num_mutations - expected_skipped self._check_skip(to_skip, expected_skipped, expected_mutated) def test_skip_too_much_single_template(self): self.model.connect(self.templates[0]) m_num_mutations = self.model.num_mutations() to_skip = m_num_mutations + 10 expected_skipped = m_num_mutations expected_mutated = m_num_mutations - expected_skipped self._check_skip(to_skip, expected_skipped, expected_mutated) def test_skip_zero_multi_template(self): self.model.connect(self.templates[0]) self.model.connect(self.templates[0], self.templates[1]) m_num_mutations = self.model.num_mutations() to_skip = 0 expected_skipped = to_skip expected_mutated = m_num_mutations self._check_skip(to_skip, expected_skipped, expected_mutated) def test_skip_half_multi_template(self): self.model.connect(self.templates[0]) self.model.connect(self.templates[0], self.templates[1]) m_num_mutations = self.model.num_mutations() to_skip = m_num_mutations / 2 expected_skipped = to_skip expected_mutated = m_num_mutations - expected_skipped self._check_skip(to_skip, expected_skipped, expected_mutated) def test_skip_exact_multi_template(self): self.model.connect(self.templates[0]) self.model.connect(self.templates[0], self.templates[1]) m_num_mutations = self.model.num_mutations() to_skip = m_num_mutations expected_skipped = to_skip expected_mutated = m_num_mutations - expected_skipped self._check_skip(to_skip, expected_skipped, expected_mutated) def test_skip_too_much_multi_template(self): self.model.connect(self.templates[0]) self.model.connect(self.templates[0], self.templates[1]) m_num_mutations = self.model.num_mutations() to_skip = m_num_mutations + 10 expected_skipped = m_num_mutations expected_mutated = m_num_mutations - expected_skipped self._check_skip(to_skip, expected_skipped, expected_mutated) def test_failure_to_to(self): self.assertEqual(len(self.todo), 0) def test_exception_if_loop(self): self.model.connect(self.templates[0]) self.model.connect(self.templates[0], self.templates[1]) self.model.connect(self.templates[1], self.templates[0]) with self.assertRaises(KittyException): self.model.num_mutations()
def setUp(self): self.logger = get_test_logger() self.logger.debug('TESTING METHOD: %s', self._testMethodName) self.model = GraphModel() self.templates = self.get_templates() self.todo = []
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)
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)
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()
# Make target expect response target.set_expect_response(True) # Define controller controller = MyLocalProcessController(name='simple_server', process_path='./simple_server_orig', process_args=[], delay_after_start=0.2, start_each_test=False, logger=None) target.set_controller(controller) # Define model model = GraphModel() model.connect(get_startdt) model.connect(get_startdt, get_stopdt) model.connect(get_startdt, get_testfr) model.connect(get_testfr, get_stopdt) model.connect(get_startdt, get_GI) model.connect(get_GI, get_stopdt) # Define fuzzer fuzzer = ServerFuzzer(option_line="") fuzzer.set_interface(WebInterface(port=web_port)) fuzzer.set_model(model) fuzzer.set_target(target)
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 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