## # 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::Exploit::ORACLE def initialize(info = {}) super(update_info(info, 'Name' => 'Oracle Database Enumeration', 'Description' => %q{ This module provides a simple way to scan an Oracle database server for configuration parameters that may be useful during a penetration test. Valid database credentials must be provided for this module to run. }, 'Author' => [ 'Carlos Perez ' ], 'License' => MSF_LICENSE )) end def run return if not check_dependencies begin # Get all values from v$parameter query = 'select name,value from v$parameter' vparm = {} params = prepare_exec(query) params.each do |l| name,value = l.split(",") vparm["#{name}"] = value end rescue => e if e.to_s =~ /ORA-00942: table or view does not exist/ print_error("It appears you do not have sufficient rights to perform the check") else raise e end end print_status("Running Oracle Enumeration....") # Version Check query = 'select * from v$version' ver = prepare_exec(query) print_status("The versions of the Components are:") ver.each do |v| print_status("\t#{v.chomp}") report_note( :host => datastore['RHOST'], :proto => 'tcp', :sname => 'oracle', :port => datastore['RPORT'], :type => 'ORA_ENUM', :data => "Component Version: #{v.chomp}", :update => :unique_data ) end # Saving Major Release Number for other checks majorrel = ver[0].scan(/Edition Release (\d*)./) #------------------------------------------------------- # Audit Check print_status("Auditing:") begin if vparm["audit_trail"] == "NONE" print_status("\tDatabase Auditing is not enabled!") report_note( :host => datastore['RHOST'], :proto => 'tcp', :sname => 'oracle', :port => datastore['RPORT'], :type => 'ORA_ENUM', :data => "Audit Trail: Disabled", :update => :unique_data ) else print_status("\tDatabase Auditing is enabled!") report_note( :host => datastore['RHOST'], :proto => 'tcp', :sname => 'oracle', :port => datastore['RPORT'], :type => 'ORA_ENUM', :data => "Audit Trail: Enabled", :update => :unique_data ) end if vparm["audit_sys_operations"] == "FALSE" print_status("\tAuditing of SYS Operations is not enabled!") report_note( :host => datastore['RHOST'], :proto => 'tcp', :sname => 'oracle', :port => datastore['RPORT'], :type => 'ORA_ENUM', :data => "Audit SYS Ops: Disabled", :update => :unique_data ) else print_status("\tAuditing of SYS Operations is enabled!") report_note( :host => datastore['RHOST'], :proto => 'tcp', :sname => 'oracle', :port => datastore['RPORT'], :type => 'ORA_ENUM', :data => "Audit SYS Ops: Enabled", :update => :unique_data ) end end #------------------------------------------------------- # Security Settings print_status("Security Settings:") begin if vparm["sql92_security"] == "FALSE" print_status("\tSQL92 Security restriction on SELECT is not Enabled") report_note( :host => datastore['RHOST'], :proto => 'tcp', :sname => 'oracle', :port => datastore['RPORT'], :type => 'ORA_ENUM', :data => "SQL92: Disabled", :update => :unique_data ) else print_status("\tSQL92 Security restriction on SELECT is Enabled") report_note( :host => datastore['RHOST'], :proto => 'tcp', :sname => 'oracle', :port => datastore['RPORT'], :type => 'ORA_ENUM', :data => "SQL92: Enabled", :update => :unique_data ) end # check for encryption of logins on version before 10g if majorrel.join.to_i < 10 if vparm["dblink_encrypt_login"] == "FALSE" print_status("\tLink Encryption for Logins is not Enabled") report_note( :host => datastore['RHOST'], :proto => 'tcp', :sname => 'oracle', :port => datastore['RPORT'], :type => 'ORA_ENUM', :data => "Link Encryption: Disabled", :update => :unique_data ) else print_status("\tLink Encryption for Logins is Enabled") report_note( :host => datastore['RHOST'], :proto => 'tcp', :sname => 'oracle', :port => datastore['RPORT'], :type => 'ORA_ENUM', :data => "Link Encryption: Enabled", :update => :unique_data ) end end print_status("\tUTL Directory Access is set to #{vparm["utl_file_dir"]}") if vparm["utl_file_dir"] != " " report_note( :host => datastore['RHOST'], :proto => 'tcp', :sname => 'oracle', :port => datastore['RPORT'], :type => 'ORA_ENUM', :data => "UTL_DIR: #{ vparm["utl_file_dir"]}" ) if not vparm["utl_file_dir"]#.empty? print_status("\tAudit log is saved at #{vparm["audit_file_dest"]}") report_note( :host => datastore['RHOST'], :proto => 'tcp', :sname => 'oracle', :port => datastore['RPORT'], :type => 'ORA_ENUM', :data => "Audit Log Location: #{ vparm["audit_file_dest"]}" ) if not vparm["audit_file_dest"]#.empty? end #------------------------------------------------------- # Password Policy print_status("Password Policy:") begin query = %Q| SELECT limit FROM dba_profiles WHERE resource_name = 'PASSWORD_LOCK_TIME' AND profile = 'DEFAULT' | lockout = prepare_exec(query) print_status("\tCurrent Account Lockout Time is set to #{lockout[0].chomp}") report_note( :host => datastore['RHOST'], :proto => 'tcp', :sname => 'oracle', :port => datastore['RPORT'], :type => 'ORA_ENUM', :data => "Account Lockout Time: #{lockout[0].chomp}", :update => :unique_data ) rescue => e if e.to_s =~ /ORA-00942: table or view does not exist/ print_error("It appears you do not have sufficient rights to perform the check") else raise e end end begin query = %Q| SELECT limit FROM dba_profiles WHERE resource_name = 'FAILED_LOGIN_ATTEMPTS' AND profile = 'DEFAULT' | failed_logins = prepare_exec(query) print_status("\tThe Number of Failed Logins before an account is locked is set to #{failed_logins[0].chomp}") report_note( :host => datastore['RHOST'], :proto => 'tcp', :sname => 'oracle', :port => datastore['RPORT'], :type => 'ORA_ENUM', :data => "Account Fail Logins Permitted: #{failed_logins[0].chomp}", :update => :unique_data ) rescue => e if e.to_s =~ /ORA-00942: table or view does not exist/ print_error("It appears you do not have sufficient rights to perform the check") else raise e end end begin query = %Q| SELECT limit FROM dba_profiles WHERE resource_name = 'PASSWORD_GRACE_TIME' AND profile = 'DEFAULT' | grace_time = prepare_exec(query) print_status("\tThe Password Grace Time is set to #{grace_time[0].chomp}") report_note( :host => datastore['RHOST'], :proto => 'tcp', :sname => 'oracle', :port => datastore['RPORT'], :type => 'ORA_ENUM', :data => "Account Password Grace Time: #{grace_time[0].chomp}", :update => :unique_data ) rescue => e if e.to_s =~ /ORA-00942: table or view does not exist/ print_error("It appears you do not have sufficient rights to perform the check") else raise e end end begin query = %Q| SELECT limit FROM dba_profiles WHERE resource_name = 'PASSWORD_LIFE_TIME' AND profile = 'DEFAULT' | passlife_time = prepare_exec(query) print_status("\tThe Lifetime of Passwords is set to #{passlife_time[0].chomp}") report_note( :host => datastore['RHOST'], :proto => 'tcp', :sname => 'oracle', :port => datastore['RPORT'], :type => 'ORA_ENUM', :data => "Password Life Time: #{passlife_time[0].chomp}", :update => :unique_data ) rescue => e if e.to_s =~ /ORA-00942: table or view does not exist/ print_error("It appears you do not have sufficient rights to perform the check") else raise e end end begin query = %Q| SELECT limit FROM dba_profiles WHERE resource_name = 'PASSWORD_REUSE_TIME' AND profile = 'DEFAULT' | passreuse = prepare_exec(query) print_status("\tThe Number of Times a Password can be reused is set to #{passreuse[0].chomp}") report_note( :host => datastore['RHOST'], :proto => 'tcp', :sname => 'oracle', :port => datastore['RPORT'], :type => 'ORA_ENUM', :data => "Password Reuse Time: #{passreuse[0].chomp}", :update => :unique_data ) rescue => e if e.to_s =~ /ORA-00942: table or view does not exist/ print_error("It appears you do not have sufficient rights to perform the check") else raise e end end begin query = %Q| SELECT limit FROM dba_profiles WHERE resource_name = 'PASSWORD_REUSE_MAX' AND profile = 'DEFAULT' | passreusemax = prepare_exec(query) print_status("\tThe Maximum Number of Times a Password needs to be changed before it can be reused is set to #{passreusemax[0].chomp}") report_note( :host => datastore['RHOST'], :proto => 'tcp', :sname => 'oracle', :port => datastore['RPORT'], :type => 'ORA_ENUM', :data => "Password Maximun Reuse Time: #{passreusemax[0].chomp}", :update => :unique_data ) print_status("\tThe Number of Times a Password can be reused is set to #{passreuse[0].chomp}") rescue => e if e.to_s =~ /ORA-00942: table or view does not exist/ print_error("It appears you do not have sufficient rights to perform the check") else raise e end end begin query = %Q| SELECT limit FROM dba_profiles WHERE resource_name = 'PASSWORD_VERIFY_FUNCTION' AND profile = 'DEFAULT' | passrand = prepare_exec(query) if passrand[0] =~ /NULL/ print_status("\tPassword Complexity is not checked") report_note( :host => datastore['RHOST'], :proto => 'tcp', :sname => 'oracle', :port => datastore['RPORT'], :type => 'ORA_ENUM', :data => "Password Complexity is not being checked for new passwords", :update => :unique_data ) else print_status("\tPassword Complexity is being checked") report_note( :host => datastore['RHOST'], :proto => 'tcp', :sname => 'oracle', :port => datastore['RPORT'], :type => 'ORA_ENUM', :data => "Password Complexity is being checked for new passwords", :update => :unique_data ) end rescue => e if e.to_s =~ /ORA-00942: table or view does not exist/ print_error("It appears you do not have sufficient rights to perform the check") else raise e end end #------------------------------------------------------- begin if majorrel.join.to_i < 11 query = %Q| SELECT name, password FROM sys.user$ where password != 'null' and type# = 1 and astatus = 0 | activeacc = prepare_exec(query) print_status("Active Accounts on the System in format Username,Hash are:") activeacc.each do |aa| print_status("\t#{aa.chomp}") report_note( :host => datastore['RHOST'], :proto => 'tcp', :sname => 'oracle', :port => datastore['RPORT'], :type => 'ORA_ENUM', :data => "Active Account #{aa.chomp}", :update => :unique_data ) end else query = %Q| SELECT name, password, spare4 FROM sys.user$ where password != 'null' and type# = 1 and astatus = 0 | activeacc = prepare_exec(query) print_status("Active Accounts on the System in format Username,Password,Spare4 are:") activeacc.each do |aa| print_status("\t#{aa.chomp}") report_note( :host => datastore['RHOST'], :proto => 'tcp', :sname => 'oracle', :port => datastore['RPORT'], :type => 'ORA_ENUM', :data => "Active Account #{aa.chomp}", :update => :unique_data ) end end rescue => e if e.to_s =~ /ORA-00942: table or view does not exist/ print_error("It appears you do not have sufficient rights to perform the check") else raise e end end begin if majorrel.join.to_i < 11 query = %Q| SELECT username, password FROM dba_users WHERE account_status = 'EXPIRED & LOCKED' | disabledacc = prepare_exec(query) print_status("Expired or Locked Accounts on the System in format Username,Hash are:") disabledacc.each do |da| print_status("\t#{da.chomp}") report_note( :host => datastore['RHOST'], :proto => 'tcp', :sname => 'oracle', :port => datastore['RPORT'], :type => 'ORA_ENUM', :data => "Disabled Account #{da.chomp}", :update => :unique_data ) end else query = %Q| SELECT name, password, spare4 FROM sys.user$ where password != 'null' and type# = 1 and astatus = 8 or astatus = 9 | disabledacc = prepare_exec(query) print_status("Expired or Locked Accounts on the System in format Username,Password,Spare4 are:") disabledacc.each do |da| print_status("\t#{da.chomp}") report_note( :host => datastore['RHOST'], :proto => 'tcp', :sname => 'oracle', :port => datastore['RPORT'], :type => 'ORA_ENUM', :data => "Disabled Account #{da.chomp}", :update => :unique_data ) end end rescue => e if e.to_s =~ /ORA-00942: table or view does not exist/ print_error("It appears you do not have sufficient rights to perform the check") else raise e end end begin query = %Q| SELECT grantee FROM dba_role_privs WHERE granted_role = 'DBA' | dbaacc = prepare_exec(query) print_status("Accounts with DBA Privilege in format Username,Hash on the System are:") dbaacc.each do |dba| print_status("\t#{dba.chomp}") report_note( :host => datastore['RHOST'], :proto => 'tcp', :sname => 'oracle', :port => datastore['RPORT'], :type => 'ORA_ENUM', :data => "Account with DBA Priv #{dba.chomp}", :update => :unique_data ) end rescue => e if e.to_s =~ /ORA-00942: table or view does not exist/ print_error("It appears you do not have sufficient rights to perform the check") else raise e end end begin query = %Q| SELECT grantee FROM dba_sys_privs WHERE privilege = 'ALTER SYSTEM' | altersys = prepare_exec(query) print_status("Accounts with Alter System Privilege on the System are:") altersys.each do |as| print_status("\t#{as.chomp}") report_note( :host => datastore['RHOST'], :proto => 'tcp', :sname => 'oracle', :port => datastore['RPORT'], :type => 'ORA_ENUM', :data => "Account with ALTER SYSTEM Priv #{as.chomp}", :update => :unique_data) end rescue => e if e.to_s =~ /ORA-00942: table or view does not exist/ print_error("It appears you do not have sufficient rights to perform the check") else raise e end end begin query = %Q| SELECT grantee FROM dba_sys_privs WHERE privilege = 'JAVA ADMIN' | javaacc = prepare_exec(query) print_status("Accounts with JAVA ADMIN Privilege on the System are:") javaacc.each do |j| print_status("\t#{j.chomp}") report_note( :host => datastore['RHOST'], :proto => 'tcp', :sname => 'oracle', :port => datastore['RPORT'], :type => 'ORA_ENUM', :data => "Account with JAVA ADMIN Priv #{j.chomp}", :update => :unique_data ) end rescue => e if e.to_s =~ /ORA-00942: table or view does not exist/ print_error("It appears you do not have sufficient rights to perform the check") else raise e end end begin query = %Q| select grantee from dba_sys_privs where privilege = 'CREATE LIBRARY' or privilege = 'CREATE ANY' | libpriv = prepare_exec(query) print_status("Accounts that have CREATE LIBRARY Privilege on the System are:") libpriv.each do |lp| print_status("\t#{lp.chomp}") report_note( :host => datastore['RHOST'], :proto => 'tcp', :sname => 'oracle', :port => datastore['RPORT'], :type => 'ORA_ENUM', :data => "Account with CREATE LIBRARY Priv #{lp.chomp}", :update => :unique_data ) end rescue => e if e.to_s =~ /ORA-00942: table or view does not exist/ print_error("It appears you do not have sufficient rights to perform the check") else raise e end end #Default Password Check begin print_status("Default password check:") if majorrel.join.to_i == 11 query = %Q| SELECT * FROM dba_users_with_defpwd | defpwd = prepare_exec(query) defpwd.each do |dp| print_status("\tThe account #{dp.chomp} has a default password.") report_note( :host => datastore['RHOST'], :proto => 'tcp', :sname => 'oracle', :port => datastore['RPORT'], :type => 'ORA_ENUM', :data => "Account with Default Password #{dp.chomp}", :update => :unique_data ) end else query = %Q| SELECT name, password FROM sys.user$ where password != 'null' and type# = 1 | ordfltpss = "#{File.join(Msf::Config.data_directory, "wordlists", "oracle_default_hashes.txt")}" returnedstring = prepare_exec(query) accts = {} returnedstring.each do |record| user,pass = record.split(",") accts["#{pass.chomp}"] = user end ::File.open(ordfltpss, "rb").each_line do |l| accrcrd = l.split(",") if accts.has_key?(accrcrd[2]) print_status("\tDefault pass for account #{accrcrd[0]} is #{accrcrd[1]} ") report_note( :host => datastore['RHOST'], :proto => 'tcp', :sname => 'oracle', :port => datastore['RPORT'], :type => 'ORA_ENUM', :data => "Account with Default Password #{accrcrd[0]} is #{accrcrd[1]}", :update => :unique_data ) end end end rescue => e if e.to_s =~ /ORA-00942: table or view does not exist/ print_error("It appears you do not have sufficient rights to perform the check") else raise e end end end end