Path: blob/master/modules/auxiliary/scanner/oracle/isqlplus_sidbrute.rb
19500 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::AuthBrute9include Msf::Auxiliary::Report1011def initialize12super(13'Name' => 'Oracle iSQLPlus SID Check',14'Description' => %q{15This module attempts to bruteforce the SID on the Oracle application server iSQL*Plus16login pages. It does this by testing Oracle error responses returned in the HTTP response.17Incorrect username/pass with a correct SID will produce an Oracle ORA-01017 error.18Works against Oracle 9.2, 10.1 & 10.2 iSQL*Plus. This module will attempt to19fingerprint the version and automatically select the correct POST request.20},21'References' => [22[ 'URL', 'https://blog.carnal0wnage.com/' ],23],24'Author' => [ 'CG', 'todb' ],25'License' => MSF_LICENSE26)2728register_options([29Opt::RPORT(5560),30OptString.new('URI', [ true, 'Oracle iSQLPlus path', '/isqlplus/']),31OptString.new('SID', [ false, 'A single SID to test']),32OptPath.new('SIDFILE', [ false, 'A file containing a list of SIDs', File.join(Msf::Config.install_root, 'data', 'wordlists', 'sid.txt')]),33OptInt.new('TIMEOUT', [false, 'Time to wait for HTTP responses', 30])34])3536deregister_options(37"RHOST", "USERNAME", "PASSWORD", "USER_FILE", "PASS_FILE", "USERPASS_FILE",38"BLANK_PASSWORDS", "USER_AS_PASS", "REMOVE_USER_FILE", "REMOVE_PASS_FILE",39"BRUTEFORCE_SPEED" # Slow as heck anyway40)41end4243def sid_file44datastore['SIDFILE']45end4647def hostport48[target_host, rport].join(":")49end5051def uri52datastore['URI'] || "/isqlplus/"53end5455def timeout56(datastore['TIMEOUT'] || 30).to_i57end5859def msg60msg = "#{hostport} - Oracle iSQL*Plus -"61end6263def run_host(ip)64oracle_ver = get_oracle_version(ip)65if not check_oracle_version(oracle_ver)66print_error "#{msg} Unknown Oracle version, skipping."67return68end69begin70print_status("#{msg} Starting SID check")71sid_data.each do |sid|72guess = check_oracle_sid(ip, oracle_ver, sid)73return if guess and datastore['STOP_ON_SUCCESS']74end75rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout => e76print_error "#{msg} Cannot connect"77rescue ::Timeout::Error, ::Errno::EPIPE, Errno::ECONNRESET => e78print_error e.message79end80end8182def get_oracle_version(ip)83begin84res = send_request_cgi({85'version' => '1.1',86'uri' => uri,87'method' => 'GET',88}, timeout)89oracle_ver = nil90if (res.nil?)91print_error("#{msg} no response")92elsif (res.code == 200)93print_status("#{msg} Received an HTTP #{res.code}")94oracle_ver = detect_oracle_version(res)95elsif (res.code == 404)96print_error("#{msg} Received an HTTP 404, check URIPATH")97elsif (res.code == 302)98print_error("#{msg} Received an HTTP 302 to #{res.headers['Location']}")99else100print_error("#{msg} Received an HTTP #{res.code}")101end102return oracle_ver103rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout => e104print_error "#{msg} Cannot connect"105end106end107108def detect_oracle_version(res)109m = res.body.match(/iSQL\*Plus Release (9\.0|9\.1|9\.2|10\.1|10\.2)/)110oracle_ver = nil111oracle_ver = 10 if m[1] && m[1] =~ /10/112oracle_ver = m[1].to_f if m[1] && m[1] =~ /9\.[012]/113if oracle_ver114print_status("#{msg} Detected Oracle version #{oracle_ver}")115print_status("#{msg} SID detection for iSQL*Plus 10.1 may be unreliable") if oracle_ver == 10.1116else117print_error("#{msg} Unknown Oracle version detected.")118end119return oracle_ver120end121122def check_oracle_version(ver)123[9.0, 9.1, 9.2, 10].include? ver124end125126def build_post_request(ver, sid)127post_request = nil128case ver129when 9.0130post_request = "action=logon&sqlcmd=&sqlparms=&username=scott&password=tiger&sid=#{sid.strip}&privilege=&Log+In=%B5%C7%C2%BC"131when 9.1132post_request = "action=logon&username=a&password=a&sid=#{sid.strip}&login=Login"133when 9.2134post_request = "action=logon&username=a&password=a&sid=#{sid.strip}&login=Login"135when 10136post_request = "username=a&password=a&connectID=#{sid.strip}&report=&script=&dynamic=&type=&action=&variables=&event=login"137end138return post_request139end140141def parse_isqlplus_response(res, sid)142guess = false143if (res.nil?)144print_error("#{msg} No response")145elsif (res.code == 200)146if (res.body =~ /ORA-01017:/ or res.body =~ /ORA-28273:/)147if sid.nil? || sid.empty?148print_good("#{msg} Received ORA-01017 on a blank SID -- SIDs are not enforced upon login.")149else150print_good("#{msg} Received ORA-01017, probable correct SID '#{sid.strip}'")151end152guess = true153elsif (res.body =~ /(ORA-12170):/ or res.body =~ /(ORA-12154):/ or res.body =~ /(ORA-12162):/)154vprint_status("#{msg} Incorrect SID: '#{sid.strip}' (got error code #{$1})")155elsif res.body =~ /(ORA-12541):/156print_status("#{msg} Possible correct SID, but got ORA-12541: No Listener error.")157guess = true158else159print_status("#{msg} Received an unknown error") # Should say what the error was160end161elsif (res.code == 404)162print_status("#{msg} Received an HTTP 404, check URIPATH")163elsif (res.code == 302)164print_status("#{msg} Received an HTTP 302 redirect to #{res.headers['Location']}")165else166print_status("#{msg} Received an unexpected response: #{res.code}")167end168169report_isqlplus_service(target_host, res) if res170return guess171end172173def report_isqlplus_service(ip, res)174sname = datastore['SSL'] ? 'https' : 'http'175report_service(176:host => ip,177:proto => 'tcp',178:port => rport,179:name => sname,180:info => res.headers["Server"].to_s.strip181)182end183184def report_oracle_sid(ip, sid)185report_note(186:host => ip,187:proto => 'tcp',188:port => rport,189:type => "oracle.sid",190:data => ((sid.nil? || sid.empty?) ? "*BLANK*" : sid),191:update => :unique_data192)193end194195def sid_data196if datastore['SID'] and not datastore['SID'].empty?197[datastore['SID']]198elsif sid_file and ::File.readable? sid_file199::File.open(sid_file, "rb") { |f| f.read f.stat.size }.each_line.map { |x| x.strip.upcase }.uniq200else201raise ArugmentError, "Cannot read file '#{sid_file}'"202end203end204205def check_oracle_sid(ip, oracle_ver, sid)206post_request = build_post_request(oracle_ver, sid)207vprint_status "#{msg} Trying SID '#{sid}', waiting for response..."208res = send_request_cgi({209'version' => '1.1',210'uri' => uri,211'method' => 'POST',212'data' => post_request,213'headers' =>214{215'Referer' => "http://#{ip}:#{rport}#{uri}"216}217}, timeout)218guess = parse_isqlplus_response(res, sid)219report_oracle_sid(ip, sid) if guess220return guess221end222end223224225