예제 #1
0
    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
예제 #2
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)
예제 #3
0
 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
예제 #4
0
 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
예제 #5
0
파일: fuzz.py 프로젝트: RoelofBerg/VxFuzz
    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
예제 #6
0
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()
예제 #7
0
    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)
예제 #8
0
 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()
예제 #9
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)
예제 #10
0
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
예제 #11
0
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()
예제 #12
0
    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)
예제 #13
0
파일: runner.py 프로젝트: Fors3cDream/kitty
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()
예제 #14
0
파일: runner.py 프로젝트: cisco-sas/kitty
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()
예제 #15
0
    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)
예제 #16
0
    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)
예제 #17
0
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()
예제 #18
0
    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)
예제 #19
0
    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()
예제 #20
0
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()
예제 #21
0
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
예제 #22
0
    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)
예제 #23
0
    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)
예제 #24
0
    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)
예제 #25
0
    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()
예제 #26
0
    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()
예제 #27
0
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])
예제 #28
0
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()
예제 #29
0
    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()
예제 #30
0
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()
예제 #31
0
파일: runner.py 프로젝트: dovf/kitty
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()
예제 #32
0
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'),
예제 #33
0
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:
예제 #34
0
파일: runner.py 프로젝트: cisco-sas/kitty
                 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()
예제 #35
0
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])
예제 #36
0
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
예제 #37
0
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,
예제 #38
0
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)
예제 #39
0
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()
예제 #40
0
 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 = []
예제 #41
0
 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 = []
예제 #42
0
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)
예제 #43
0
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)
예제 #44
0
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)
예제 #46
0
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)
예제 #47
0
파일: fuzz.py 프로젝트: wapen/VxFuzz
    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