metasploit-framework/modules/auxiliary/scanner/sap/sap_router_portscanner.rb

368 lines
10 KiB
Ruby
Raw Normal View History

2013-06-13 15:08:44 +00:00
##
# 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/
##
2013-05-29 22:36:53 +00:00
require 'msf/core'
class Metasploit3 < Msf::Auxiliary
include Msf::Exploit::Remote::Tcp
include Msf::Auxiliary::Report
include Msf::Auxiliary::Scanner
def initialize
super(
2013-06-25 22:08:58 +00:00
'Name' => 'SAPRouter Port Scanner',
'Description' => %q{
2013-06-13 15:08:44 +00:00
This module allows for mapping ACLs and identify open/closed ports accessible
on hosts through a saprouter.
},
2013-06-25 22:08:58 +00:00
'Author' => [
'Bruno Morisson <bm[at]integrity.pt>', # metasploit module
'nmonkee' # saprouter packet building code from sapcat.rb and default sap ports information
],
'References' =>
[
# General
['URL', 'http://help.sap.com/saphelp_nw70/helpdata/EN/4f/992dfe446d11d189700000e8322d00/frameset.htm'],
['URL', 'http://help.sap.com/saphelp_dimp50/helpdata/En/f8/bb960899d743378ccb8372215bb767/content.htm'],
['URL', 'http://labs.mwrinfosecurity.com/blog/2012/09/13/sap-smashing-internet-windows/'],
['URL', 'http://conference.hitb.org/hitbsecconf2010ams/materials/D2T2%20-%20Mariano%20Nunez%20Di%20Croce%20-%20SAProuter%20.pdf'],
['URL', 'http://scn.sap.com/docs/DOC-17124'] # SAP default ports
],
2013-06-25 22:08:58 +00:00
'License' => MSF_LICENSE
2013-05-29 22:36:53 +00:00
)
register_options(
2013-06-25 22:08:58 +00:00
[
OptAddress.new('SAPROUTER_HOST', [true, 'SAPRouter address', '']),
OptPort.new('SAPROUTER_PORT', [true, 'SAPRouter TCP port', '3299']),
OptEnum.new('MODE', [true, 'Connection Mode: SAP_PROTO or TCP ', 'SAP_PROTO', ['SAP_PROTO', 'TCP']]),
OptString.new('INSTANCES', [false, 'SAP instance numbers to scan (NN in PORTS definition)', '00-99']),
OptString.new('PORTS', [true, 'Ports to scan (e.g. 3200-3299,5NN13)', '32NN']),
# Default ports: 32NN,33NN,48NN,80NN,36NN,81NN,5NN00-5NN19,21212,21213,
# 59975,59976,4238-4241,3299,3298,515,7200,7210,7269,7270,7575,39NN,
# 3909,4NN00,8200,8210,8220,8230,4363,4444,4445,9999,3NN01-3NN08,
# 3NN11,3NN17,20003-20007,31596,31597,31602,31601,31604,2000-2002,
# 8355,8357,8351-8353,8366,1090,1095,20201,1099,1089,443NN,444NN
OptInt.new('CONCURRENCY', [true, 'The number of concurrent ports to check per host', 10]),
], self.class)
2013-05-29 22:36:53 +00:00
deregister_options('RPORT')
end
2013-07-03 17:41:12 +00:00
# Converts a instance specification like "4,21-23,33" into a sorted,
# unique array of valid port numbers like [4,21,22,23,33]
def sap_instance_to_list(instance)
instances = []
return if !instance
# Build ports array from port specification
instance.split(/,/).each do |item|
start, stop = item.split(/-/).map { |p| p.to_i }
start ||= 0
stop ||= item.match(/-/) ? 99 : start
start, stop = stop, start if stop < start
start.upto(stop) { |p| instances << p }
end
# Sort, and remove dups and invalid instances
instances.sort.uniq.delete_if { |p| p < 0 or p > 99 }
end
2013-06-23 16:55:38 +00:00
def build_sap_ports(ports)
sap_ports = []
sap_instances = sap_instance_to_list(datastore['INSTANCES'])
# if we have INSTANCES, let's fill in the NN on PORTS
if sap_instances and ports.include? 'NN'
sap_instances.each { |i| sap_ports << (ports.gsub('NN', "%02d" % i)).to_s }
ports = Rex::Socket.portspec_crack(sap_ports.join(','))
else
ports = Rex::Socket.portspec_crack(ports)
end
2013-07-03 17:41:12 +00:00
return ports
end
2013-05-29 22:36:53 +00:00
def build_ni_packet(routes)
mode = {'SAP_PROTO' => 0, 'TCP' => 1}[datastore['MODE']]
2013-05-29 22:36:53 +00:00
route_data=''
2013-06-13 15:08:44 +00:00
ni_packet = [
2013-06-25 22:08:58 +00:00
'NI_ROUTE',
0,
2,
39,
2,
mode,
0,
0,
1
2013-06-13 15:08:44 +00:00
].pack("A8c8")
2013-05-29 22:36:53 +00:00
first = false
routes.each do |host, port| # create routes
2013-06-13 15:08:44 +00:00
route_item = [host, 0, port.to_s, 0, 0].pack("A*CA*cc")
2013-05-29 22:36:53 +00:00
if !first
2013-06-13 15:08:44 +00:00
route_data = [route_data, route_item.length, route_item].pack("A*NA*")
2013-05-29 22:36:53 +00:00
first = true
else
route_data = route_data << route_item
end
end
ni_packet << [route_data.length - 4].pack('N') << route_data # add routes to packet
ni_packet = [ni_packet.length].pack('N') << ni_packet # add size
end
def sap_port_info(port)
case port.to_s
when /^3299$/
service = "SAP Router"
when /^3298$/
service = "SAP niping (Network Test Program)"
when /^32[0-9][0-9]/
service = "SAP Dispatcher sapdp" + port.to_s[-2, 2]
when /^33[0-9][0-9]/
service = "SAP Gateway sapgw" + port.to_s[-2, 2]
when /^48[0-9][0-9]/
service = "SAP Gateway [SNC] sapgw" + port.to_s[-2, 2]
when /^80[0-9][0-9]/
service = "SAP ICM HTTP"
when /^443[0-9][0-9]/
service = "SAP ICM HTTPS"
when /^36[0-9][0-9]/
service = "SAP Message Server sapms<SID>" + port.to_s[-2, 2]
when /^81[0-9][0-9]/
service = "SAP Message Server [HTTP]"
when /^444[0-9][0-9]/
service = "SAP Message Server [HTTPS]"
when /^5[0-9][0-9]00/
service = "SAP JAVA EE Dispatcher [HTTP]"
when /^5[0-9][0-9]01/
service = "SAP JAVA EE Dispatcher [HTTPS]"
when /^5[0-9][0-9]02/
service = "SAP JAVA EE Dispatcher [IIOP]"
when /^5[0-9][0-9]03/
service = "SAP JAVA EE Dispatcher [IIOP over SSL]"
when /^5[0-9][0-9]04/
service = "SAP JAVA EE Dispatcher [P4]"
when /^5[0-9][0-9]05/
service = "SAP JAVA EE Dispatcher [P4 over HTTP]"
when /^5[0-9][0-9]06/
service = "SAP JAVA EE Dispatcher [P4 over SSL]"
when /^5[0-9][0-9]07/
service = "SAP JAVA EE Dispatcher [IIOP]"
when /^5[0-9][0-9]08$/
service = "SAP JAVA EE Dispatcher [Telnet]"
when /^5[0-9][0-9]10/
service = "SAP JAVA EE Dispatcher [JMS]"
when /^5[0-9][0-9]16/
service = "SAP JAVA Enq. Replication"
when /^5[0-9][0-9]13/
service = "SAP StartService [SOAP] sapctrl" + port.to_s[1, 2]
when /^5[0-9][0-9]14/
service = "SAP StartService [SOAP over SSL] sapctrl" + port.to_s[1, 2]
when /^5[0-9][0-9]1(7|8|9)/
service = "SAP Software Deployment Manager"
when /^2121(2|3)/
service = "SAPinst"
when /^5997(5|6)/
service = "SAPinst (IBM AS/400 iSeries)"
when /^42(3|4)(8|9|0|1$)/
service = "SAP Upgrade"
when /^515$/
service = "SAPlpd"
when /^7(2|5)(00|10|69|70|75$)/
service = "LiveCache MaxDB (formerly SAP DB)"
when /^5[0-9][0-9]15/
service = "DTR - Design Time Repository"
when /^3909$/
service = "ITS MM (Mapping Manager) sapvwmm00_<INST>"
when /^39[0-9][0-9]$/
service = "ITS AGate sapavw00_<INST>"
when /^4[0-9][0-9]00/
service = "IGS Multiplexer"
when /^8200$/
service = "XI JMS/JDBC/File Adapter"
when /^8210$/
service = "XI JMS Adapter"
when /^8220$/
service = "XI JDBC Adapter"
when /^8230$/
service = "XI File Adapter"
when /^4363$/
service = "IPC Dispatcher"
when /^4444$/
service = "IPC Dispatcher"
when /^4445$/
service = "IPC Data Loader"
when /^9999$/
service = "IPC Server"
when /^3[0-9][0-9](0|1)(1|2|3|4|5|6|7|8$)/
service = "SAP Software Deployment Manager"
when /^2000(3|4|5|6|7$)/
service = "MDM (Master Data Management)"
when /^3159(6|7$)/
service = "MDM (Master Data Management)"
when /^3160(2|3|4$)/
service = "MDM (Master Data Management)"
when /^200(0|1|2$)/
service = "MDM Server (Master Data Management)"
when /^83(5|6)(1|2|3|5|6|7$)/
service = "MDM Server (Master Data Management)"
when /^109(0|5$)/
service = "Content Server / Cache Server"
when /^20201$/
service = "CRM - Central Software Deployment Manager"
when /^10(8|9)9$/
service = "PAW - Performance Assessment Workbench"
else
service = ''
end
end
2013-05-29 22:36:53 +00:00
def parse_response_packet(response, ip, port)
2013-06-23 16:55:38 +00:00
#vprint_error("#{ip}:#{port} - response packet: #{response}")
2013-05-29 22:36:53 +00:00
case response
2013-05-31 23:31:06 +00:00
when /NI_RTERR/
case response
when /timed out/
2013-06-13 15:08:44 +00:00
vprint_error ("#{ip}:#{port} - connection timed out")
2013-05-31 23:31:06 +00:00
when /refused/
2013-06-13 15:08:44 +00:00
vprint_error("#{ip}:#{port} - TCP closed")
return [ip, port, "closed", sap_port_info(port)]
2013-05-31 23:31:06 +00:00
when /denied/
2013-06-13 15:08:44 +00:00
vprint_error("#{ip}:#{port} - blocked by ACL")
2013-05-31 23:31:06 +00:00
when /invalid/
2013-06-13 15:08:44 +00:00
vprint_error("#{ip}:#{port} - invalid route")
2013-05-31 23:31:06 +00:00
when /reacheable/
2013-06-13 15:08:44 +00:00
vprint_error("#{ip}:#{port} - unreachable")
2013-05-29 22:36:53 +00:00
else
2013-06-13 15:08:44 +00:00
vprint_error("#{ip}:#{port} - unknown error message")
2013-05-31 23:31:06 +00:00
end
when /NI_PONG/
2013-06-25 22:08:58 +00:00
vprint_good("#{ip}:#{port} - TCP OPEN")
return [ip, port, "open", sap_port_info(port)]
2013-05-31 23:31:06 +00:00
else
2013-06-13 15:08:44 +00:00
vprint_error("#{ip}:#{port} - unknown response")
2013-05-29 22:36:53 +00:00
end
2013-06-13 15:08:44 +00:00
return nil
2013-05-29 22:36:53 +00:00
end
def run_host(ip)
sap_host = datastore['SAPROUTER_HOST']
sap_port = datastore['SAPROUTER_PORT']
2013-06-23 16:55:38 +00:00
ports = datastore['PORTS']
# if port definition has NN then we require INSTANCES
2013-06-23 16:55:38 +00:00
if ports.include? 'NN' and datastore['INSTANCES'].nil?
print_error('Error: No instances specified')
return
end
2013-06-23 16:55:38 +00:00
ports = build_sap_ports(ports)
2013-05-29 22:36:53 +00:00
if ports.empty?
print_error('Error: No valid ports specified')
return
end
print_status("Scanning #{ip}")
2013-05-31 23:31:06 +00:00
thread = []
2013-06-13 15:08:44 +00:00
r = []
2013-05-29 22:36:53 +00:00
2013-06-13 15:08:44 +00:00
begin
ports.each do |port|
2013-05-29 22:36:53 +00:00
if thread.length >= datastore['CONCURRENCY']
# Assume the first thread will be among the earliest to finish
thread.first.join
end
thread << framework.threads.spawn("Module(#{self.refname})-#{ip}:#{port}", false) do
begin
# create ni_packet to send to saprouter
routes = {sap_host => sap_port, ip => port}
ni_packet = build_ni_packet(routes)
s = connect(false,
2013-07-03 17:42:37 +00:00
{
'RPORT' => sap_port,
'RHOST' => sap_host
}
)
s.write(ni_packet, ni_packet.length)
response = s.get()
res = parse_response_packet(response, ip, port)
if res
r << res
end
rescue ::Rex::ConnectionRefused
print_error("#{ip}:#{port} - Unable to connect to SAPRouter #{sap_host}:#{sap_port} - Connection Refused")
rescue ::Rex::ConnectionError, ::IOError, ::Timeout::Error
rescue ::Rex::Post::Meterpreter::RequestError
rescue ::Interrupt
raise $!
ensure
disconnect(s) rescue nil
2013-06-13 15:08:44 +00:00
end
2013-05-31 23:31:06 +00:00
end
2013-05-29 22:36:53 +00:00
end
thread.each { |x| x.join }
2013-05-31 23:31:06 +00:00
2013-06-13 15:08:44 +00:00
rescue ::Timeout::Error
ensure
thread.each { |x| x.kill rescue nil }
end
tbl = Msf::Ui::Console::Table.new(
2013-06-25 22:08:58 +00:00
Msf::Ui::Console::Table::Style::Default,
'Header' => "Portscan Results",
'Prefix' => "\n",
'Postfix' => "\n",
'Indent' => 1,
'Columns' =>
[
"Host",
"Port",
"State",
"Info",
])
2013-06-13 15:08:44 +00:00
r.each do |res|
tbl << [res[0], res[1], res[2], res[3]]
2013-07-03 17:41:12 +00:00
report_service(:host => res[0], :port => res[1], :state => res[2])
2013-06-13 15:08:44 +00:00
end
2013-07-03 17:41:12 +00:00
print_warning("Warning: Service info could be innacurated")
print(tbl.to_s)
2013-05-29 22:36:53 +00:00
end
end