Skip to content

Commit 23cc2bd

Browse files
committed
Merge remote branch 'origin/master'
2 parents 6a4d398 + 0f5f5f9 commit 23cc2bd

File tree

4 files changed

+375
-1
lines changed

4 files changed

+375
-1
lines changed

lib/msf/core/exploit/mixins.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@
5959
require 'msf/core/exploit/wdbrpc'
6060
require 'msf/core/exploit/wdbrpc_client'
6161
require 'msf/core/exploit/afp'
62-
62+
require 'msf/core/exploit/realport'
6363

6464
# Telephony
6565
require 'msf/core/exploit/dialup'

lib/msf/core/exploit/realport.rb

Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
# -*- coding: binary -*-
2+
3+
require 'msf/core'
4+
require 'msf/core/exploit/tcp'
5+
6+
module Msf
7+
8+
###
9+
#
10+
# This module provides methods for working with the RealPort protocol
11+
#
12+
###
13+
module Exploit::Remote::RealPort
14+
include Msf::Exploit::Remote::Tcp
15+
16+
#
17+
# Initializes an instance of an auxiliary module that uses RealPort
18+
#
19+
20+
def initialize(info = {})
21+
super
22+
register_options( [
23+
Opt::RPORT(771)
24+
], Msf::Exploit::Remote::RealPort )
25+
end
26+
27+
@@REALPORT_BAUD_MAP = {
28+
'2400' => "\x03\x00",
29+
'9600' => "\x00\xc0",
30+
'19200' => "\x00\x60",
31+
'38400' => "\x00\x20",
32+
'57600' => "\x00\x30",
33+
'76800' => "\x00\x10",
34+
'115200' => "\x00\x10", # Yup, same as above
35+
'230400' => "\x00\x08",
36+
'460800' => "\x00\x04",
37+
'921600' => "\x00\x02",
38+
}
39+
40+
# Connect to the RealPort service and send the initial handshake
41+
# This has the benefit of retrieving the port count and product
42+
# Returns true if it succeeds and nil otherwise
43+
def realport_connect
44+
connect
45+
sock.put("\xfb\x01\xfb\x02\xfb\x18")
46+
res = sock.get_once(12, 5)
47+
return unless (res and res.length == 12)
48+
49+
unless res[0,2] == "\xfc\x01"
50+
vprint_error("#{rhost}:#{rport} Bad reply: #{res.inspect}")
51+
return
52+
end
53+
54+
len = res[2,2].unpack("n").first
55+
return unless len > 0
56+
57+
res = sock.get_once(len, 5)
58+
unless res.length == len
59+
vprint_error("#{rhost}:#{rport} Bad length: #{res.length} wanted #{len}")
60+
return
61+
end
62+
63+
name,info = res.split("\xfc\x02", 2)
64+
fields = info.unpack("n*")
65+
66+
@realport_port_count = fields[1].to_i
67+
@realport_name = name.gsub(/[\r\n]/, '')
68+
69+
# The server also sends us an additional four-byte packet we can ignore here
70+
# This throws away a \xFC\x18\x00\x04 sequence
71+
sock.get_once(-1, 5)
72+
73+
return true
74+
end
75+
76+
def realport_disconnect
77+
disconnect
78+
end
79+
80+
def realport_baud_to_speed(baud)
81+
@@REALPORT_BAUD_MAP[baud]
82+
end
83+
84+
def realport_recv_banner(port=0, timeout=30, max_data=4096)
85+
#
86+
# Data is received here, header is:
87+
# a2 00 01 82 XX
88+
# ^ [ counter ] [ length ] [ data ]
89+
#
90+
91+
# Can also see f0 here (keep alive)
92+
93+
banner = ""
94+
stime = Time.now.to_f
95+
dcnt = 0
96+
pcnt = 0
97+
98+
while banner.length < max_data and (Time.now.to_f - stime) < timeout
99+
100+
res = sock.get_once(1, 1)
101+
unless res
102+
if banner.length == 0 or pcnt < 3
103+
# Send a new line to wake up the remote end
104+
realport_send(port, "\r")
105+
pcnt += 1
106+
next
107+
else
108+
# Allow three empty reads *after* we have sent at least one probe and have data
109+
dcnt += 1
110+
break if dcnt > 3
111+
next
112+
end
113+
end
114+
bit = res.unpack("C").first
115+
case bit
116+
when (0xA0 + port)
117+
# Read the packet sequence number (two bytes)
118+
res = sock.get_once(2, 1)
119+
when 0xF0
120+
# Skip this keep-alive response
121+
when (0x80 + port)
122+
# Read the one-byte length value
123+
res = sock.get_once(1, 1)
124+
if res
125+
len = res.unpack("C").first
126+
res = sock.get_once(len, 1)
127+
if res
128+
banner << res
129+
end
130+
end
131+
end
132+
end
133+
banner
134+
end
135+
136+
def realport_send(port=0, data)
137+
sock.put( [port].pack("C") + data )
138+
end
139+
140+
def realport_close(port=0)
141+
cprt = [ 0xb0 + port ].pack("C")
142+
pkt = cprt + "\x28\x00\xc0\x00\xb0\x00\x01\x00\x00\x00\x00" + cprt + "\x0a\x03"
143+
144+
# Response
145+
# b2 0b 03 00 00 02
146+
147+
# Send a close request
148+
sock.put(pkt)
149+
res = sock.get_once(-1, 5)
150+
151+
vprint_status("#{target_host}:#{rport} Port:#{port} Close:#{ res.inspect }")
152+
return
153+
end
154+
155+
def realport_open(port=0, baud='9600')
156+
157+
@realport_banner = ''
158+
159+
cprt = [ 0xb0 + port ].pack("C")
160+
aprt = [ 0xa0 + port ].pack("C")
161+
162+
speed = realport_baud_to_speed(baud)
163+
164+
# Open port
165+
pkt1 = "\xf0" + cprt + "\x0a"+ "\x00"
166+
167+
# Response
168+
# b2 0b 00 00 00 02
169+
# ^ ^ <- port number
170+
171+
# Open the port
172+
sock.put(pkt1)
173+
res = sock.get_once(-1, 5)
174+
175+
vprint_status("#{target_host}:#{rport} Port:#{port} Baud:#{baud} Open:#{ res.inspect }")
176+
177+
# Access the port
178+
pkt2 =
179+
cprt + "\x0e" +
180+
cprt + "\x2a\x02\xc0\xf3" +
181+
cprt + "\x10" +
182+
cprt + "\x14" +
183+
cprt + "\x16" +
184+
cprt + "\x2c\x03\x00\x00"
185+
186+
# Response (GOOD)
187+
# b2 0f 00 00 00 00 b2 15 0f ff 0f ff b2 11 00 00
188+
# 13 b2 17 01 02 00 2f 06 a8 00 1c 20 00 00 00 00
189+
# 00 f3 f3 00 00 00 00 00 00 00 00 00 00 00 00 00
190+
# 00
191+
192+
# Response (BAD)
193+
# \xFF \x17 Access to unopened port\x00
194+
195+
# Send negotiate request
196+
sock.put(pkt2)
197+
res = sock.get_once(-1, 5)
198+
if res.to_s =~ /^\xff/
199+
vprint_status("#{target_host}:#{rport} Port:#{port} is closed: #{res.inspect}")
200+
return :closed
201+
end
202+
203+
vprint_status("#{target_host}:#{rport} Port:#{port} Baud:#{baud} Negotiate:#{ res.inspect }")
204+
205+
# Terminal settings
206+
pkt3 =
207+
cprt + "\x30\x03\xff\x00\x64" +
208+
cprt + "\x2d\x03\xff\x0b\xff" +
209+
cprt + "\x28" + speed + "\x04" +
210+
cprt + "\x00\x01\x00\x00\x00\x00" +
211+
cprt + "\x2c\x00\x12\x00" +
212+
cprt + "\x2e\x11\x13\x16\x00\x00" +
213+
cprt + "\x2f\x03\xff\x00\x64" +
214+
cprt + "\x40\x37" + aprt + "\x0f\xff"
215+
216+
# Response
217+
# c2 12 00 00 f0
218+
# ^
219+
220+
# Send terminal settings request
221+
sock.put(pkt3)
222+
res = sock.get_once(-1, 5)
223+
224+
if res.to_s =~ /^\xff/
225+
vprint_status("#{target_host}:#{rport} Port:#{port} is closed: #{res.inspect}")
226+
return :closed
227+
end
228+
229+
vprint_status("#{target_host}:#{rport} Port:#{port} Baud:#{baud} Settings:#{ res.inspect }")
230+
return :open
231+
end
232+
233+
end
234+
235+
236+
end
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
##
2+
# $Id$
3+
##
4+
5+
##
6+
# This file is part of the Metasploit Framework and may be subject to
7+
# redistribution and commercial restrictions. Please see the Metasploit
8+
# web site for more information on licensing and terms of use.
9+
# http://metasploit.com/
10+
##
11+
12+
require 'msf/core'
13+
14+
class Metasploit3 < Msf::Auxiliary
15+
16+
include Msf::Exploit::Remote::RealPort
17+
include Msf::Auxiliary::Report
18+
include Msf::Auxiliary::Scanner
19+
20+
def initialize
21+
super(
22+
'Name' => 'Digi RealPort Serial Server Port Scanner',
23+
'Description' => 'Identify active ports on RealPort-enabled serial servers.',
24+
'References' =>
25+
[
26+
['URL', 'http://www.digi.com/pdf/fs_realport.pdf'],
27+
['URL', 'http://www.digi.com/support/productdetail?pid=2229&type=drivers']
28+
],
29+
'Author' =>
30+
[
31+
'hdm'
32+
],
33+
'License' => MSF_LICENSE
34+
)
35+
36+
register_options(
37+
[
38+
OptInt.new("BANNER_TIMEOUT", [true, "How long to capture data from the serial port", 5]),
39+
OptString.new('BAUD_RATES', [true, "A space delimited list of baud rates to try for each port", "9600 115200"]),
40+
OptString.new('PORTS', [true, "A space delimited list of 1-indexed serial port numbers to try, default is all supported", "ALL"])
41+
], self.class)
42+
end
43+
44+
def setup
45+
test_speeds = datastore['BAUD_RATES'].split(/\s+/)
46+
test_speeds.each do |baud|
47+
valid = realport_baud_to_speed(baud)
48+
if not valid
49+
raise RuntimeError, "The baud rate #{baud} is not supported"
50+
end
51+
end
52+
end
53+
54+
def run_host(target_host)
55+
test_ports = datastore['PORTS'].upcase.split(/\s+/)
56+
test_speeds = datastore['BAUD_RATES'].split(/\s+/)
57+
58+
return unless realport_connect
59+
60+
info = "#{@realport_name} ( ports: #{@realport_port_count} )"
61+
vprint_status("#{target_host}:#{rport} is running #{info}")
62+
report_service(:host => rhost, :port => rport, :name => "realport", :info => info)
63+
64+
1.upto(@realport_port_count) do |pnum|
65+
unless test_ports.include?('ALL') or test_ports.include?(pnum.to_s)
66+
# Skip this port
67+
next
68+
end
69+
70+
test_speeds.each do |baud|
71+
ret = realport_open(pnum - 1, baud)
72+
break unless ret == :open
73+
res = realport_recv_banner(pnum - 1, datastore['BANNER_TIMEOUT'])
74+
if res and res.length > 0
75+
print_status("#{target_host}:#{rport} [port #{pnum} @ #{baud}bps] #{res.inspect}")
76+
report_note(
77+
:host => target_host,
78+
:proto => 'tcp',
79+
:port => rport,
80+
:type => "realport.port#{pnum}.banner",
81+
:data => {:baud => baud, :banner => res},
82+
:update => :unique_data
83+
)
84+
85+
end
86+
realport_close(pnum - 1)
87+
end
88+
end
89+
90+
realport_disconnect
91+
end
92+
93+
end
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
##
2+
# $Id$
3+
##
4+
5+
##
6+
# This file is part of the Metasploit Framework and may be subject to
7+
# redistribution and commercial restrictions. Please see the Metasploit
8+
# web site for more information on licensing and terms of use.
9+
# http://metasploit.com/
10+
##
11+
12+
require 'msf/core'
13+
14+
class Metasploit3 < Msf::Auxiliary
15+
16+
include Msf::Exploit::Remote::RealPort
17+
include Msf::Auxiliary::Report
18+
include Msf::Auxiliary::Scanner
19+
20+
def initialize
21+
super(
22+
'Name' => 'Digi RealPort Serial Server Version',
23+
'Description' => 'Detect serial servers that speak the RealPort protocol.',
24+
'References' =>
25+
[
26+
['URL', 'http://www.digi.com/pdf/fs_realport.pdf'],
27+
['URL', 'http://www.digi.com/support/productdetail?pid=2229&type=drivers']
28+
],
29+
'Author' =>
30+
[
31+
'hdm'
32+
],
33+
'License' => MSF_LICENSE
34+
)
35+
end
36+
37+
def run_host(target_host)
38+
if realport_connect
39+
info = "#{@realport_name} ( ports: #{@realport_port_count} )"
40+
print_status("#{target_host}:#{rport} #{info}")
41+
report_service(:host => rhost, :port => rport, :name => "realport", :info => info)
42+
end
43+
realport_disconnect
44+
end
45+
end

0 commit comments

Comments
 (0)