Exemple #1
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
 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
Exemple #3
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)
Exemple #4
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)
Exemple #5
0
    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
Exemple #6
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()
Exemple #7
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()
Exemple #8
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()
Exemple #9
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='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()
Exemple #10
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 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()
Exemple #11
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)
Exemple #12
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)
Exemple #13
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()
    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()
Exemple #15
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()
Exemple #16
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
http_get_vX = Template(name='HTTP_GET_VX', fields = [
    Method('GET', name='method', fuzzable=False),
    Delimiter(' ', name='space1', fuzzable=False),
    url.Path('api/pet/7', name='path'),# moze sqlinjection?
    Delimiter(' ', name='space2',fuzzable=False),
    String('HTTP', name='protocol name',fuzzable=False),
    Delimiter('/', name='fws1',fuzzable=False),
    Dword(1, name='major version', encoder=ENC_INT_DEC,fuzzable=False),
    Delimiter('.', name='dot1',fuzzable=False),
    Dword(1, name='minor version', encoder=ENC_INT_DEC,fuzzable=False),
    Static('\r\n'),
    Static('Host: 127.0.0.1:5000'),
    Static('\r\n'),
    Static('Connection: close'),
    Static('\r\n\r\n', name='eom')
])

model.connect(http_get_vX)
fuzzer = ServerFuzzer()
fuzzer.set_model(model)
fuzzer.set_target(target)
fuzzer.set_store_all_reports(True)
os.remove("fuzz_session.sqlite")
fuzzer.set_session_file("fuzz_session.sqlite")
fuzzer.set_interface(WebInterface())


fuzzer.start()
print 'finished!'
Exemple #18
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()
Exemple #19
0
        Static('\r\n\r\n'),
        Container(name='chunk',
                  fields=[
                      dict_to_JsonObject({
                          'breed': 'Husky',
                          'id': 1,
                          'name': 'Bingo',
                          'tag': 'friendly'
                      })
                  ]),
        Static(
            '\r\n\r\n', name='eom'
        )  # 4. The double "new lines" ("\r\n\r\n") at the end of the request
    ])

model.connect(http_post_json)
fuzzer = ServerFuzzer()
fuzzer.set_model(model)
fuzzer.set_target(target)
fuzzer.set_store_all_reports(True)
os.remove("fuzz_session.sqlite")
fuzzer.set_session_file("fuzz_session.sqlite")
fuzzer.set_interface(WebInterface())

fuzzer.start()
print 'finished!'

# manager = fuzzer.dataman.get_session_info_manager()
# session_info = manager.get_session_info()
#
#
Exemple #20
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()
Exemple #21
0
        Dword(1, name='minor version', encoder=ENC_INT_DEC),
        Static('\r\n'),
        Static('Host: 127.0.0.1:5000'),
        Static('\r\n'),
        Static('Content-Type: text/plain'),
        Static('\r\n'),
        Static('Content-Length: '),
        Size(name='size in bytes',
             sized_field='chunk',
             length=32,
             encoder=ENC_INT_DEC,
             calc_func=lambda x: len(x) / 8),
        Static('\r\n\r\n'),
        Container(name='chunk', fields=[Static('say=Hi&to=Mom', name='form')]),
        Static(
            '\r\n\r\n', name='eom'
        )  # 4. The double "new lines" ("\r\n\r\n") at the end of the request
    ])

model.connect(http_get_vPost)
fuzzer = ServerFuzzer()
fuzzer.set_model(model)
fuzzer.set_target(target)
fuzzer.set_store_all_reports(True)
os.remove("fuzz_session.sqlite")
fuzzer.set_session_file("fuzz_session.sqlite")
fuzzer.set_interface(WebInterface())

fuzzer.start()
print 'finished!'
http_get_v1 = Template(name='HTTP_GET_V1',
                       fields=[
                           String('GET', name='method', fuzzable=False),
                           Delimiter(' ', name='space1', fuzzable=False),
                           Delimiter('/', name='backslash'),
                           String('somewhere', name='path', max_size=5),
                           Delimiter(' ', name='space2'),
                           String('HTTP', name='protocol name'),
                           Delimiter('/', name='fws1'),
                           Dword(1, name='major version', encoder=ENC_INT_DEC),
                           Delimiter('.', name='dot1'),
                           Dword(1, name='minor version', encoder=ENC_INT_DEC),
                           Static('\r\n'),
                           Static('Host: 127.0.0.1:5000'),
                           Static('\r\n'),
                           Static('Connection: close'),
                           Static('\r\n\r\n', name='eom')
                       ])

model.connect(http_get_v1)
fuzzer = ServerFuzzer()
fuzzer.set_model(model)
fuzzer.set_target(target)
fuzzer.set_store_all_reports(True)
os.remove("fuzz_session.sqlite")
fuzzer.set_session_file("fuzz_session.sqlite")
fuzzer.set_interface(WebInterface())

fuzzer.start()
print 'finished!'
http_get_v2 = Template(name='HTTP_GET_V2',
                       fields=[
                           String('GET', name='method', fuzzable=False),
                           Delimiter(' ', name='space1', fuzzable=False),
                           url.Path('somewhere/else', name='path'),
                           Delimiter(' ', name='space2'),
                           String('HTTP', name='protocol name'),
                           Delimiter('/', name='fws1'),
                           Dword(1, name='major version', encoder=ENC_INT_DEC),
                           Delimiter('.', name='dot1'),
                           Dword(1, name='minor version', encoder=ENC_INT_DEC),
                           Static('\r\n'),
                           Static('Host: 127.0.0.1:5000'),
                           Static('\r\n'),
                           Static('Connection: close'),
                           Static('\r\n\r\n', name='eom')
                       ])

model.connect(http_get_v2)
fuzzer = ServerFuzzer()
fuzzer.set_model(model)
fuzzer.set_target(target)
fuzzer.set_store_all_reports(True)
os.remove("fuzz_session.sqlite")
fuzzer.set_session_file("fuzz_session.sqlite")
fuzzer.set_interface(WebInterface())

fuzzer.start()
print 'finished!'
    ])

################# Actual fuzzer code #################

target = ClientTarget(name='104Target')
controller = ClientProcessController(
        "simple_client_single",
        "./simple_client_fast",
        ["10.84.134.10"]
    )
target.set_controller(controller)
target.set_mutation_server_timeout(20)
 

model = GraphModel()
model.connect(get_startdt)
#model.connect(get_startdt, get_stopdt)
model.connect(get_startdt, get_ASDU)

#model.connect(get_startdt, get_testfr)
#model.connect(get_testfr, get_stopdt)

fuzzer = ClientFuzzer(name='104 Fuzzer')
fuzzer.set_model(model)
fuzzer.set_target(target)
fuzzer.set_interface(WebInterface(host='0.0.0.0', port=26000))
fuzzer.set_delay_between_tests(0.1)

my_stack = My104Stack("10.84.69.44")
my_stack.set_fuzzer(fuzzer)
fuzzer.start()
Exemple #25
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()
Exemple #26
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 = ServerTargetMock(config, logger=self.logger)
        self.fuzzer.set_target(target)

        self.fuzzer.start()

    def _testStatsApiReportList(self, report_list):
        uut = WebInterface(host=self.host, port=self.port)
        report_list.sort()
        self._runFuzzerWithReportList(uut, report_list)
        actual_report_list = self._webGetReportList()
        self.assertListEqual(actual_report_list, report_list)

    def testStatsApiReportListEmpty(self):
        self._testStatsApiReportList([])

    def testStatsApiReportListSingle(self):
        self._testStatsApiReportList([5])

    def testStatsApiReportListMultiple(self):
        self._testStatsApiReportList([1, 2, 3, 4, 5])

    def testStatsApiReportListAll(self):
        self._testStatsApiReportList([x for x in range(self.end_index)])

    def _testStatsApi(self):
        '''
        .. todo:: other stats API tests
        '''
        pass

    def _testReportApiReportExists(self, report_list):
        for report_id in report_list:
            response = self._webGetReport(report_id)
            self.assertIn('report', response)
            self.assertIn('encoding', response)

    def _testReportApiValid(self, report_list):
        self._testStatsApiReportList(report_list)
        self._testReportApiReportExists(report_list)

    def testReportApiSingle(self):
        self._testReportApiValid([1])

    def testReportApiMultiple(self):
        self._testReportApiValid([1, 2, 3])

    def testReportApiAll(self):
        self._testReportApiValid([x for x in range(self.end_index)])

    def _testReportApiError(self, request):
        self._testReportApiValid([x for x in range(self.end_index)])
        resp = self._webValidRequest(request)
        self.assertIn('error', resp)
        self.assertNotIn('report', resp)

    def testReportApiErrorWhenNoReportId(self):
        self._testReportApiError('%s/api/report' % (self.url))

    def testReportApiErrorWhenReportIdNotInt(self):
        self._testReportApiError('%s/api/report?report_id=%s' %
                                 (self.url, '%%'))

    def testReportApiErrorWhenNoSuchReport(self):
        self._testReportApiError('%s/api/report?report_id=%s' %
                                 (self.url, self.end_index + 1))

    def _testPauseApi(self):
        '''
        .. todo:: pause/resume api tests
        '''
        pass
Exemple #27
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()
Exemple #28
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)
Exemple #29
0
                 edge.src is the get_session template
                 edge.dst is the send_data template
    :param resp: the response from the target
    """
    fuzzer.logger.info("session is: %s" % resp[1:3].encode("hex"))
    fuzzer.target.session_data["session_id"] = resp[1:3]


# Define session target
target = TcpTarget(name="session_test_target", host=target_ip, port=target_port, timeout=2)
# Make target expect response
target.set_expect_response(True)


# Define controller
controller = SessionServerController(name="ServerController", host=target_ip, port=target_port)
target.set_controller(controller)

# Define model
model = GraphModel()
model.connect(get_session)
model.connect(get_session, send_data, new_session_callback)

# Define fuzzer
fuzzer = ServerFuzzer()
fuzzer.set_interface(WebInterface(port=web_port))
fuzzer.set_model(model)
fuzzer.set_target(target)
fuzzer.set_delay_between_tests(0.2)
fuzzer.start()
class TestClientFuzzer(unittest.TestCase):
    def setUp(self):
        self.logger = get_test_logger()
        self.logger.debug('TESTING METHOD: %s', self._testMethodName)
        self._default_stage = 'simple_str_template'

        self.t_str = Template(name=self._default_stage,
                              fields=[String(name='str1', value='kitty')])

        self.t_int = Template(name='simple_int_template',
                              fields=[UInt32(name='int1', value=0x1234)])
        self.fuzzer = None
        self.mutations = {}
        self.prepare()

    def tearDown(self):
        if self.fuzzer:
            self.fuzzer.stop()

    def default_callback(self, test, stage, resp):
        if test not in self.mutations:
            self.mutations[test] = []
        self.mutations[test].append((stage, resp))

    def prepare(self):
        self.start_index = 10
        self.end_index = 20
        self.delay_duration = 0
        self.fuzzer = ClientFuzzer(name="TestServerFuzzer", logger=self.logger)

        self.interface = EmptyInterface()
        self.fuzzer.set_interface(self.interface)

        self.model = GraphModel()
        self.model.logger = self.logger

        self.model.connect(self.t_str)
        self.fuzzer.set_model(self.model)

        self.default_config = {
            'always': {
                'trigger': {
                    'fuzzer': self.fuzzer,
                    'stages': [(self._default_stage, {})]
                }
            }
        }
        self.target = ClientTargetMock(self.default_config,
                                       self.default_callback,
                                       logger=self.logger)
        self.fuzzer.set_target(self.target)

        self.fuzzer.set_range(self.start_index, self.end_index)
        self.fuzzer.set_delay_between_tests(self.delay_duration)

    def testRaisesExceptionWhenStartedWithoutModel(self):

        self.fuzzer.set_model(None)
        self.assertRaises(AssertionError, self.fuzzer.start)
        self.fuzzer = None

    def testRaisesExceptionWhenStartedWithoutTarget(self):
        self.fuzzer.set_target(None)
        self.assertRaises(AssertionError, self.fuzzer.start)
        self.fuzzer = None

    def testRaisesExceptionWhenStartedWithoutInterface(self):
        self.fuzzer.set_interface(None)
        self.assertRaises(AssertionError, self.fuzzer.start)
        self.fuzzer = None

    def testVanilla(self):
        self.fuzzer.start()
        self.fuzzer.wait_until_done()
        info = self.fuzzer._get_session_info()
        # reports = self.fuzzer._get_reports_manager()
        # self.assertEqual(len(reports), 0)
        self.assertEqual(info.failure_count, 0)
        self.assertEqual(info.current_index, None)
        # self.assertEqual(info.original_start_index, 10)
        self.assertEqual(info.start_index, self.start_index)
        self.assertEqual(info.end_index, self.end_index)

    def testStartingFromStartIndex(self):
        start_index = self.model.num_mutations() - 2
        self.fuzzer.set_range(start_index)
        self.fuzzer.start()
        self.fuzzer.wait_until_done()

        info = self.fuzzer._get_session_info()
        self.assertEqual(info.current_index, None)
        self.assertEqual(info.end_index, self.model.last_index())

    def testEndingAtEndIndex(self):
        start_index = 0
        end_index = 3
        self.fuzzer.set_range(start_index, end_index)
        self.fuzzer.start()
        self.fuzzer.wait_until_done()

        info = self.fuzzer._get_session_info()
        self.assertEqual(info.start_index, 0)
        self.assertEqual(info.end_index, 3)
        self.assertEqual(info.current_index, None)

    def testFullMutationRange(self):
        self.fuzzer.set_range()
        self.fuzzer.start()
        self.fuzzer.wait_until_done()

        info = self.fuzzer._get_session_info()
        self.assertEqual(info.start_index, 0)
        self.assertEqual(info.end_index, self.model.last_index())
        self.assertEqual(info.current_index, None)

    def testTestFailedWhenReportIsFailed(self):
        config = {
            '13': {
                'report': {
                    'status': 'failed',
                    'reason': 'failure reason'
                }
            }
        }
        config.update(self.default_config)
        target = ClientTargetMock(config,
                                  self.default_callback,
                                  logger=self.logger)
        self.fuzzer.set_target(target)
        self.fuzzer.start()
        self.fuzzer.wait_until_done()
        info = self.fuzzer._get_session_info()
        reports = self.fuzzer.dataman.get_report_test_ids()
        self.assertEqual(
            sorted(reports),
            sorted([int(x) for x in config.keys() if x != 'always']))
        self.assertEqual(info.failure_count, len(config) - 1)

    def testAllFailedTestsHaveReports(self):
        config = {
            '10': {
                'report': {
                    'status': 'failed',
                    'reason': 'failure reason'
                }
            },
            '11': {
                'report': {
                    'status': 'failed',
                    'reason': 'failure reason'
                }
            },
            '12': {
                'report': {
                    'status': 'failed',
                    'reason': 'failure reason'
                }
            },
            '13': {
                'report': {
                    'status': 'failed',
                    'reason': 'failure reason'
                }
            }
        }
        config.update(self.default_config)
        target = ClientTargetMock(config,
                                  self.default_callback,
                                  logger=self.logger)
        self.fuzzer.set_target(target)
        self.fuzzer.start()
        self.fuzzer.wait_until_done()
        info = self.fuzzer._get_session_info()
        reports = self.fuzzer.dataman.get_report_test_ids()
        self.assertEqual(
            sorted(reports),
            sorted([int(x) for x in config.keys() if x != 'always']))
        self.assertEqual(info.failure_count, len(config) - 1)

    def testStoringAllReportsWhenStoreAllReportsIsSetToTrue(self):
        config = {}
        config.update(self.default_config)
        target = ClientTargetMock(config,
                                  self.default_callback,
                                  logger=self.logger)
        self.fuzzer.set_store_all_reports(True)
        self.fuzzer.set_target(target)
        self.fuzzer.start()
        self.fuzzer.wait_until_done()
        info = self.fuzzer._get_session_info()
        reports = self.fuzzer.dataman.get_report_test_ids()
        expected_mutation_count = self.end_index - self.start_index + 1
        expected_failure_count = 0
        self.assertEqual(len(reports), expected_mutation_count)
        self.assertEqual(info.failure_count, expected_failure_count)

    def testOnlyTestsInSetRangeAreExecuted(self):
        start_index = self.model.num_mutations() - 5
        self.model.connect(self.t_str, self.t_int)
        expected_end_index = self.model.last_index()
        self.fuzzer.set_range(start_index)
        self.fuzzer.start()
        self.fuzzer.wait_until_done()
        info = self.fuzzer._get_session_info()
        self.assertEqual(info.failure_count, 0)
        self.assertEqual(info.current_index, None)
        self.assertEqual(info.start_index, start_index)
        self.assertEqual(info.end_index, expected_end_index)

    def testGetMutationForStage(self):
        self.fuzzer.set_range(0, 1)
        config = {
            'always': {
                'trigger': {
                    'fuzzer': self.fuzzer,
                    'stages': [(self._default_stage, {})]
                }
            }
        }
        target = ClientTargetMock(config,
                                  self.default_callback,
                                  logger=self.logger)
        self.fuzzer.set_target(target)
        self.fuzzer.start()
        self.fuzzer.wait_until_done()
        self.assertIn(0, self.mutations)
        self.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])
Exemple #31
0
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:
                __parent_tokens.extend(__tokens[2:])
Exemple #32
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()
Exemple #33
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)
Exemple #34
0
    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
Exemple #35
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)
http_get_v3 = Template(
    name='HTTP_GET_V3',
    fields=[
        Method('GET', name='method', fuzzable=True),  # 7 + iteration
        Delimiter(' ', name='space1', fuzzable=False),
        url.Path('somewhere/else', name='path'),
        Delimiter(' ', name='space2'),
        String('HTTP', name='protocol name'),
        Delimiter('/', name='fws1'),
        Dword(1, name='major version', encoder=ENC_INT_DEC),
        Delimiter('.', name='dot1'),
        Dword(1, name='minor version', encoder=ENC_INT_DEC),
        Static('\r\n'),
        Static('Host: 127.0.0.1:5000'),
        Static('\r\n'),
        Static('Connection: close'),
        Static('\r\n\r\n', name='eom')
    ])

model.connect(http_get_v3)
fuzzer = ServerFuzzer()
fuzzer.set_model(model)
fuzzer.set_target(target)
fuzzer.set_store_all_reports(True)
os.remove("fuzz_session.sqlite")
fuzzer.set_session_file("fuzz_session.sqlite")
fuzzer.set_interface(WebInterface())

fuzzer.start()
print 'finished!'
Exemple #37
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()
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)
fuzzer.set_delay_between_tests(0.2)
fuzzer.start()
Exemple #39
0
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()
Exemple #40
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)
Exemple #41
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])
    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()