248 lines
4.8 KiB
Ruby
248 lines
4.8 KiB
Ruby
# -*- coding: binary -*-
|
|
require 'msf/core'
|
|
|
|
module Msf
|
|
|
|
###
|
|
#
|
|
# This module exposes methods for manipulating the WDRPC service
|
|
#
|
|
###
|
|
module Exploit::Remote::WDBRPC
|
|
|
|
# WDB_TARGET_CONNECT2
|
|
def wdbrpc_request_connect2(ip)
|
|
ip += "\x00"
|
|
while(ip.length % 4 != 0)
|
|
ip << "\x00"
|
|
end
|
|
|
|
data = [
|
|
0x00000002,
|
|
0x00000000,
|
|
0x00000000,
|
|
0x00000001,
|
|
ip.length
|
|
].pack("N*") + ip
|
|
|
|
wdbrpc_request(0x7a, data)
|
|
end
|
|
|
|
# WDB_TARGET_CONNECT
|
|
def wdbrpc_request_connect(ip)
|
|
data = [ 0x00000002, 0x00000000, 0x00000000 ].pack("N*")
|
|
wdbrpc_request(1, data)
|
|
end
|
|
|
|
# WDB_TARGET_DISCONNECT
|
|
def wdbrpc_request_disconnect
|
|
data = [ 0x00000002, 0x00000000, 0x00000000 ].pack("N*")
|
|
wdbrpc_request(2, data)
|
|
end
|
|
|
|
def wdbrpc_request_regread(regset=0, offset=0, length=512, params=0)
|
|
data = [ regset ].pack("N")
|
|
|
|
# WDB_CTX
|
|
data << [
|
|
0, # WDB_CTX_SYSTEM (3 for task)
|
|
0, # SYSTEM (or set for task)
|
|
].pack("N*")
|
|
|
|
# WDB_MEM_REGION
|
|
data << [
|
|
offset, # baseAddress
|
|
length, # numberOfBytes
|
|
params, # params
|
|
].pack("N*")
|
|
|
|
wdbrpc_request(40, data)
|
|
end
|
|
|
|
|
|
def wdbrpc_request_memread(offset=0, length=512, params=0)
|
|
|
|
# WDB_MEM_REGION
|
|
data = [
|
|
offset, # baseAddress
|
|
length, # numberOfBytes
|
|
params, # params
|
|
].pack("N*")
|
|
|
|
wdbrpc_request(10, data)
|
|
end
|
|
|
|
def wdbrpc_request_memwrite(offset=0, buff='', params=0)
|
|
|
|
# Make sure its DWORD aligned
|
|
while(buff.length % 4 != 0)
|
|
buff << "\x00"
|
|
end
|
|
|
|
# WDB_MEM_XFER
|
|
data = [
|
|
buff.length,
|
|
offset, # target
|
|
buff.length
|
|
].pack("N*") + buff
|
|
|
|
wdbrpc_request(11, data)
|
|
end
|
|
|
|
|
|
def wdbrpc_request_memscan(offset=0, depth=1024, buff='', params=0)
|
|
# Make sure its DWORD aligned
|
|
while(buff.length % 4 != 0)
|
|
buff << "\x00"
|
|
end
|
|
|
|
# WDB_MEM_REGION
|
|
data = [
|
|
offset, # baseAddress
|
|
depth, # numberOfBytes
|
|
params, # params
|
|
].pack("N*")
|
|
|
|
# WDB_MEM_XFER
|
|
data << [
|
|
buff.length,
|
|
0,
|
|
buff.length
|
|
].pack("N*") + buff
|
|
|
|
wdbrpc_request(11, data)
|
|
end
|
|
|
|
def wdbrpc_request_context_kill(ctx_type, ctx)
|
|
|
|
# WDB_CTX
|
|
data = [
|
|
ctx_type, # WDB_CTX_SYSTEM (3 for task)
|
|
ctx, # SYSTEM (or set for task)
|
|
].pack("N*")
|
|
|
|
# options
|
|
data << [ 0 ] .pack("N")
|
|
|
|
wdbrpc_request(31, data)
|
|
end
|
|
|
|
def wdbrpc_parse_connect_reply(buff)
|
|
info = {}
|
|
head = buff.slice!(0,36)
|
|
info[:agent_ver] = wdbrpc_decode_str(buff)
|
|
info[:agent_mtu] = wdbrpc_decode_int(buff)
|
|
info[:agent_mod] = wdbrpc_decode_int(buff)
|
|
info[:rt_type] = wdbrpc_decode_int(buff)
|
|
info[:rt_vers] = wdbrpc_decode_str(buff)
|
|
info[:rt_cpu_type] = wdbrpc_decode_int(buff)
|
|
info[:rt_has_fpp] = wdbrpc_decode_bool(buff)
|
|
info[:rt_has_wp] = wdbrpc_decode_bool(buff)
|
|
info[:rt_page_size] = wdbrpc_decode_int(buff)
|
|
info[:rt_endian] = wdbrpc_decode_int(buff)
|
|
info[:rt_bsp_name] = wdbrpc_decode_str(buff)
|
|
info[:rt_bootline] = wdbrpc_decode_str(buff)
|
|
info[:rt_membase] = wdbrpc_decode_int(buff)
|
|
info[:rt_memsize] = wdbrpc_decode_int(buff)
|
|
info[:rt_region_count] = wdbrpc_decode_int(buff)
|
|
info[:rt_regions] = wdbrpc_decode_arr(buff, :int)
|
|
info[:rt_hostpool_base] = wdbrpc_decode_int(buff)
|
|
info[:rt_hostpool_size] = wdbrpc_decode_int(buff)
|
|
info
|
|
end
|
|
|
|
def wdbrpc_request(procedure, data)
|
|
pkt =
|
|
[
|
|
0x00000000, # XID (ignored by checksum and length)
|
|
0x00000000,
|
|
0x00000002,
|
|
0x55555555, # Program
|
|
0x00000001, # Version
|
|
procedure, # Procedure
|
|
0x00000000,
|
|
0x00000000,
|
|
0x00000000,
|
|
0x00000000
|
|
].pack("N*")
|
|
|
|
pkt +=
|
|
[
|
|
0x00000000, # Checksum
|
|
0x00000000, # Packet Size
|
|
wdbrpc_request_seqno
|
|
].pack("N*")
|
|
|
|
pkt += data
|
|
|
|
# Length excludes the XID
|
|
pkt[44, 4] = [ pkt.length - 4].pack("N")
|
|
|
|
# Set the checksum flag and calculate the checksum
|
|
pkt[42, 2] = [ wdbrpc_checksum(pkt) ].pack("n")
|
|
pkt[40, 2] = [0xffff].pack("n")
|
|
|
|
# Set the RPC XID
|
|
pkt[ 0, 4] = [ rand(0x100000000) ].pack("N")
|
|
|
|
pkt
|
|
end
|
|
|
|
def wdbrpc_request_seqno
|
|
@wdbrpc_seqno ||= 0
|
|
@wdbrpc_seqno += 1
|
|
end
|
|
|
|
def wdbrpc_checksum(data)
|
|
sum = 0
|
|
data.unpack("n*").each {|c| sum += c }
|
|
sum = (sum & 0xffff) + (sum >> 16)
|
|
(~sum)
|
|
end
|
|
|
|
def wdbrpc_decode_str(data)
|
|
return if data.length < 4
|
|
slen = data.slice!(0,4).unpack("N")[0]
|
|
return "" if slen == 0
|
|
while (slen % 4 != 0)
|
|
slen += 1
|
|
end
|
|
|
|
data.slice!(0,slen).to_s.split("\x00")[0]
|
|
end
|
|
|
|
def wdbrpc_decode_int(data)
|
|
return if data.length < 4
|
|
data.slice!(0,4).unpack("N")[0]
|
|
end
|
|
|
|
def wdbrpc_decode_arr(data, dtype)
|
|
return if data.length < 4
|
|
res = []
|
|
|
|
alen = data.slice!(0,4).unpack("N")[0]
|
|
return res if alen == 0
|
|
|
|
1.upto(alen) do |idx|
|
|
case dtype
|
|
when :int
|
|
res << wdbrpc_decode_int(data)
|
|
when :str
|
|
res << wdbrpc_decode_str(data)
|
|
when :bool
|
|
res << wdbrpc_decode_bool(data)
|
|
end
|
|
end
|
|
|
|
res
|
|
end
|
|
|
|
def wdbrpc_decode_bool(data)
|
|
return if data.length < 4
|
|
(data.slice!(0,4).unpack("N")[0] == 0) ? false : true
|
|
end
|
|
|
|
end
|
|
end
|
|
|