Skip to content

Commit fed6427

Browse files
author
jvazquez-r7
committed
Land rapid7#1884, @morrisson's saprouter port scanner module
2 parents cfa5b70 + 852fc33 commit fed6427

File tree

1 file changed

+186
-0
lines changed

1 file changed

+186
-0
lines changed
Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
##
2+
# This file is part of the Metasploit Framework and may be subject to
3+
# redistribution and commercial restrictions. Please see the Metasploit
4+
# web site for more information on licensing and terms of use.
5+
# http://metasploit.com/
6+
##
7+
8+
require 'msf/core'
9+
10+
class Metasploit3 < Msf::Auxiliary
11+
12+
include Msf::Exploit::Remote::Tcp
13+
include Msf::Auxiliary::Report
14+
include Msf::Auxiliary::Scanner
15+
16+
def initialize
17+
super(
18+
'Name' => 'SAPRouter Port Scanner',
19+
'Description' => %q{
20+
This module allows for mapping ACLs and identify open/closed ports accessible
21+
on hosts through a saprouter.
22+
},
23+
'Author' => [
24+
'Bruno Morisson <bm[at]integrity.pt>', # metasploit module
25+
'nmonkee' # saprouter packet building code from sapcat.rb
26+
],
27+
'References' =>
28+
[
29+
# General
30+
['URL', 'http://help.sap.com/saphelp_nw70/helpdata/EN/4f/992dfe446d11d189700000e8322d00/frameset.htm'],
31+
['URL', 'http://help.sap.com/saphelp_dimp50/helpdata/En/f8/bb960899d743378ccb8372215bb767/content.htm'],
32+
['URL', 'http://labs.mwrinfosecurity.com/blog/2012/09/13/sap-smashing-internet-windows/'],
33+
['URL', 'http://conference.hitb.org/hitbsecconf2010ams/materials/D2T2%20-%20Mariano%20Nunez%20Di%20Croce%20-%20SAProuter%20.pdf'],
34+
['URL', 'http://scn.sap.com/docs/DOC-17124'] # SAP default ports
35+
],
36+
'License' => MSF_LICENSE
37+
)
38+
39+
register_options(
40+
[
41+
OptAddress.new('SAPROUTER_HOST', [true, 'SAPRouter address', '']),
42+
OptPort.new('SAPROUTER_PORT', [true, 'SAPRouter TCP port', '3299']),
43+
OptEnum.new('MODE', [true, 'Connection Mode: SAP_PROTO or TCP ', 'SAP_PROTO', ['SAP_PROTO', 'TCP']]),
44+
OptString.new('PORTS', [true, 'Ports to scan (e.g. 22-25,80,110-900)', '3200-3299']),
45+
OptInt.new('CONCURRENCY', [true, 'The number of concurrent ports to check per host', 10]),
46+
], self.class)
47+
48+
deregister_options('RPORT')
49+
50+
end
51+
52+
def build_ni_packet(routes)
53+
54+
mode = {'SAP_PROTO'=>0,'TCP'=>1}[datastore['MODE']]
55+
56+
route_data=''
57+
ni_packet = [
58+
'NI_ROUTE',
59+
0,
60+
2,
61+
39,
62+
2,
63+
mode,
64+
0,
65+
0,
66+
1
67+
].pack("A8c8")
68+
69+
first = false
70+
71+
routes.each do |host, port| # create routes
72+
route_item = [host, 0, port.to_s, 0, 0].pack("A*CA*cc")
73+
if !first
74+
route_data = [route_data, route_item.length, route_item].pack("A*NA*")
75+
first = true
76+
else
77+
route_data = route_data << route_item
78+
end
79+
end
80+
81+
ni_packet << [route_data.length - 4].pack('N') << route_data # add routes to packet
82+
ni_packet = [ni_packet.length].pack('N') << ni_packet # add size
83+
end
84+
85+
def parse_response_packet(response, ip, port)
86+
87+
#vprint_error("#{ip}:#{port} - response packet: #{response}")
88+
89+
case response
90+
when /NI_RTERR/
91+
case response
92+
when /timed out/
93+
vprint_error ("#{ip}:#{port} - connection timed out")
94+
when /refused/
95+
vprint_error("#{ip}:#{port} - TCP closed")
96+
return [ip, port, "closed"]
97+
when /denied/
98+
vprint_error("#{ip}:#{port} - blocked by ACL")
99+
when /invalid/
100+
vprint_error("#{ip}:#{port} - invalid route")
101+
when /reacheable/
102+
vprint_error("#{ip}:#{port} - unreachable")
103+
else
104+
vprint_error("#{ip}:#{port} - unknown error message")
105+
end
106+
when /NI_PONG/
107+
print_good("#{ip}:#{port} - TCP OPEN")
108+
return [ip, port, "open"]
109+
else
110+
vprint_error("#{ip}:#{port} - unknown response")
111+
end
112+
113+
return nil
114+
end
115+
116+
def run_host(ip)
117+
118+
ports = Rex::Socket.portspec_crack(datastore['PORTS'])
119+
120+
sap_host = datastore['SAPROUTER_HOST']
121+
sap_port = datastore['SAPROUTER_PORT']
122+
123+
if ports.empty?
124+
print_error('Error: No valid ports specified')
125+
return
126+
end
127+
128+
print_status("Scanning #{ip}")
129+
thread = []
130+
r = []
131+
132+
begin
133+
ports.each do |port|
134+
135+
if thread.length >= datastore['CONCURRENCY']
136+
# Assume the first thread will be among the earliest to finish
137+
thread.first.join
138+
end
139+
thread << framework.threads.spawn("Module(#{self.refname})-#{ip}:#{port}", false) do
140+
141+
begin
142+
# create ni_packet to send to saprouter
143+
routes = {sap_host => sap_port, ip => port}
144+
ni_packet = build_ni_packet(routes)
145+
146+
s = connect(false,
147+
{
148+
'RPORT' => sap_port,
149+
'RHOST' => sap_host
150+
}
151+
)
152+
153+
s.write(ni_packet, ni_packet.length)
154+
response = s.get()
155+
156+
res = parse_response_packet(response, ip, port)
157+
if res
158+
r << res
159+
end
160+
161+
rescue ::Rex::ConnectionRefused
162+
print_error("#{ip}:#{port} - Unable to connect to SAPRouter #{sap_host}:#{sap_port} - Connection Refused")
163+
164+
rescue ::Rex::ConnectionError, ::IOError, ::Timeout::Error
165+
rescue ::Rex::Post::Meterpreter::RequestError
166+
rescue ::Interrupt
167+
raise $!
168+
ensure
169+
disconnect(s) rescue nil
170+
end
171+
end
172+
end
173+
thread.each { |x| x.join }
174+
175+
rescue ::Timeout::Error
176+
ensure
177+
thread.each { |x| x.kill rescue nil }
178+
end
179+
180+
r.each do |res|
181+
report_service(:host => res[0], :port => res[1], :state => res[2])
182+
end
183+
184+
end
185+
186+
end

0 commit comments

Comments
 (0)