Module: Msf::Exploit::Remote::Gdb
- Includes:
- Tcp
- Defined in:
- lib/msf/core/exploit/remote/gdb.rb
Overview
Implement some helpers for communicating with a remote gdb instance.
More info on the gdb protocol can be found here: sourceware.org/gdb/current/onlinedocs/gdb/Overview.html#Overview
Defined Under Namespace
Classes: BadAckError, BadChecksumError, BadResponseError
Constant Summary collapse
- GDB_FEATURES =
Default list of supported GDB features to send them to the target
'qSupported:multiprocess+;qRelocInsn+;qvCont+;'
- PC_REGISTERS =
Maps index of register in GDB that holds $PC to architecture
{ '08' => ARCH_X86, '0f' => ARCH_ARMLE, '10' => ARCH_X64, '20' => ARCH_AARCH64 }
Instance Attribute Summary
Attributes included from Tcp
Instance Method Summary collapse
-
#checksum(str) ⇒ String
The two-digit checksum is computed as the modulo 256 sum of all characters between the leading ???$??? and the trailing ???#??? (an eight bit unsigned checksum).
-
#continue(opts = {}) ⇒ Object
Continues execution of the remote process.
-
#decode_rle(msg) ⇒ String
Implements decoding of gdbserver’s Run-Length-Encoding that is applied on some hex values to collapse repeated characters.
-
#detach(opts = {}) ⇒ Object
Detaches from the remote process.
- #enable_extended_mode ⇒ Object
-
#handshake(features = GDB_FEATURES) ⇒ Object
Performs a handshake packet exchange.
-
#process_info ⇒ Hash
Steps execution and finds $PC pointer and architecture.
-
#read_ack ⇒ Object
Reads an ACK packet from the wire.
-
#read_response(opts = {}) ⇒ String
Reads (and possibly decodes) from the socket and sends an ACK to verify receipt.
- #run_file(filename) ⇒ Object
-
#send_ack ⇒ Object
Send an ACK packet.
-
#send_cmd(cmd) ⇒ Object
Sends a command and receives an ACK from the remote.
-
#step ⇒ String
Executes one instruction on the remote process.
-
#verify_checksum(res) ⇒ Boolean
Verifies a response’s checksum.
-
#write(buf, addr) ⇒ Object
Writes the buffer
buf
to the addressaddr
in the remote process’s memory.
Methods included from Tcp
#chost, #cleanup, #connect, #connect_timeout, #cport, #disconnect, #handler, #initialize, #lhost, #lport, #peer, #print_prefix, #proxies, #rhost, #rport, #set_tcp_evasions, #shutdown, #ssl, #ssl_cipher, #ssl_verify_mode, #ssl_version
Instance Method Details
#checksum(str) ⇒ String
The two-digit checksum is computed as the modulo 256 sum of all characters between the leading ???$??? and the trailing ???#??? (an eight bit unsigned checksum).
98 99 100 |
# File 'lib/msf/core/exploit/remote/gdb.rb', line 98 def checksum(str) "%02x" % str.bytes.inject(0) { |b, sum| (sum+b)%256 } end |
#continue(opts = {}) ⇒ Object
Continues execution of the remote process
144 145 146 147 |
# File 'lib/msf/core/exploit/remote/gdb.rb', line 144 def continue(opts={}) send_cmd 'vCont;c' read_response if opts.fetch(:read, true) end |
#decode_rle(msg) ⇒ String
Implements decoding of gdbserver’s Run-Length-Encoding that is applied on some hex values to collapse repeated characters.
sourceware.org/gdb/current/onlinedocs/gdb/Overview.html#Binary-Data
87 88 89 90 91 92 |
# File 'lib/msf/core/exploit/remote/gdb.rb', line 87 def decode_rle(msg) vprint_status "Before decoding: #{msg}" msg.gsub /.\*./ do |match| match.bytes.to_a.first.chr * (match.bytes.to_a.last - 29 + 1) end end |
#detach(opts = {}) ⇒ Object
Detaches from the remote process
152 153 154 155 |
# File 'lib/msf/core/exploit/remote/gdb.rb', line 152 def detach(opts={}) send_cmd 'D' read_response if opts.fetch(:read, true) end |
#enable_extended_mode ⇒ Object
176 177 178 179 |
# File 'lib/msf/core/exploit/remote/gdb.rb', line 176 def enable_extended_mode send_cmd("!") read_response end |
#handshake(features = GDB_FEATURES) ⇒ Object
Performs a handshake packet exchange
184 185 186 187 |
# File 'lib/msf/core/exploit/remote/gdb.rb', line 184 def handshake(features=GDB_FEATURES) send_cmd features read_response # lots of flags, nothing interesting end |
#process_info ⇒ Hash
Steps execution and finds $PC pointer and architecture
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
# File 'lib/msf/core/exploit/remote/gdb.rb', line 122 def process_info data = step 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] if my_arch.nil? raise RuntimeError, "Could not detect a supported arch from response to step:\n#{pc_data}" end { arch: my_arch, pc: Rex::Text.to_hex(Rex::Arch.pack_addr(my_arch, Integer(pc, 16)), ''), pc_raw: Integer(pc, 16) } end |
#read_ack ⇒ Object
Reads an ACK packet from the wire
45 46 47 48 49 50 |
# File 'lib/msf/core/exploit/remote/gdb.rb', line 45 def read_ack unless sock.get_once(1) == '+' raise BadAckError end vprint_status('Received ack...') end |
#read_response(opts = {}) ⇒ String
Reads (and possibly decodes) from the socket and sends an ACK to verify receipt
69 70 71 72 73 74 75 76 77 78 |
# File 'lib/msf/core/exploit/remote/gdb.rb', line 69 def read_response(opts={}) decode, verify = opts.fetch(:decode, false), opts.fetch(:verify, true) res = sock.get_once raise BadResponseError if res.nil? raise BadChecksumError if (verify && !verify_checksum(res)) res = decode_rle(res) if decode vprint_status('Result: '+res) send_ack res end |
#run_file(filename) ⇒ Object
171 172 173 174 |
# File 'lib/msf/core/exploit/remote/gdb.rb', line 171 def run_file(filename) send_cmd "vRun;#{Rex::Text.to_hex(filename, '')}" read_response end |
#send_ack ⇒ Object
Send an ACK packet
38 39 40 41 |
# File 'lib/msf/core/exploit/remote/gdb.rb', line 38 def send_ack sock.put('+') vprint_status('Sending ack...') end |
#send_cmd(cmd) ⇒ Object
Sends a command and receives an ACK from the remote.
55 56 57 58 59 60 |
# File 'lib/msf/core/exploit/remote/gdb.rb', line 55 def send_cmd(cmd) full_cmd = '$' + cmd + '#' + checksum(cmd) vprint_status('Sending cmd: '+full_cmd) sock.put(full_cmd) read_ack end |
#step ⇒ String
Executes one instruction on the remote process
The results of running “step” will look like: x86: $T0505:00000000;04:a0f7ffbf;08:d2f0fdb7;thread:p2d39.2d39;core:0;#53 x64: $T0506:0000000000000000;07:b0587f9fff7f0000;10:d3e29d03057f0000;thread:p8bf9.8bf9;core:0;#df The third comma-separated field will contain EIP, and the register index will let us deduce the remote architecture (through PC_REGISTERS lookup)
166 167 168 169 |
# File 'lib/msf/core/exploit/remote/gdb.rb', line 166 def step send_cmd 'vCont;s' read_response(decode: true) end |
#verify_checksum(res) ⇒ Boolean
Verifies a response’s checksum
105 106 107 108 |
# File 'lib/msf/core/exploit/remote/gdb.rb', line 105 def verify_checksum(res) msg, chksum = res.match(/^\$(.*)#(\h{2})$/)[1..2] checksum(msg) == chksum end |
#write(buf, addr) ⇒ Object
Writes the buffer buf
to the address addr
in the remote process’s memory
113 114 115 116 117 |
# File 'lib/msf/core/exploit/remote/gdb.rb', line 113 def write(buf, addr) hex = Rex::Text.to_hex(buf, '') send_cmd "M#{addr},#{buf.length.to_s(16)}:#{hex}" read_response end |