def run(args): """Execute wrapper using provided arguments.""" module.LogHandler.setup(msg_prefix="{} - ".format(args["RHOSTS"])) if DEPENDENCIES_MISSING: logging.error("Module dependency (requests) is missing, cannot continue") return try: cotopaxi_output = common_utils.scrap_output( main, [args["RHOSTS"], args["RPORTS"], "-P", "DTLS"] ) module.log(cotopaxi_output, "error") start_index = cotopaxi_output.find("Identified issues:") end_index = cotopaxi_output.find("Total number", start_index) if start_index < 0 or end_index < 0: raise Exception("Incorrect format of Cotopaxi response!") protocol_services = cotopaxi_output[ start_index + 2 : end_index - 1 ].splitlines()[1:] for protocol_service in protocol_services: name_start = protocol_service.find("Protocol.") name_end = protocol_service.find(":", name_start) proto_name = protocol_service[name_start + len("Protocol.") : name_end] services = protocol_service[name_end + 3 : -1].split(",") for service in services: service = service.strip(" '") service = service.split(":") service_ip = service[0] service_port = service[1].split(" ")[0] vuln_name = service[2] transport_proto = ( PROTOCOL_TESTERS[getattr(Protocol, proto_name)] .transport_protocol() .__name__ ) module.log( "Found service - host: {} port: {} proto: {} over {}".format( service_ip, service_port, proto_name, transport_proto ), "error", ) module.log( "Found vulnerability - host: {} port: {} name: {} ".format( service_ip, service_port, vuln_name ), "error", ) module.report_service( service_ip, proto=transport_proto.lower(), port=service_port, name=proto_name.lower(), ) module.report_vuln( service_ip, name=vuln_name, References="Cotopaxi docs" ) except Exception as exc: module.log("Error: {}".format(exc), "error") logging.error(traceback.format_exc()) return
def run(args): module.log('start exploit') ret, data = exploit(args['rhost'], args['username'], args['password']) if ret: module.log('Sucsessfully added user!') module.report_vuln( args['rhost'], 'Add New Administrator User', port=args['rport'], ) else: module.log('Error! {msg}'.format(msg=data))
def report_wproxy(target, response): # We don't use the response here, but if we were a banner scraper we could # print or report it module.report_vuln(target[0], 'wproxy', port=target[0])
def run(args): if dependencies_missing: module.log( "Module dependencies (gmpy2 and cryptography python libraries) missing, cannot continue", level='error') return target = (args['rhost'], int(args['rport'])) timeout = float(args['timeout']) cipher_handshake = cipher_handshakes[args['cipher_group']] module.log( "{}:{} - Scanning host for Bleichenbacher oracle".format(*target), level='debug') N, e = get_rsa_from_server(target, timeout) if not N: module.log("{}:{} - Cannot establish SSL connection: {}".format( *target, e), level='error') return modulus_bits = int(math.ceil(math.log(N, 2))) modulus_bytes = (modulus_bits + 7) // 8 module.log("{}:{} - RSA N: {}".format(*target, hex(N)), level='debug') module.log("{}:{} - RSA e: {}".format(*target, hex(e)), level='debug') module.log("{}:{} - Modulus size: {} bits, {} bytes".format( *target, modulus_bits, modulus_bytes), level='debug') cke_2nd_prefix = bytearray.fromhex( "{0:0{1}x}".format(modulus_bytes + 6, 4) + "10" + "{0:0{1}x}".format(modulus_bytes + 2, 6) + "{0:0{1}x}".format(modulus_bytes, 4)) # pad_len is length in hex chars, so bytelen * 2 pad_len = (modulus_bytes - 48 - 3) * 2 rnd_pad = ("abcd" * (pad_len // 2 + 1))[:pad_len] rnd_pms = "aa112233445566778899112233445566778899112233445566778899112233445566778899112233445566778899" pms_good_in = int("0002" + rnd_pad + "00" + "0303" + rnd_pms, 16) # wrong first two bytes pms_bad_in1 = int("4117" + rnd_pad + "00" + "0303" + rnd_pms, 16) # 0x00 on a wrong position, also trigger older JSSE bug pms_bad_in2 = int("0002" + rnd_pad + "11" + rnd_pms + "0011", 16) # no 0x00 in the middle pms_bad_in3 = int("0002" + rnd_pad + "11" + "1111" + rnd_pms, 16) # wrong version number (according to Klima / Pokorny / Rosa paper) pms_bad_in4 = int("0002" + rnd_pad + "00" + "0202" + rnd_pms, 16) pms_good = int(gmpy2.powmod(pms_good_in, e, N)).to_bytes(modulus_bytes, byteorder="big") pms_bad1 = int(gmpy2.powmod(pms_bad_in1, e, N)).to_bytes(modulus_bytes, byteorder="big") pms_bad2 = int(gmpy2.powmod(pms_bad_in2, e, N)).to_bytes(modulus_bytes, byteorder="big") pms_bad3 = int(gmpy2.powmod(pms_bad_in3, e, N)).to_bytes(modulus_bytes, byteorder="big") pms_bad4 = int(gmpy2.powmod(pms_bad_in4, e, N)).to_bytes(modulus_bytes, byteorder="big") oracle_good = oracle(target, pms_good, cke_2nd_prefix, cipher_handshake, messageflow=False, timeout=timeout) oracle_bad1 = oracle(target, pms_bad1, cke_2nd_prefix, cipher_handshake, messageflow=False, timeout=timeout) oracle_bad2 = oracle(target, pms_bad2, cke_2nd_prefix, cipher_handshake, messageflow=False, timeout=timeout) oracle_bad3 = oracle(target, pms_bad3, cke_2nd_prefix, cipher_handshake, messageflow=False, timeout=timeout) oracle_bad4 = oracle(target, pms_bad4, cke_2nd_prefix, cipher_handshake, messageflow=False, timeout=timeout) if (oracle_good == oracle_bad1 == oracle_bad2 == oracle_bad3 == oracle_bad4): module.log( "{}:{} - Identical results ({}), retrying with changed messageflow" .format(*target, oracle_good), level='info') oracle_good = oracle(target, pms_good, cke_2nd_prefix, cipher_handshake, messageflow=True, timeout=timeout) oracle_bad1 = oracle(target, pms_bad1, cke_2nd_prefix, cipher_handshake, messageflow=True, timeout=timeout) oracle_bad2 = oracle(target, pms_bad2, cke_2nd_prefix, cipher_handshake, messageflow=True, timeout=timeout) oracle_bad3 = oracle(target, pms_bad3, cke_2nd_prefix, cipher_handshake, messageflow=True, timeout=timeout) oracle_bad4 = oracle(target, pms_bad4, cke_2nd_prefix, cipher_handshake, messageflow=True, timeout=timeout) if (oracle_good == oracle_bad1 == oracle_bad2 == oracle_bad3 == oracle_bad4): module.log( "{}:{} - Identical results ({}), no working oracle found". format(*target, oracle_good), level='info') return else: flow = True else: flow = False # Re-checking all oracles to avoid unreliable results oracle_good_verify = oracle(target, pms_good, cke_2nd_prefix, cipher_handshake, messageflow=flow, timeout=timeout) oracle_bad_verify1 = oracle(target, pms_bad1, cke_2nd_prefix, cipher_handshake, messageflow=flow, timeout=timeout) oracle_bad_verify2 = oracle(target, pms_bad2, cke_2nd_prefix, cipher_handshake, messageflow=flow, timeout=timeout) oracle_bad_verify3 = oracle(target, pms_bad3, cke_2nd_prefix, cipher_handshake, messageflow=flow, timeout=timeout) oracle_bad_verify4 = oracle(target, pms_bad4, cke_2nd_prefix, cipher_handshake, messageflow=flow, timeout=timeout) if (oracle_good != oracle_good_verify) or (oracle_bad1 != oracle_bad_verify1) or ( oracle_bad2 != oracle_bad_verify2) or ( oracle_bad3 != oracle_bad_verify3) or (oracle_bad4 != oracle_bad_verify4): module.log( "{}:{} - Getting inconsistent results, skipping".format(*target), level='warning') return # If the response to the invalid PKCS#1 request (oracle_bad1) is equal to both # requests starting with 0002, we have a weak oracle. This is because the only # case where we can distinguish valid from invalid requests is when we send # correctly formatted PKCS#1 message with 0x00 on a correct position. This # makes our oracle weak if (oracle_bad1 == oracle_bad2 == oracle_bad3): oracle_strength = "weak" else: oracle_strength = "strong" if flow: flowt = "shortened" else: flowt = "standard" s, cke_version = tls_connect(target, timeout, cipher_handshake) s.close() if cke_version[0] == 3 and cke_version[1] == 0: tlsver = "SSLv3" elif cke_version[0] == 3 and cke_version[1] == 1: tlsver = "TLSv1.0" elif cke_version[0] == 3 and cke_version[1] == 2: tlsver = "TLSv1.1" elif cke_version[0] == 3 and cke_version[1] == 3: tlsver = "TLSv1.2" else: tlsver = "TLS raw version %i/%i" % (cke_version[0], cke_version[1]) module.report_vuln(target[0], 'Bleichenbacher Oracle', port=target[1]) module.log( "{}:{} - Vulnerable: ({}) oracle found {} with {} message flow".format( *target, oracle_strength, tlsver, flowt), level='good') module.log( "{}:{} - Result of good request: {}".format( *target, oracle_good), level='debug') module.log( "{}:{} - Result of bad request 1 (wrong first bytes): {}".format( *target, oracle_bad1), level='debug') module.log( "{}:{} - Result of bad request 2 (wrong 0x00 position): {}".format( *target, oracle_bad2), level='debug') module.log( "{}:{} - Result of bad request 3 (missing 0x00): {}".format( *target, oracle_bad3), level='debug') module.log( "{}:{} - Result of bad request 4 (bad TLS version): {}".format( *target, oracle_bad4), level='debug')
def run(args): if dependencies_missing: module.log("Module dependencies (gmpy2 and cryptography python libraries) missing, cannot continue", level='error') return target = (args['rhost'], int(args['rport'])) timeout = float(args['timeout']) cipher_handshake = cipher_handshakes[args['cipher_group']] module.log("{}:{} - Scanning host for Bleichenbacher oracle".format(*target), level='debug') N, e = get_rsa_from_server(target, timeout) if not N: module.log("{}:{} - Cannot establish SSL connection: {}".format(*target, e), level='error') return modulus_bits = int(math.ceil(math.log(N, 2))) modulus_bytes = (modulus_bits + 7) // 8 module.log("{}:{} - RSA N: {}".format(*target, hex(N)), level='debug') module.log("{}:{} - RSA e: {}".format(*target, hex(e)), level='debug') module.log("{}:{} - Modulus size: {} bits, {} bytes".format(*target, modulus_bits, modulus_bytes), level='debug') cke_2nd_prefix = bytearray.fromhex("{0:0{1}x}".format(modulus_bytes + 6, 4) + "10" + "{0:0{1}x}".format(modulus_bytes + 2, 6) + "{0:0{1}x}".format(modulus_bytes, 4)) # pad_len is length in hex chars, so bytelen * 2 pad_len = (modulus_bytes - 48 - 3) * 2 rnd_pad = ("abcd" * (pad_len // 2 + 1))[:pad_len] rnd_pms = "aa112233445566778899112233445566778899112233445566778899112233445566778899112233445566778899" pms_good_in = int("0002" + rnd_pad + "00" + "0303" + rnd_pms, 16) # wrong first two bytes pms_bad_in1 = int("4117" + rnd_pad + "00" + "0303" + rnd_pms, 16) # 0x00 on a wrong position, also trigger older JSSE bug pms_bad_in2 = int("0002" + rnd_pad + "11" + rnd_pms + "0011", 16) # no 0x00 in the middle pms_bad_in3 = int("0002" + rnd_pad + "11" + "1111" + rnd_pms, 16) # wrong version number (according to Klima / Pokorny / Rosa paper) pms_bad_in4 = int("0002" + rnd_pad + "00" + "0202" + rnd_pms, 16) pms_good = int(gmpy2.powmod(pms_good_in, e, N)).to_bytes(modulus_bytes, byteorder="big") pms_bad1 = int(gmpy2.powmod(pms_bad_in1, e, N)).to_bytes(modulus_bytes, byteorder="big") pms_bad2 = int(gmpy2.powmod(pms_bad_in2, e, N)).to_bytes(modulus_bytes, byteorder="big") pms_bad3 = int(gmpy2.powmod(pms_bad_in3, e, N)).to_bytes(modulus_bytes, byteorder="big") pms_bad4 = int(gmpy2.powmod(pms_bad_in4, e, N)).to_bytes(modulus_bytes, byteorder="big") oracle_good = oracle(target, pms_good, cke_2nd_prefix, cipher_handshake, messageflow=False, timeout=timeout) oracle_bad1 = oracle(target, pms_bad1, cke_2nd_prefix, cipher_handshake, messageflow=False, timeout=timeout) oracle_bad2 = oracle(target, pms_bad2, cke_2nd_prefix, cipher_handshake, messageflow=False, timeout=timeout) oracle_bad3 = oracle(target, pms_bad3, cke_2nd_prefix, cipher_handshake, messageflow=False, timeout=timeout) oracle_bad4 = oracle(target, pms_bad4, cke_2nd_prefix, cipher_handshake, messageflow=False, timeout=timeout) if (oracle_good == oracle_bad1 == oracle_bad2 == oracle_bad3 == oracle_bad4): module.log("{}:{} - Identical results ({}), retrying with changed messageflow".format(*target, oracle_good), level='info') oracle_good = oracle(target, pms_good, cke_2nd_prefix, cipher_handshake, messageflow=True, timeout=timeout) oracle_bad1 = oracle(target, pms_bad1, cke_2nd_prefix, cipher_handshake, messageflow=True, timeout=timeout) oracle_bad2 = oracle(target, pms_bad2, cke_2nd_prefix, cipher_handshake, messageflow=True, timeout=timeout) oracle_bad3 = oracle(target, pms_bad3, cke_2nd_prefix, cipher_handshake, messageflow=True, timeout=timeout) oracle_bad4 = oracle(target, pms_bad4, cke_2nd_prefix, cipher_handshake, messageflow=True, timeout=timeout) if (oracle_good == oracle_bad1 == oracle_bad2 == oracle_bad3 == oracle_bad4): module.log("{}:{} - Identical results ({}), no working oracle found".format(*target, oracle_good), level='info') return else: flow = True else: flow = False # Re-checking all oracles to avoid unreliable results oracle_good_verify = oracle(target, pms_good, cke_2nd_prefix, cipher_handshake, messageflow=flow, timeout=timeout) oracle_bad_verify1 = oracle(target, pms_bad1, cke_2nd_prefix, cipher_handshake, messageflow=flow, timeout=timeout) oracle_bad_verify2 = oracle(target, pms_bad2, cke_2nd_prefix, cipher_handshake, messageflow=flow, timeout=timeout) oracle_bad_verify3 = oracle(target, pms_bad3, cke_2nd_prefix, cipher_handshake, messageflow=flow, timeout=timeout) oracle_bad_verify4 = oracle(target, pms_bad4, cke_2nd_prefix, cipher_handshake, messageflow=flow, timeout=timeout) if (oracle_good != oracle_good_verify) or (oracle_bad1 != oracle_bad_verify1) or (oracle_bad2 != oracle_bad_verify2) or (oracle_bad3 != oracle_bad_verify3) or (oracle_bad4 != oracle_bad_verify4): module.log("{}:{} - Getting inconsistent results, skipping".format(*target), level='warning') return # If the response to the invalid PKCS#1 request (oracle_bad1) is equal to both # requests starting with 0002, we have a weak oracle. This is because the only # case where we can distinguish valid from invalid requests is when we send # correctly formatted PKCS#1 message with 0x00 on a correct position. This # makes our oracle weak if (oracle_bad1 == oracle_bad2 == oracle_bad3): oracle_strength = "weak" else: oracle_strength = "strong" if flow: flowt = "shortened" else: flowt = "standard" s, cke_version = tls_connect(target, timeout, cipher_handshake) s.close() if cke_version[0] == 3 and cke_version[1] == 0: tlsver = "SSLv3" elif cke_version[0] == 3 and cke_version[1] == 1: tlsver = "TLSv1.0" elif cke_version[0] == 3 and cke_version[1] == 2: tlsver = "TLSv1.1" elif cke_version[0] == 3 and cke_version[1] == 3: tlsver = "TLSv1.2" else: tlsver = "TLS raw version %i/%i" % (cke_version[0], cke_version[1]) module.report_vuln(target[0], 'Bleichenbacher Oracle', port=target[1]) module.log("{}:{} - Vulnerable: ({}) oracle found {} with {} message flow".format(*target, oracle_strength, tlsver, flowt), level='good') module.log("{}:{} - Result of good request: {}".format(*target, oracle_good), level='debug') module.log("{}:{} - Result of bad request 1 (wrong first bytes): {}".format(*target, oracle_bad1), level='debug') module.log("{}:{} - Result of bad request 2 (wrong 0x00 position): {}".format(*target, oracle_bad2), level='debug') module.log("{}:{} - Result of bad request 3 (missing 0x00): {}".format(*target, oracle_bad3), level='debug') module.log("{}:{} - Result of bad request 4 (bad TLS version): {}".format(*target, oracle_bad4), level='debug')
def run(args): """Execute wrapper using provided arguments.""" module.LogHandler.setup(msg_prefix="{} - ".format(args["RHOSTS"])) if DEPENDENCIES_MISSING: logging.error( "Module dependency (requests) is missing, cannot continue") return try: parameters = [ args["RHOSTS"], args["RPORTS"], "-V", "-P", MODULE_PROTOCOL ] if "true" == args["IGNORE_PING_CHECK"]: parameters += ["--ignore-ping-check"] if args["PATH_CORPUS"].strip(): parameters += ["-C", args["PATH_CORPUS"]] cotopaxi_output = common_utils.scrap_output(main, parameters) module.log(cotopaxi_output, "error") start_index = cotopaxi_output.find("Payloads causing crash:") end_index = cotopaxi_output.find("Total number", start_index) if start_index < 0 or end_index < 0: raise Exception("Incorrect format of Cotopaxi response!") protocol_services = cotopaxi_output[start_index + 2:end_index - 1].splitlines()[1:] for protocol_service in protocol_services: name_start = protocol_service.find("Protocol.") name_end = protocol_service.find(":", name_start) proto_name = protocol_service[name_start + len("Protocol."):name_end] services = protocol_service[name_end + 3:-1].split(",") for service in services: service = service.strip(" '") service = service.split(":") service_ip = service[0] service_port = service[1].split(" ")[0] payload = service[2] transport_proto = (PROTOCOL_TESTERS[getattr( Protocol, proto_name)].transport_protocol().__name__) module.log( "Found service - host: {} port: {} proto: {} over {} using {}" .format( service_ip, service_port, proto_name, transport_proto, MODULE_PROTOCOL.lower(), ), "error", ) module.report_service( service_ip, proto=transport_proto.lower(), port=service_port, name=proto_name.lower(), # info="Server: " + service_name, ) module.log( "Found vulnerability - host: {} port: {} name: crash after payload: {} " .format(service_ip, service_port, payload), "error", ) module.report_vuln( service_ip, name="Fuzzer crash - payload {}".format(payload), References="Cotopaxi docs", ) except Exception as exc: module.log("Error: {}".format(exc), "error") logging.error(traceback.format_exc()) return