133 lines
3.8 KiB
Ruby
133 lines
3.8 KiB
Ruby
|
##
|
||
|
# $Id$
|
||
|
##
|
||
|
|
||
|
##
|
||
|
# This file is part of the Metasploit Framework and may be subject to
|
||
|
# redistribution and commercial restrictions. Please see the Metasploit
|
||
|
# Framework web site for more information on licensing and terms of use.
|
||
|
# http://metasploit.com/framework/
|
||
|
##
|
||
|
|
||
|
require 'msf/core'
|
||
|
|
||
|
class Metasploit3 < Msf::Auxiliary
|
||
|
|
||
|
include Msf::Exploit::Remote::TNS
|
||
|
include Msf::Auxiliary::Report
|
||
|
include Msf::Auxiliary::Scanner
|
||
|
include Msf::Auxiliary::AuthBrute # Actually, doesn't use much here, but there's a couple handy functions.
|
||
|
|
||
|
def initialize(info = {})
|
||
|
super(update_info(info,
|
||
|
'Name' => 'Oracle TNS Listener SID Bruteforce',
|
||
|
'Description' => %q{
|
||
|
This module queries the TNS listner for a valid Oracle database
|
||
|
instance name (also known as a SID).
|
||
|
Any response other than a "reject" will be considered a success.
|
||
|
If a specific SID is provided, that SID will be attempted. Otherwise,
|
||
|
SIDs read from the named file will be attempted in sequence instead.
|
||
|
},
|
||
|
'Author' => [ 'todb' ],
|
||
|
'License' => MSF_LICENSE,
|
||
|
'Version' => '$$'
|
||
|
))
|
||
|
|
||
|
register_options(
|
||
|
[
|
||
|
OptPath.new('SID_FILE', [ false, "File containing instance names, one per line", File.join(Msf::Config.install_root, "data", "wordlists", "sid.txt") ]),
|
||
|
OptString.new('SID', [ false, 'A specific SID to attempt.' ]),
|
||
|
Opt::RPORT(1521)
|
||
|
], self.class)
|
||
|
|
||
|
deregister_options("RHOST", "USERNAME", "PASSWORD", "USER_FILE", "PASS_FILE", "USERPASS_FILE",
|
||
|
"BLANK_PASSWORDS", "USER_AS_PASS", "REMOVE_USER_FILE", "REMOVE_PASS_FILE",
|
||
|
"REMOVE_USERPASS_FILE")
|
||
|
end
|
||
|
|
||
|
def build_sid_request(sid,ip)
|
||
|
connect_data = "(DESCRIPTION=(CONNECT_DATA=(SID=#{sid})(CID=(PROGRAM=)(HOST=__jdbc__)(USER=)))(ADDRESS=(PROTOCOL=tcp)(HOST=#{ip})(PORT=#{rport})))"
|
||
|
pkt = tns_packet(connect_data)
|
||
|
end
|
||
|
|
||
|
def check_sid(sid,ip)
|
||
|
pkt = build_sid_request(sid,ip)
|
||
|
sock.put(pkt)
|
||
|
data = sock.get_once
|
||
|
parse_response(data)
|
||
|
end
|
||
|
|
||
|
def target_host
|
||
|
"#{rhost}:#{rport}"
|
||
|
end
|
||
|
|
||
|
def parse_response(data)
|
||
|
return unless data
|
||
|
len,sum,type,r,hsum,rest = data.unpack("nnCCnA*")
|
||
|
type # 2 is "accept", 11 is resend. Usually you get 11, then 2. 4 is refuse.
|
||
|
end
|
||
|
|
||
|
def do_sid_check(sid,ip)
|
||
|
begin
|
||
|
connect
|
||
|
response_code = check_sid(sid,ip)
|
||
|
if response_code.nil?
|
||
|
print_status "#{target_host} - Oracle - No response given, something is wrong."
|
||
|
return :abort
|
||
|
elsif response_code != 4
|
||
|
print_good "#{target_host} - Oracle - '#{sid}' is valid"
|
||
|
report_note(
|
||
|
:host => ip,
|
||
|
:proto => 'tcp',
|
||
|
:port => rport,
|
||
|
:sname => 'oracle',
|
||
|
:type => "oracle.sid",
|
||
|
:data => sid,
|
||
|
:update => :unique_data
|
||
|
)
|
||
|
return :success
|
||
|
else
|
||
|
vprint_status "#{target_host} - Oracle - Refused '#{sid}'"
|
||
|
return :fail
|
||
|
end
|
||
|
disconnect
|
||
|
rescue ::Rex::ConnectionError, ::Errno::EPIPE
|
||
|
print_error("#{target_host} - Oracle - unable to connect to a TNS listener")
|
||
|
return :abort
|
||
|
end
|
||
|
end
|
||
|
|
||
|
# Based vaugely on each_user_pass in AuthBrute
|
||
|
def each_sid(&block)
|
||
|
@@oracle_sid_fail = []
|
||
|
@@oracle_sid_success = []
|
||
|
if datastore['SID'].nil? || datastore['SID'].empty?
|
||
|
sids = extract_words(datastore['SID_FILE']).map {|s| s.to_s.strip.upcase}.uniq
|
||
|
else
|
||
|
sids = [datastore['SID'].to_s.strip.upcase]
|
||
|
end
|
||
|
print_status "Checking #{sids.size} SID#{sids.size != 1 && "s"} against #{target_host}"
|
||
|
sids.each do |s|
|
||
|
userpass_sleep_interval unless (@@oracle_sid_fail | @@oracle_sid_success).empty?
|
||
|
next if @@oracle_sid_fail.include?(s) || @@oracle_sid_success.include?(s)
|
||
|
ret = block.call(s)
|
||
|
case ret
|
||
|
when :abort
|
||
|
break
|
||
|
when :success
|
||
|
@@oracle_sid_success << s
|
||
|
break if datastore["STOP_ON_SUCCESS"]
|
||
|
when :fail
|
||
|
@@oracle_sid_fail << s
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def run_host(ip)
|
||
|
each_sid do |sid|
|
||
|
vprint_status "#{target_host} - Oracle - Checking '#{sid}'..."
|
||
|
do_sid_check(sid,ip)
|
||
|
end
|
||
|
end
|
||
|
end
|