Merge remote branch 'origin/master'
commit
23cc2bd1a1
|
@ -59,7 +59,7 @@ require 'msf/core/exploit/vim_soap'
|
||||||
require 'msf/core/exploit/wdbrpc'
|
require 'msf/core/exploit/wdbrpc'
|
||||||
require 'msf/core/exploit/wdbrpc_client'
|
require 'msf/core/exploit/wdbrpc_client'
|
||||||
require 'msf/core/exploit/afp'
|
require 'msf/core/exploit/afp'
|
||||||
|
require 'msf/core/exploit/realport'
|
||||||
|
|
||||||
# Telephony
|
# Telephony
|
||||||
require 'msf/core/exploit/dialup'
|
require 'msf/core/exploit/dialup'
|
||||||
|
|
|
@ -0,0 +1,236 @@
|
||||||
|
# -*- coding: binary -*-
|
||||||
|
|
||||||
|
require 'msf/core'
|
||||||
|
require 'msf/core/exploit/tcp'
|
||||||
|
|
||||||
|
module Msf
|
||||||
|
|
||||||
|
###
|
||||||
|
#
|
||||||
|
# This module provides methods for working with the RealPort protocol
|
||||||
|
#
|
||||||
|
###
|
||||||
|
module Exploit::Remote::RealPort
|
||||||
|
include Msf::Exploit::Remote::Tcp
|
||||||
|
|
||||||
|
#
|
||||||
|
# Initializes an instance of an auxiliary module that uses RealPort
|
||||||
|
#
|
||||||
|
|
||||||
|
def initialize(info = {})
|
||||||
|
super
|
||||||
|
register_options( [
|
||||||
|
Opt::RPORT(771)
|
||||||
|
], Msf::Exploit::Remote::RealPort )
|
||||||
|
end
|
||||||
|
|
||||||
|
@@REALPORT_BAUD_MAP = {
|
||||||
|
'2400' => "\x03\x00",
|
||||||
|
'9600' => "\x00\xc0",
|
||||||
|
'19200' => "\x00\x60",
|
||||||
|
'38400' => "\x00\x20",
|
||||||
|
'57600' => "\x00\x30",
|
||||||
|
'76800' => "\x00\x10",
|
||||||
|
'115200' => "\x00\x10", # Yup, same as above
|
||||||
|
'230400' => "\x00\x08",
|
||||||
|
'460800' => "\x00\x04",
|
||||||
|
'921600' => "\x00\x02",
|
||||||
|
}
|
||||||
|
|
||||||
|
# Connect to the RealPort service and send the initial handshake
|
||||||
|
# This has the benefit of retrieving the port count and product
|
||||||
|
# Returns true if it succeeds and nil otherwise
|
||||||
|
def realport_connect
|
||||||
|
connect
|
||||||
|
sock.put("\xfb\x01\xfb\x02\xfb\x18")
|
||||||
|
res = sock.get_once(12, 5)
|
||||||
|
return unless (res and res.length == 12)
|
||||||
|
|
||||||
|
unless res[0,2] == "\xfc\x01"
|
||||||
|
vprint_error("#{rhost}:#{rport} Bad reply: #{res.inspect}")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
len = res[2,2].unpack("n").first
|
||||||
|
return unless len > 0
|
||||||
|
|
||||||
|
res = sock.get_once(len, 5)
|
||||||
|
unless res.length == len
|
||||||
|
vprint_error("#{rhost}:#{rport} Bad length: #{res.length} wanted #{len}")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
name,info = res.split("\xfc\x02", 2)
|
||||||
|
fields = info.unpack("n*")
|
||||||
|
|
||||||
|
@realport_port_count = fields[1].to_i
|
||||||
|
@realport_name = name.gsub(/[\r\n]/, '')
|
||||||
|
|
||||||
|
# The server also sends us an additional four-byte packet we can ignore here
|
||||||
|
# This throws away a \xFC\x18\x00\x04 sequence
|
||||||
|
sock.get_once(-1, 5)
|
||||||
|
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
def realport_disconnect
|
||||||
|
disconnect
|
||||||
|
end
|
||||||
|
|
||||||
|
def realport_baud_to_speed(baud)
|
||||||
|
@@REALPORT_BAUD_MAP[baud]
|
||||||
|
end
|
||||||
|
|
||||||
|
def realport_recv_banner(port=0, timeout=30, max_data=4096)
|
||||||
|
#
|
||||||
|
# Data is received here, header is:
|
||||||
|
# a2 00 01 82 XX
|
||||||
|
# ^ [ counter ] [ length ] [ data ]
|
||||||
|
#
|
||||||
|
|
||||||
|
# Can also see f0 here (keep alive)
|
||||||
|
|
||||||
|
banner = ""
|
||||||
|
stime = Time.now.to_f
|
||||||
|
dcnt = 0
|
||||||
|
pcnt = 0
|
||||||
|
|
||||||
|
while banner.length < max_data and (Time.now.to_f - stime) < timeout
|
||||||
|
|
||||||
|
res = sock.get_once(1, 1)
|
||||||
|
unless res
|
||||||
|
if banner.length == 0 or pcnt < 3
|
||||||
|
# Send a new line to wake up the remote end
|
||||||
|
realport_send(port, "\r")
|
||||||
|
pcnt += 1
|
||||||
|
next
|
||||||
|
else
|
||||||
|
# Allow three empty reads *after* we have sent at least one probe and have data
|
||||||
|
dcnt += 1
|
||||||
|
break if dcnt > 3
|
||||||
|
next
|
||||||
|
end
|
||||||
|
end
|
||||||
|
bit = res.unpack("C").first
|
||||||
|
case bit
|
||||||
|
when (0xA0 + port)
|
||||||
|
# Read the packet sequence number (two bytes)
|
||||||
|
res = sock.get_once(2, 1)
|
||||||
|
when 0xF0
|
||||||
|
# Skip this keep-alive response
|
||||||
|
when (0x80 + port)
|
||||||
|
# Read the one-byte length value
|
||||||
|
res = sock.get_once(1, 1)
|
||||||
|
if res
|
||||||
|
len = res.unpack("C").first
|
||||||
|
res = sock.get_once(len, 1)
|
||||||
|
if res
|
||||||
|
banner << res
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
banner
|
||||||
|
end
|
||||||
|
|
||||||
|
def realport_send(port=0, data)
|
||||||
|
sock.put( [port].pack("C") + data )
|
||||||
|
end
|
||||||
|
|
||||||
|
def realport_close(port=0)
|
||||||
|
cprt = [ 0xb0 + port ].pack("C")
|
||||||
|
pkt = cprt + "\x28\x00\xc0\x00\xb0\x00\x01\x00\x00\x00\x00" + cprt + "\x0a\x03"
|
||||||
|
|
||||||
|
# Response
|
||||||
|
# b2 0b 03 00 00 02
|
||||||
|
|
||||||
|
# Send a close request
|
||||||
|
sock.put(pkt)
|
||||||
|
res = sock.get_once(-1, 5)
|
||||||
|
|
||||||
|
vprint_status("#{target_host}:#{rport} Port:#{port} Close:#{ res.inspect }")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
def realport_open(port=0, baud='9600')
|
||||||
|
|
||||||
|
@realport_banner = ''
|
||||||
|
|
||||||
|
cprt = [ 0xb0 + port ].pack("C")
|
||||||
|
aprt = [ 0xa0 + port ].pack("C")
|
||||||
|
|
||||||
|
speed = realport_baud_to_speed(baud)
|
||||||
|
|
||||||
|
# Open port
|
||||||
|
pkt1 = "\xf0" + cprt + "\x0a"+ "\x00"
|
||||||
|
|
||||||
|
# Response
|
||||||
|
# b2 0b 00 00 00 02
|
||||||
|
# ^ ^ <- port number
|
||||||
|
|
||||||
|
# Open the port
|
||||||
|
sock.put(pkt1)
|
||||||
|
res = sock.get_once(-1, 5)
|
||||||
|
|
||||||
|
vprint_status("#{target_host}:#{rport} Port:#{port} Baud:#{baud} Open:#{ res.inspect }")
|
||||||
|
|
||||||
|
# Access the port
|
||||||
|
pkt2 =
|
||||||
|
cprt + "\x0e" +
|
||||||
|
cprt + "\x2a\x02\xc0\xf3" +
|
||||||
|
cprt + "\x10" +
|
||||||
|
cprt + "\x14" +
|
||||||
|
cprt + "\x16" +
|
||||||
|
cprt + "\x2c\x03\x00\x00"
|
||||||
|
|
||||||
|
# Response (GOOD)
|
||||||
|
# b2 0f 00 00 00 00 b2 15 0f ff 0f ff b2 11 00 00
|
||||||
|
# 13 b2 17 01 02 00 2f 06 a8 00 1c 20 00 00 00 00
|
||||||
|
# 00 f3 f3 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||||
|
# 00
|
||||||
|
|
||||||
|
# Response (BAD)
|
||||||
|
# \xFF \x17 Access to unopened port\x00
|
||||||
|
|
||||||
|
# Send negotiate request
|
||||||
|
sock.put(pkt2)
|
||||||
|
res = sock.get_once(-1, 5)
|
||||||
|
if res.to_s =~ /^\xff/
|
||||||
|
vprint_status("#{target_host}:#{rport} Port:#{port} is closed: #{res.inspect}")
|
||||||
|
return :closed
|
||||||
|
end
|
||||||
|
|
||||||
|
vprint_status("#{target_host}:#{rport} Port:#{port} Baud:#{baud} Negotiate:#{ res.inspect }")
|
||||||
|
|
||||||
|
# Terminal settings
|
||||||
|
pkt3 =
|
||||||
|
cprt + "\x30\x03\xff\x00\x64" +
|
||||||
|
cprt + "\x2d\x03\xff\x0b\xff" +
|
||||||
|
cprt + "\x28" + speed + "\x04" +
|
||||||
|
cprt + "\x00\x01\x00\x00\x00\x00" +
|
||||||
|
cprt + "\x2c\x00\x12\x00" +
|
||||||
|
cprt + "\x2e\x11\x13\x16\x00\x00" +
|
||||||
|
cprt + "\x2f\x03\xff\x00\x64" +
|
||||||
|
cprt + "\x40\x37" + aprt + "\x0f\xff"
|
||||||
|
|
||||||
|
# Response
|
||||||
|
# c2 12 00 00 f0
|
||||||
|
# ^
|
||||||
|
|
||||||
|
# Send terminal settings request
|
||||||
|
sock.put(pkt3)
|
||||||
|
res = sock.get_once(-1, 5)
|
||||||
|
|
||||||
|
if res.to_s =~ /^\xff/
|
||||||
|
vprint_status("#{target_host}:#{rport} Port:#{port} is closed: #{res.inspect}")
|
||||||
|
return :closed
|
||||||
|
end
|
||||||
|
|
||||||
|
vprint_status("#{target_host}:#{rport} Port:#{port} Baud:#{baud} Settings:#{ res.inspect }")
|
||||||
|
return :open
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
end
|
|
@ -0,0 +1,93 @@
|
||||||
|
##
|
||||||
|
# $Id$
|
||||||
|
##
|
||||||
|
|
||||||
|
##
|
||||||
|
# This file is part of the Metasploit Framework and may be subject to
|
||||||
|
# redistribution and commercial restrictions. Please see the Metasploit
|
||||||
|
# web site for more information on licensing and terms of use.
|
||||||
|
# http://metasploit.com/
|
||||||
|
##
|
||||||
|
|
||||||
|
require 'msf/core'
|
||||||
|
|
||||||
|
class Metasploit3 < Msf::Auxiliary
|
||||||
|
|
||||||
|
include Msf::Exploit::Remote::RealPort
|
||||||
|
include Msf::Auxiliary::Report
|
||||||
|
include Msf::Auxiliary::Scanner
|
||||||
|
|
||||||
|
def initialize
|
||||||
|
super(
|
||||||
|
'Name' => 'Digi RealPort Serial Server Port Scanner',
|
||||||
|
'Description' => 'Identify active ports on RealPort-enabled serial servers.',
|
||||||
|
'References' =>
|
||||||
|
[
|
||||||
|
['URL', 'http://www.digi.com/pdf/fs_realport.pdf'],
|
||||||
|
['URL', 'http://www.digi.com/support/productdetail?pid=2229&type=drivers']
|
||||||
|
],
|
||||||
|
'Author' =>
|
||||||
|
[
|
||||||
|
'hdm'
|
||||||
|
],
|
||||||
|
'License' => MSF_LICENSE
|
||||||
|
)
|
||||||
|
|
||||||
|
register_options(
|
||||||
|
[
|
||||||
|
OptInt.new("BANNER_TIMEOUT", [true, "How long to capture data from the serial port", 5]),
|
||||||
|
OptString.new('BAUD_RATES', [true, "A space delimited list of baud rates to try for each port", "9600 115200"]),
|
||||||
|
OptString.new('PORTS', [true, "A space delimited list of 1-indexed serial port numbers to try, default is all supported", "ALL"])
|
||||||
|
], self.class)
|
||||||
|
end
|
||||||
|
|
||||||
|
def setup
|
||||||
|
test_speeds = datastore['BAUD_RATES'].split(/\s+/)
|
||||||
|
test_speeds.each do |baud|
|
||||||
|
valid = realport_baud_to_speed(baud)
|
||||||
|
if not valid
|
||||||
|
raise RuntimeError, "The baud rate #{baud} is not supported"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def run_host(target_host)
|
||||||
|
test_ports = datastore['PORTS'].upcase.split(/\s+/)
|
||||||
|
test_speeds = datastore['BAUD_RATES'].split(/\s+/)
|
||||||
|
|
||||||
|
return unless realport_connect
|
||||||
|
|
||||||
|
info = "#{@realport_name} ( ports: #{@realport_port_count} )"
|
||||||
|
vprint_status("#{target_host}:#{rport} is running #{info}")
|
||||||
|
report_service(:host => rhost, :port => rport, :name => "realport", :info => info)
|
||||||
|
|
||||||
|
1.upto(@realport_port_count) do |pnum|
|
||||||
|
unless test_ports.include?('ALL') or test_ports.include?(pnum.to_s)
|
||||||
|
# Skip this port
|
||||||
|
next
|
||||||
|
end
|
||||||
|
|
||||||
|
test_speeds.each do |baud|
|
||||||
|
ret = realport_open(pnum - 1, baud)
|
||||||
|
break unless ret == :open
|
||||||
|
res = realport_recv_banner(pnum - 1, datastore['BANNER_TIMEOUT'])
|
||||||
|
if res and res.length > 0
|
||||||
|
print_status("#{target_host}:#{rport} [port #{pnum} @ #{baud}bps] #{res.inspect}")
|
||||||
|
report_note(
|
||||||
|
:host => target_host,
|
||||||
|
:proto => 'tcp',
|
||||||
|
:port => rport,
|
||||||
|
:type => "realport.port#{pnum}.banner",
|
||||||
|
:data => {:baud => baud, :banner => res},
|
||||||
|
:update => :unique_data
|
||||||
|
)
|
||||||
|
|
||||||
|
end
|
||||||
|
realport_close(pnum - 1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
realport_disconnect
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -0,0 +1,45 @@
|
||||||
|
##
|
||||||
|
# $Id$
|
||||||
|
##
|
||||||
|
|
||||||
|
##
|
||||||
|
# This file is part of the Metasploit Framework and may be subject to
|
||||||
|
# redistribution and commercial restrictions. Please see the Metasploit
|
||||||
|
# web site for more information on licensing and terms of use.
|
||||||
|
# http://metasploit.com/
|
||||||
|
##
|
||||||
|
|
||||||
|
require 'msf/core'
|
||||||
|
|
||||||
|
class Metasploit3 < Msf::Auxiliary
|
||||||
|
|
||||||
|
include Msf::Exploit::Remote::RealPort
|
||||||
|
include Msf::Auxiliary::Report
|
||||||
|
include Msf::Auxiliary::Scanner
|
||||||
|
|
||||||
|
def initialize
|
||||||
|
super(
|
||||||
|
'Name' => 'Digi RealPort Serial Server Version',
|
||||||
|
'Description' => 'Detect serial servers that speak the RealPort protocol.',
|
||||||
|
'References' =>
|
||||||
|
[
|
||||||
|
['URL', 'http://www.digi.com/pdf/fs_realport.pdf'],
|
||||||
|
['URL', 'http://www.digi.com/support/productdetail?pid=2229&type=drivers']
|
||||||
|
],
|
||||||
|
'Author' =>
|
||||||
|
[
|
||||||
|
'hdm'
|
||||||
|
],
|
||||||
|
'License' => MSF_LICENSE
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def run_host(target_host)
|
||||||
|
if realport_connect
|
||||||
|
info = "#{@realport_name} ( ports: #{@realport_port_count} )"
|
||||||
|
print_status("#{target_host}:#{rport} #{info}")
|
||||||
|
report_service(:host => rhost, :port => rport, :name => "realport", :info => info)
|
||||||
|
end
|
||||||
|
realport_disconnect
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue