def testFailureInSubReportEntry(self): entry_name = 'sub report' report = Report(self.report_name) subreport = Report(entry_name) report.add(entry_name, subreport) subreport.failed(self.failure_reason) self.assertEqual(report.get_status(), Report.FAILED) self.assertEqual(report.get('reason'), self.failure_reason)
def testSuccess(self): ''' .. note:: success was deprecated, and it only calls passed() ''' report = Report(self.report_name) report.failed(self.failure_reason) self.assertEqual(report.get_status(), Report.FAILED) report.success() self.assertEqual(report.get_status(), Report.PASSED)
def transmit(self, payload): ''' Transmit single payload, and receive response, if expected. The actual implementation of the send/receive should be in ``_send_to_target`` and ``_receive_from_target``. :type payload: str :param payload: payload to send :rtype: str :return: the response (if received) ''' response = None trans_report_name = 'transmission_0x%04x' % self.transmission_count trans_report = Report(trans_report_name) self.transmission_report = trans_report self.report.add(trans_report_name, trans_report) try: trans_report.add('request (hex)', payload.encode('hex')) trans_report.add('request (raw)', '%s' % payload) trans_report.add('request length', len(payload)) trans_report.add('request time', time.time()) request = payload.encode('hex') request = request if len(request) < 100 else (request[:100] + ' ...') self.logger.info('request(%d): %s' % (len(payload), request)) self._send_to_target(payload) trans_report.success() if self.expect_response: try: response = self._receive_from_target() trans_report.add('response time', time.time()) trans_report.add('response (hex)', response.encode('hex')) trans_report.add('response (raw)', '%s' % response) trans_report.add('response length', len(response)) printed_response = response.encode('hex') printed_response = printed_response if len(printed_response) < 100 else (printed_response[:100] + ' ...') self.logger.info('response(%d): %s' % (len(response), printed_response)) except Exception as ex2: trans_report.failed('failed to receive response: %s' % ex2) trans_report.add('traceback', traceback.format_exc()) self.logger.error('target.transmit - failure in receive (exception: %s)' % ex2) self.logger.error(traceback.format_exc()) self.receive_failure = True else: response = '' except Exception as ex1: trans_report.failed('failed to send payload: %s' % ex1) trans_report.add('traceback', traceback.format_exc()) self.logger.error('target.transmit - failure in send (exception: %s)' % ex1) self.logger.error(traceback.format_exc()) self.send_failure = True self.transmission_count += 1 return response
def transmit(self, payload): """ This is the original transmit method from ServerTarget overwritten with special cases such as 40X or 50X according to the aim of the test. Accordin to https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/500 500 Internal Server Error 501 Not Implemented 502 Bad Gateway 503 Service Unavailable 504 Gateway Timeout 505 HTTP Version Not Supported 506 Variant Also Negotiates 507 Insufficient Storage 508 Loop Detected 510 Not Extended 511 Network Authentication Required Original method docstring: Transmit single payload, and receive response, if expected. The actual implementation of the send/receive should be in ``_send_to_target`` and ``_receive_from_target``. :type payload: str :param payload: payload to send :rtype: str :return: the response (if received) """ SERVER_50x_CODES = [ '500 Internal Server Error', '501 Not Implemented', '502 Bad Gateway', '503 Service Unavailable', '504 Gateway Timeout', '505 HTTP Version Not Supported', '506 Variant Also Negotiates', '507 Insufficient Storage', '508 Loop Detected', '510 Not Extended', '511 Network Authentication Required' ] SERVER_40xCODES = [ '400 Bad Request', '401 Unauthorized', '402 Payment Required', '403 Forbidden', '404 Not Found', '405 Method Not Allowed', '406 Not Acceptable', '407 Proxy Authentication Required', '408 Request Timeout', '409 Conflict', '410 Gone', '411 Length Required', '412 Precondition Failed', '413 Payload Too Large', '414 URI Too Long', '415 Unsupported Media Type', '416 Range Not Satisfiable', '417 Expectation Failed', '422 Unprocessable Entity', '425 Too Early', '426 Upgrade Required', '428 Precondition Required', '429 Too Many Requests', '431 Request Header Fields Too Large', '451 Unavailable For Legal Reasons' ] response = None trans_report_name = 'transmission_0x%04x' % self.transmission_count trans_report = Report(trans_report_name) self.transmission_report = trans_report self.report.add(trans_report_name, trans_report) try: trans_report.add('request (hex)', hexlify(payload).decode()) trans_report.add('request (raw)', '%s' % payload) trans_report.add('request length', len(payload)) trans_report.add('request time', time.time()) request = hexlify(payload).decode() request = request if len(request) < 100 else (request[:100] + ' ...') self.logger.info(f"request({len(payload)}): {request}") self.logger.debug(f"payload {payload}") self._send_to_target(payload) trans_report.success() if self.expect_response: try: response = self._receive_from_target() trans_report.add('response time', time.time()) trans_report.add('response (hex)', hexlify(response).decode()) trans_report.add('response (raw)', '%s' % response) trans_report.add('response length', len(response)) trans_report.add('Session ID', str(self._uuid)) printed_response = hexlify(response).decode() printed_response = printed_response if len( printed_response) < 100 else (printed_response[:100] + ' ...') self.logger.info( f"response({len(response)}): {printed_response}") string_response = response.decode('utf-8') response_code_string = string_response.splitlines()[0] response_code = response_code_string.replace( 'HTTP/1.1 ', '') if response_code in SERVER_40xCODES or response_code in SERVER_50x_CODES: self.logger.info( f"response failure {response.decode('utf-8')}") trans_report.failed('Failure in HTTP-PROTO response.') trans_report.add('Response', response.decode('utf-8')) self.report.set_status('failed') self.receive_failure = True except Exception as ex2: trans_report.failed('failed to receive response: %s' % ex2) trans_report.add('traceback', traceback.format_exc()) self.logger.error( f"target.transmit - failure in receive (exception: {ex2})" ) self.logger.error(traceback.format_exc()) self.receive_failure = True else: response = '' except Exception as ex1: #trans_report.failed('failed to send payload: %s' % ex1) #trans_report.add('traceback', traceback.format_exc()) self.logger.error( f"target.transmit - failure in send (exception: {ex1})") self.logger.error(traceback.format_exc()) #self.send_failure = True self.transmission_count += 1 return response
def testClearRestoresStatusToDefaultPassed(self): report = Report(self.report_name) self.assertEqual(report.get_status(), Report.PASSED) report.failed('mock failure') report.clear() self.assertEqual(report.get_status(), Report.PASSED)
def testPassed(self): report = Report(self.report_name) report.failed(self.failure_reason) self.assertEqual(report.get_status(), Report.FAILED) report.passed() self.assertEqual(report.get_status(), Report.PASSED)
def testFailedWithoutReason(self): report = Report(self.report_name) self.assertEqual(report.get_status(), Report.PASSED) report.failed() self.assertEqual(report.get_status(), Report.FAILED) self.assertEqual(report.get('reason'), None)
class BaseTarget(KittyObject): ''' BaseTarget contains the common logic and behaviour of all target. ''' def __init__(self, name='BaseTarget', logger=None): super(BaseTarget, self).__init__(name, logger) self.controller = None self.monitors = [] self.report = Report(name) self.test_number = None self.fuzzer = None def set_fuzzer(self, fuzzer): self.fuzzer = fuzzer def set_controller(self, controller): ''' Set a controller ''' self.controller = controller def add_monitor(self, monitor): ''' Add a monitor ''' self.monitors.append(monitor) def setup(self): ''' Make sure the target is ready for fuzzing, including monitors and controllers ''' if self.controller: self.controller.setup() for monitor in self.monitors: monitor.setup() def teardown(self): ''' Clean up the target once all tests are completed ''' if self.controller: self.controller.teardown() for monitor in self.monitors: monitor.teardown() def pre_test(self, test_num): ''' Called when a test is started ''' self.test_number = test_num self.report = Report(self.name) if self.controller: self.controller.pre_test(test_number=self.test_number) for monitor in self.monitors: monitor.pre_test(test_number=self.test_number) self.report.add('test_number', test_num) self.report.add('state', 'STARTED') def post_test(self, test_num): ''' Called when test is completed, a report should be prepared now ''' if self.controller: self.controller.post_test() for monitor in self.monitors: monitor.post_test() self.report.add('state', 'COMPLETED') if self.controller: controller_report = self.controller.get_report() self.report.add('controller', controller_report) for monitor in self.monitors: current_report = monitor.get_report() self.report.add(current_report.get('name'), current_report) if self.report.is_failed(): self.report.failed() if self.report.is_failed(): self.logger.warning('!!! Test %d failed !!!' % (test_num)) def get_report(self): return self.report def get_session_data(self): ''' Session related data dictionary to be used by data model. :return: dictionary (str, bytes) ''' return {}
def transmit(self, payload): ''' Transmit single payload, and receive response, if expected. The actual implementation of the send/receive should be in ``_send_to_target`` and ``_receive_from_target``. :type payload: str :param payload: payload to send :rtype: str :return: the response (if received) ''' response = None trans_report_name = 'transmission_0x%04x' % self.transmission_count trans_report = Report(trans_report_name) self.transmission_report = trans_report self.report.add(trans_report_name, trans_report) try: trans_report.add('request (hex)', hexlify(payload).decode()) trans_report.add('request (raw)', '%s' % payload) trans_report.add('request length', len(payload)) trans_report.add('request time', time.time()) request = hexlify(payload).decode() request = request if len(request) < 100 else (request[:100] + ' ...') self.logger.info('request(%d): %s' % (len(payload), request)) self._send_to_target(payload) trans_report.success() if self.expect_response: try: response = self._receive_from_target() trans_report.add('response time', time.time()) trans_report.add('response (hex)', hexlify(response).decode()) trans_report.add('response (raw)', '%s' % response) trans_report.add('response length', len(response)) printed_response = hexlify(response).decode() printed_response = printed_response if len( printed_response) < 100 else (printed_response[:100] + ' ...') self.logger.info('response(%d): %s' % (len(response), printed_response)) except Exception as ex2: trans_report.failed('failed to receive response: %s' % ex2) trans_report.add('traceback', traceback.format_exc()) self.logger.error( 'target.transmit - failure in receive (exception: %s)' % ex2) self.logger.error(traceback.format_exc()) self.receive_failure = True else: response = '' except Exception as ex1: trans_report.failed('failed to send payload: %s' % ex1) trans_report.add('traceback', traceback.format_exc()) self.logger.error( 'target.transmit - failure in send (exception: %s)' % ex1) self.logger.error(traceback.format_exc()) self.send_failure = True self.transmission_count += 1 return response
def transmit(self, payload): """ This is the original transmit method from ServerTarget overwritten with DNS response code specific reporting Accordin to: https://support.umbrella.com/hc/en-us/articles/232254248-Common-DNS-return-codes-for-any-DNS-service-and-Umbrella- NOERROR RCODE:0 DNS Query completed successfully FORMERR RCODE:1 DNS Query Format Error SERVFAIL RCODE:2 Server failed to complete the DNS request NXDOMAIN RCODE:3 Domain name does not exist. NOTIMP RCODE:4 Function not implemented REFUSED RCODE:5 The server refused to answer for the query YXDOMAIN RCODE:6 Name that should not exist, does exist XRRSET RCODE:7 RRset that should not exist, does exist NOTAUTH RCODE:8 Server not authoritative for the zone NOTZONE RCODE:9 Name not in zone Original method docstring: Transmit single payload, and receive response, if expected. The actual implementation of the send/receive should be in ``_send_to_target`` and ``_receive_from_target``. :type payload: str :param payload: payload to send :rtype: str :return: the response (if received) """ DNS_RETRUN_CODES = [ 'NOERROR', 'FORMERR', 'SERVFAIL', 'NXDOMAIN', 'NOTIMP', 'REFUSED', 'YXDOMAIN', 'XRRSET', 'NOTAUTH', 'NOTZONE' ] DNS_EXCLUDE = [0, 3, 5] response = None trans_report_name = 'transmission_0x%04x' % self.transmission_count trans_report = Report(trans_report_name) self.transmission_report = trans_report self.report.add(trans_report_name, trans_report) try: trans_report.add('request (hex)', hexlify(payload).decode()) trans_report.add('request (raw)', '%s' % payload) trans_report.add('request length', len(payload)) trans_report.add('request time', time.time()) request = hexlify(payload).decode() request = request if len(request) < 100 else (request[:100] + ' ...') self.logger.info(f"request({len(payload)}): {request}") self._send_to_target(payload) trans_report.success() if self.expect_response: try: response = self._receive_from_target() trans_report.add('response time', time.time()) trans_report.add('response (hex)', hexlify(response).decode()) trans_report.add('response (raw)', '%s' % response) trans_report.add('response length', len(response)) trans_report.add('Session ID', str(self._uuid)) printed_response = hexlify(response).decode() printed_response = printed_response if len(printed_response) < 100 else (printed_response[:100] + ' ...') self.logger.info(f"response({len(response)}): {printed_response}") server_message = response.split(b',', 0) reply = codecs.encode(server_message[0], 'hex') # USE DNS LIB TO HELP DEBUGGING MALFORMED HEADER debug_response_header = DNSBufferExt(unhexlify(reply)) parsed_dns_response_header = DNSHeader.parse(debug_response_header) dns_response_message = DNSRecordExt.parse(server_message[0]) if int(parsed_dns_response_header.rcode) not in DNS_EXCLUDE: self.logger.error(f"DNS response code: " f"{DNS_RETRUN_CODES[int(parsed_dns_response_header.rcode)]}") self.logger.error(f"Debug header: {str(parsed_dns_response_header)}") trans_report.failed(f"Failure in response, code: " f"{DNS_RETRUN_CODES[int(parsed_dns_response_header.rcode)]}") trans_report.add('Response', str(dns_response_message)) trans_report.add('traceback', traceback.format_exc()) self.receive_failure = True self.report.set_status('failed') except Exception as ex2: trans_report.failed('failed to receive response: %s' % ex2) trans_report.add('traceback', traceback.format_exc()) self.logger.error(f"target.transmit - failure in receive (exception: {ex2})") self.logger.error(traceback.format_exc()) self.receive_failure = True else: response = '' except Exception as ex1: trans_report.failed('failed to send payload: %s' % ex1) trans_report.add('traceback', traceback.format_exc()) self.logger.error(f"target.transmit - failure in send (exception: {ex1})") self.logger.error(traceback.format_exc()) self.send_failure = True self.transmission_count += 1 return response